| 
									
										
										
										
											2011-11-03 18:22:26 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright © 2010 Intel Corporation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a | 
					
						
							|  |  |  |  * copy of this software and associated documentation files (the "Software"), | 
					
						
							|  |  |  |  * to deal in the Software without restriction, including without limitation | 
					
						
							|  |  |  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
					
						
							|  |  |  |  * and/or sell copies of the Software, and to permit persons to whom the | 
					
						
							|  |  |  |  * Software is furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice (including the next | 
					
						
							|  |  |  |  * paragraph) shall be included in all copies or substantial portions of the | 
					
						
							|  |  |  |  * Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
					
						
							|  |  |  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | 
					
						
							|  |  |  |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
					
						
							|  |  |  |  * DEALINGS IN THE SOFTWARE. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Authors: | 
					
						
							|  |  |  |  *	Li Peng <peng.li@intel.com> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-16 12:13:30 +00:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2011-11-03 18:22:26 +00:00
										 |  |  | #include <linux/mutex.h>
 | 
					
						
							|  |  |  | #include <linux/pci.h>
 | 
					
						
							|  |  |  | #include <linux/i2c.h>
 | 
					
						
							|  |  |  | #include <linux/interrupt.h>
 | 
					
						
							|  |  |  | #include <linux/delay.h>
 | 
					
						
							|  |  |  | #include "psb_drv.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define HDMI_READ(reg)		readl(hdmi_dev->regs + (reg))
 | 
					
						
							|  |  |  | #define HDMI_WRITE(reg, val)	writel(val, hdmi_dev->regs + (reg))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define HDMI_HCR	0x1000
 | 
					
						
							|  |  |  | #define HCR_DETECT_HDP		(1 << 6)
 | 
					
						
							|  |  |  | #define HCR_ENABLE_HDCP		(1 << 5)
 | 
					
						
							|  |  |  | #define HCR_ENABLE_AUDIO	(1 << 2)
 | 
					
						
							|  |  |  | #define HCR_ENABLE_PIXEL	(1 << 1)
 | 
					
						
							|  |  |  | #define HCR_ENABLE_TMDS		(1 << 0)
 | 
					
						
							|  |  |  | #define HDMI_HICR	0x1004
 | 
					
						
							|  |  |  | #define HDMI_INTR_I2C_ERROR	(1 << 4)
 | 
					
						
							|  |  |  | #define HDMI_INTR_I2C_FULL	(1 << 3)
 | 
					
						
							|  |  |  | #define HDMI_INTR_I2C_DONE	(1 << 2)
 | 
					
						
							|  |  |  | #define HDMI_INTR_HPD		(1 << 0)
 | 
					
						
							|  |  |  | #define HDMI_HSR	0x1008
 | 
					
						
							|  |  |  | #define HDMI_HISR	0x100C
 | 
					
						
							|  |  |  | #define HDMI_HI2CRDB0	0x1200
 | 
					
						
							|  |  |  | #define HDMI_HI2CHCR	0x1240
 | 
					
						
							|  |  |  | #define HI2C_HDCP_WRITE		(0 << 2)
 | 
					
						
							|  |  |  | #define HI2C_HDCP_RI_READ	(1 << 2)
 | 
					
						
							|  |  |  | #define HI2C_HDCP_READ		(2 << 2)
 | 
					
						
							|  |  |  | #define HI2C_EDID_READ		(3 << 2)
 | 
					
						
							|  |  |  | #define HI2C_READ_CONTINUE	(1 << 1)
 | 
					
						
							|  |  |  | #define HI2C_ENABLE_TRANSACTION	(1 << 0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define HDMI_ICRH	0x1100
 | 
					
						
							|  |  |  | #define HDMI_HI2CTDR0	0x1244
 | 
					
						
							|  |  |  | #define HDMI_HI2CTDR1	0x1248
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define I2C_STAT_INIT		0
 | 
					
						
							|  |  |  | #define I2C_READ_DONE		1
 | 
					
						
							|  |  |  | #define I2C_TRANSACTION_DONE	2
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct hdmi_i2c_dev { | 
					
						
							|  |  |  | 	struct i2c_adapter *adap; | 
					
						
							|  |  |  | 	struct mutex i2c_lock; | 
					
						
							|  |  |  | 	struct completion complete; | 
					
						
							|  |  |  | 	int status; | 
					
						
							|  |  |  | 	struct i2c_msg *msg; | 
					
						
							|  |  |  | 	int buf_offset; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void hdmi_i2c_irq_enable(struct oaktrail_hdmi_dev *hdmi_dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 temp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	temp = HDMI_READ(HDMI_HICR); | 
					
						
							|  |  |  | 	temp |= (HDMI_INTR_I2C_ERROR | HDMI_INTR_I2C_FULL | HDMI_INTR_I2C_DONE); | 
					
						
							|  |  |  | 	HDMI_WRITE(HDMI_HICR, temp); | 
					
						
							|  |  |  | 	HDMI_READ(HDMI_HICR); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void hdmi_i2c_irq_disable(struct oaktrail_hdmi_dev *hdmi_dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	HDMI_WRITE(HDMI_HICR, 0x0); | 
					
						
							|  |  |  | 	HDMI_READ(HDMI_HICR); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap); | 
					
						
							|  |  |  | 	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | 
					
						
							|  |  |  | 	u32 temp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i2c_dev->status = I2C_STAT_INIT; | 
					
						
							|  |  |  | 	i2c_dev->msg = pmsg; | 
					
						
							|  |  |  | 	i2c_dev->buf_offset = 0; | 
					
						
							|  |  |  | 	INIT_COMPLETION(i2c_dev->complete); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable I2C transaction */ | 
					
						
							|  |  |  | 	temp = ((pmsg->len) << 20) | HI2C_EDID_READ | HI2C_ENABLE_TRANSACTION; | 
					
						
							|  |  |  | 	HDMI_WRITE(HDMI_HI2CHCR, temp); | 
					
						
							|  |  |  | 	HDMI_READ(HDMI_HI2CHCR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (i2c_dev->status != I2C_TRANSACTION_DONE) | 
					
						
							|  |  |  | 		wait_for_completion_interruptible_timeout(&i2c_dev->complete, | 
					
						
							|  |  |  | 								10 * HZ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int xfer_write(struct i2c_adapter *adap, struct i2c_msg *pmsg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * XXX: i2c write seems isn't useful for EDID probe, don't do anything | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap, | 
					
						
							|  |  |  | 				struct i2c_msg *pmsg, | 
					
						
							|  |  |  | 				int num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap); | 
					
						
							|  |  |  | 	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | 
					
						
							| 
									
										
										
										
											2012-03-08 16:13:23 +00:00
										 |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2011-11-03 18:22:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	mutex_lock(&i2c_dev->i2c_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable i2c unit */ | 
					
						
							|  |  |  | 	HDMI_WRITE(HDMI_ICRH, 0x00008760); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable irq */ | 
					
						
							|  |  |  | 	hdmi_i2c_irq_enable(hdmi_dev); | 
					
						
							|  |  |  | 	for (i = 0; i < num; i++) { | 
					
						
							|  |  |  | 		if (pmsg->len && pmsg->buf) { | 
					
						
							|  |  |  | 			if (pmsg->flags & I2C_M_RD) | 
					
						
							| 
									
										
										
										
											2012-03-08 16:13:23 +00:00
										 |  |  | 				xfer_read(adap, pmsg); | 
					
						
							| 
									
										
										
										
											2011-11-03 18:22:26 +00:00
										 |  |  | 			else | 
					
						
							| 
									
										
										
										
											2012-03-08 16:13:23 +00:00
										 |  |  | 				xfer_write(adap, pmsg); | 
					
						
							| 
									
										
										
										
											2011-11-03 18:22:26 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		pmsg++;         /* next message */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Disable irq */ | 
					
						
							|  |  |  | 	hdmi_i2c_irq_disable(hdmi_dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_unlock(&i2c_dev->i2c_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return i; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 oaktrail_hdmi_i2c_func(struct i2c_adapter *adapter) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct i2c_algorithm oaktrail_hdmi_i2c_algorithm = { | 
					
						
							|  |  |  | 	.master_xfer	= oaktrail_hdmi_i2c_access, | 
					
						
							|  |  |  | 	.functionality  = oaktrail_hdmi_i2c_func, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct i2c_adapter oaktrail_hdmi_i2c_adapter = { | 
					
						
							|  |  |  | 	.name		= "oaktrail_hdmi_i2c", | 
					
						
							|  |  |  | 	.nr		= 3, | 
					
						
							|  |  |  | 	.owner		= THIS_MODULE, | 
					
						
							|  |  |  | 	.class		= I2C_CLASS_DDC, | 
					
						
							|  |  |  | 	.algo		= &oaktrail_hdmi_i2c_algorithm, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void hdmi_i2c_read(struct oaktrail_hdmi_dev *hdmi_dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | 
					
						
							|  |  |  | 	struct i2c_msg *msg = i2c_dev->msg; | 
					
						
							|  |  |  | 	u8 *buf = msg->buf; | 
					
						
							|  |  |  | 	u32 temp; | 
					
						
							|  |  |  | 	int i, offset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	offset = i2c_dev->buf_offset; | 
					
						
							|  |  |  | 	for (i = 0; i < 0x10; i++) { | 
					
						
							|  |  |  | 		temp = HDMI_READ(HDMI_HI2CRDB0 + (i * 4)); | 
					
						
							|  |  |  | 		memcpy(buf + (offset + i * 4), &temp, 4); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	i2c_dev->buf_offset += (0x10 * 4); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* clearing read buffer full intr */ | 
					
						
							|  |  |  | 	temp = HDMI_READ(HDMI_HISR); | 
					
						
							|  |  |  | 	HDMI_WRITE(HDMI_HISR, temp | HDMI_INTR_I2C_FULL); | 
					
						
							|  |  |  | 	HDMI_READ(HDMI_HISR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* continue read transaction */ | 
					
						
							|  |  |  | 	temp = HDMI_READ(HDMI_HI2CHCR); | 
					
						
							|  |  |  | 	HDMI_WRITE(HDMI_HI2CHCR, temp | HI2C_READ_CONTINUE); | 
					
						
							|  |  |  | 	HDMI_READ(HDMI_HI2CHCR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i2c_dev->status = I2C_READ_DONE; | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void hdmi_i2c_transaction_done(struct oaktrail_hdmi_dev *hdmi_dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | 
					
						
							|  |  |  | 	u32 temp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* clear transaction done intr */ | 
					
						
							|  |  |  | 	temp = HDMI_READ(HDMI_HISR); | 
					
						
							|  |  |  | 	HDMI_WRITE(HDMI_HISR, temp | HDMI_INTR_I2C_DONE); | 
					
						
							|  |  |  | 	HDMI_READ(HDMI_HISR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	temp = HDMI_READ(HDMI_HI2CHCR); | 
					
						
							|  |  |  | 	HDMI_WRITE(HDMI_HI2CHCR, temp & ~HI2C_ENABLE_TRANSACTION); | 
					
						
							|  |  |  | 	HDMI_READ(HDMI_HI2CHCR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i2c_dev->status = I2C_TRANSACTION_DONE; | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static irqreturn_t oaktrail_hdmi_i2c_handler(int this_irq, void *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct oaktrail_hdmi_dev *hdmi_dev = dev; | 
					
						
							|  |  |  | 	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev; | 
					
						
							|  |  |  | 	u32 stat; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stat = HDMI_READ(HDMI_HISR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stat & HDMI_INTR_HPD) { | 
					
						
							|  |  |  | 		HDMI_WRITE(HDMI_HISR, stat | HDMI_INTR_HPD); | 
					
						
							|  |  |  | 		HDMI_READ(HDMI_HISR); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stat & HDMI_INTR_I2C_FULL) | 
					
						
							|  |  |  | 		hdmi_i2c_read(hdmi_dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stat & HDMI_INTR_I2C_DONE) | 
					
						
							|  |  |  | 		hdmi_i2c_transaction_done(hdmi_dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	complete(&i2c_dev->complete); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * choose alternate function 2 of GPIO pin 52, 53, | 
					
						
							|  |  |  |  * which is used by HDMI I2C logic | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void oaktrail_hdmi_i2c_gpio_fix(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-05-03 15:09:22 +01:00
										 |  |  | 	void __iomem *base; | 
					
						
							| 
									
										
										
										
											2011-11-03 18:22:26 +00:00
										 |  |  | 	unsigned int gpio_base = 0xff12c000; | 
					
						
							|  |  |  | 	int gpio_len = 0x1000; | 
					
						
							|  |  |  | 	u32 temp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	base = ioremap((resource_size_t)gpio_base, gpio_len); | 
					
						
							|  |  |  | 	if (base == NULL) { | 
					
						
							|  |  |  | 		DRM_ERROR("gpio ioremap fail\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	temp = readl(base + 0x44); | 
					
						
							|  |  |  | 	DRM_DEBUG_DRIVER("old gpio val %x\n", temp); | 
					
						
							|  |  |  | 	writel((temp | 0x00000a00), (base +  0x44)); | 
					
						
							|  |  |  | 	temp = readl(base + 0x44); | 
					
						
							|  |  |  | 	DRM_DEBUG_DRIVER("new gpio val %x\n", temp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iounmap(base); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int oaktrail_hdmi_i2c_init(struct pci_dev *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct oaktrail_hdmi_dev *hdmi_dev; | 
					
						
							|  |  |  | 	struct hdmi_i2c_dev *i2c_dev; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hdmi_dev = pci_get_drvdata(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i2c_dev = kzalloc(sizeof(struct hdmi_i2c_dev), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (i2c_dev == NULL) { | 
					
						
							|  |  |  | 		DRM_ERROR("Can't allocate interface\n"); | 
					
						
							|  |  |  | 		ret = -ENOMEM; | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i2c_dev->adap = &oaktrail_hdmi_i2c_adapter; | 
					
						
							|  |  |  | 	i2c_dev->status = I2C_STAT_INIT; | 
					
						
							|  |  |  | 	init_completion(&i2c_dev->complete); | 
					
						
							|  |  |  | 	mutex_init(&i2c_dev->i2c_lock); | 
					
						
							|  |  |  | 	i2c_set_adapdata(&oaktrail_hdmi_i2c_adapter, hdmi_dev); | 
					
						
							|  |  |  | 	hdmi_dev->i2c_dev = i2c_dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable HDMI I2C function on gpio */ | 
					
						
							|  |  |  | 	oaktrail_hdmi_i2c_gpio_fix(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* request irq */ | 
					
						
							|  |  |  | 	ret = request_irq(dev->irq, oaktrail_hdmi_i2c_handler, IRQF_SHARED, | 
					
						
							|  |  |  | 			  oaktrail_hdmi_i2c_adapter.name, hdmi_dev); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		DRM_ERROR("Failed to request IRQ for I2C controller\n"); | 
					
						
							|  |  |  | 		goto err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Adapter registration */ | 
					
						
							|  |  |  | 	ret = i2c_add_numbered_adapter(&oaktrail_hdmi_i2c_adapter); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  | 	kfree(i2c_dev); | 
					
						
							|  |  |  | exit: | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void oaktrail_hdmi_i2c_exit(struct pci_dev *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct oaktrail_hdmi_dev *hdmi_dev; | 
					
						
							|  |  |  | 	struct hdmi_i2c_dev *i2c_dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hdmi_dev = pci_get_drvdata(dev); | 
					
						
							|  |  |  | 	if (i2c_del_adapter(&oaktrail_hdmi_i2c_adapter)) | 
					
						
							|  |  |  | 		DRM_DEBUG_DRIVER("Failed to delete hdmi-i2c adapter\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i2c_dev = hdmi_dev->i2c_dev; | 
					
						
							|  |  |  | 	kfree(i2c_dev); | 
					
						
							|  |  |  | 	free_irq(dev->irq, hdmi_dev); | 
					
						
							|  |  |  | } |