diff --git a/README b/README
index a24ec89ba4420a..ceaca518ade76e 100644
--- a/README
+++ b/README
@@ -1,3 +1,26 @@
+Summary:
+ Get CEC (tv-remote control over HDMI) working on linux.
+ There are android-kernel sources, which have not made it
+ to the main linux kernel-tree, so also the hardkernel
+ linux-tree doesn't have CEC for exynos platforms.
+
+Status:
+ Copied s5p-cec code from all over the internet, mostly from
+ http://dn.odroid.com/Android_Alpha_4.0.3/BSP/
+ Made it compile as module (s5p-cec.ko)
+ Fixed the insmod()/rmmod() stuff. Error handling and resource
+ free-ing were quite broken.
+
+ Using a modified cec-client, it's possible to observe the
+ tv changing it's inputs, see:
+ https://github.com/vamanea/libcec.git
+
+TODO:
+ Cleanup this tree, so it becomes a nice diff upon hardkernel's 3.8 tree
+
+
+================================================================================
+
Linux kernel release 3.x
These are the release notes for Linux version 3. Read them carefully,
diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c
index 56b9c93617d255..7de33c3ee67f5b 100644
--- a/arch/arm/mach-exynos/clock-exynos4.c
+++ b/arch/arm/mach-exynos/clock-exynos4.c
@@ -716,6 +716,10 @@ static struct clk exynos4_init_clocks_off[] = {
.parent = &exynos4_clk_aclk_100.clk,
.enable = exynos4_clk_ip_perir_ctrl,
.ctrlbit = (1 << 14),
+ }, {
+ .name = "hdmicec",
+ .enable = exynos4_clk_ip_perir_ctrl,
+ .ctrlbit = (1 << 11),
}, {
.name = "usbhost",
.enable = exynos4_clk_ip_fsys_ctrl ,
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index 1f4dc35cd4b9b8..f5b0f19ae43ccf 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -132,6 +132,7 @@
#define EXYNOS4_IRQ_GPS IRQ_SPI(111)
#define EXYNOS4_IRQ_INTFEEDCTRL_SSS IRQ_SPI(112)
#define EXYNOS4_IRQ_SLIMBUS IRQ_SPI(113)
+#define EXYNOS4_IRQ_CEC IRQ_SPI(114)
#define EXYNOS4_IRQ_TSI IRQ_SPI(115)
#define EXYNOS4_IRQ_SATA IRQ_SPI(116)
@@ -235,6 +236,8 @@
#define IRQ_KEYPAD EXYNOS4_IRQ_KEYPAD
#define IRQ_PMU EXYNOS4_IRQ_PMU
+#define IRQ_CEC EXYNOS4_IRQ_CEC
+
#define IRQ_FIMD0_FIFO EXYNOS4_IRQ_FIMD0_FIFO
#define IRQ_FIMD0_VSYNC EXYNOS4_IRQ_FIMD0_VSYNC
#define IRQ_FIMD0_SYSTEM EXYNOS4_IRQ_FIMD0_SYSTEM
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index e178cf189d1f5b..49cacd2ef52ca8 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -79,6 +79,8 @@
#define EXYNOS4_PA_KEYPAD 0x100A0000
+#define EXYNOS4_PA_CEC 0x100B0000
+
#define EXYNOS4_PA_DMC0 0x10400000
#define EXYNOS4_PA_DMC1 0x10410000
@@ -276,6 +278,9 @@
#define SAMSUNG_PA_ADC1 EXYNOS4_PA_ADC1
#define SAMSUNG_PA_KEYPAD EXYNOS4_PA_KEYPAD
+#define S5P_PA_HDMI_CEC EXYNOS4_PA_CEC
+#define S5P_SZ_HDMI_CEC SZ_4K
+
/* Compatibility UART */
#define EXYNOS4_PA_UART0 0x13800000
diff --git a/arch/arm/mach-exynos/mach-hkdk4412.c b/arch/arm/mach-exynos/mach-hkdk4412.c
index 2e0cf0a52e6d93..8b8a9b66f5d360 100644
--- a/arch/arm/mach-exynos/mach-hkdk4412.c
+++ b/arch/arm/mach-exynos/mach-hkdk4412.c
@@ -393,6 +393,7 @@ static struct platform_device *hkdk4412_devices[] __initdata = {
&mali_gpu_device,
#if defined(CONFIG_S5P_DEV_TV)
&s5p_device_hdmi,
+ &s5p_device_cec,
&s5p_device_i2c_hdmiphy,
&s5p_device_mixer,
&hdmi_fixed_voltage,
@@ -417,6 +418,12 @@ static struct platform_device *hkdk4412_devices[] __initdata = {
#endif
};
+#if defined(CONFIG_S5P_DEV_TV)
+static struct s5p_platform_cec hdmi_cec_data __initdata = {
+
+};
+#endif
+
static void __init hkdk4412_map_io(void)
{
clk_xusbxti.rate = 24000000;
@@ -525,6 +532,7 @@ static void __init hkdk4412_machine_init(void)
s5p_tv_setup();
s5p_i2c_hdmiphy_set_platdata(NULL);
s5p_hdmi_set_platdata(&hdmiphy_info, NULL, 0);
+ s5p_hdmi_cec_set_platdata(&hdmi_cec_data);
#endif
s5p_fimd0_set_platdata(&hkdk4412_fb_pdata);
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 5e34b9c16196c4..d283b06db8d8ab 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -705,6 +705,7 @@ static struct platform_device *origen_devices[] __initdata = {
&s5p_device_fimd0,
&s5p_device_g2d,
&s5p_device_hdmi,
+ &s5p_device_cec,
&s5p_device_i2c_hdmiphy,
&s5p_device_jpeg,
&s5p_device_mfc,
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c
index ae6da40c2aa9e1..2a7f8afff9ee83 100644
--- a/arch/arm/mach-exynos/mach-smdk4x12.c
+++ b/arch/arm/mach-exynos/mach-smdk4x12.c
@@ -39,12 +39,19 @@
#include
#include
#include
+#include
#include
#include
#include "common.h"
+#if defined(CONFIG_ARCH_EXYNOS4)
+#define HDMI_GPX(_nr) EXYNOS4_GPX3(_nr)
+#elif defined(CONFIG_ARCH_EXYNOS5)
+#define HDMI_GPX(_nr) EXYNOS5_GPX3(_nr)
+#endif
+
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define SMDK4X12_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
S3C2410_UCON_RXILEVEL | \
@@ -246,6 +253,12 @@ static struct samsung_keypad_platdata smdk4x12_keypad_data __initdata = {
.cols = 8,
};
+#if defined(CONFIG_S5P_DEV_TV)
+static struct s5p_platform_cec hdmi_cec_data __initdata = {
+
+};
+#endif
+
#ifdef CONFIG_DRM_EXYNOS_FIMD
static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
.panel = {
@@ -332,6 +345,14 @@ static void __init smdk4x12_reserve(void)
s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20);
}
+#if defined(CONFIG_S5P_DEV_TV)
+void s5p_cec_cfg_gpio(struct platform_device *pdev)
+{
+ s3c_gpio_cfgpin(HDMI_GPX(6), S3C_GPIO_SFN(0x3));
+ s3c_gpio_setpull(HDMI_GPX(6), S3C_GPIO_PULL_NONE);
+}
+#endif
+
static void __init smdk4x12_machine_init(void)
{
s3c_i2c0_set_platdata(NULL);
@@ -359,6 +380,10 @@ static void __init smdk4x12_machine_init(void)
s3c_sdhci3_set_platdata(&smdk4x12_hsmmc3_pdata);
s3c_hsotg_set_platdata(&smdk4x12_hsotg_pdata);
+
+#if defined(CONFIG_S5P_DEV_TV)
+ s5p_hdmi_cec_set_platdata(&hdmi_cec_data);
+#endif
#ifdef CONFIG_DRM_EXYNOS_FIMD
s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 35548e3c097d8e..00174f821fbc09 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -315,6 +315,7 @@ static struct platform_device *smdkv310_devices[] __initdata = {
&smdkv310_smsc911x,
&exynos4_device_ahci,
&s5p_device_hdmi,
+ &s5p_device_cec,
&s5p_device_mixer,
};
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index b7c8a1917ffce5..824b73423672c6 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -48,6 +48,8 @@
#define S5PV210_PA_PCM1 0xE1200000
#define S5PV210_PA_PCM2 0xE2B00000
+#define S5PV210_PA_CEC 0xE1B00000
+
#define S5PV210_PA_TIMER 0xE2500000
#define S5PV210_PA_SYSTIMER 0xE2600000
#define S5PV210_PA_WATCHDOG 0xE2700000
@@ -126,6 +128,8 @@
#define S5P_PA_VP S5PV210_PA_VP
#define S5P_PA_MIXER S5PV210_PA_MIXER
#define S5P_PA_HDMI S5PV210_PA_HDMI
+#define S5P_PA_CEC S5PV210_PA_CEC
+#define S5P_SZ_CEC SZ_4K
#define S5P_PA_ONENAND S5PC110_PA_ONENAND
#define S5P_PA_ONENAND_DMA S5PC110_PA_ONENAND_DMA
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 82e30674093a8d..87d5224b8de46c 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -68,6 +68,8 @@
#include
#include
#include
+#include
+
static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
@@ -806,6 +808,7 @@ void __init s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info,
#endif /* CONFIG_S5P_DEV_I2C_HDMIPHY */
+
/* I2S */
#ifdef CONFIG_PLAT_S3C24XX
@@ -1357,6 +1360,18 @@ struct platform_device s5p_device_hdmi = {
.resource = s5p_hdmi_resources,
};
+static struct resource s5p_cec_resources[] = {
+ [0] = DEFINE_RES_MEM(S5P_PA_HDMI_CEC, S5P_SZ_HDMI_CEC),
+ [1] = DEFINE_RES_IRQ(IRQ_CEC),
+};
+
+struct platform_device s5p_device_cec = {
+ .name = "s5p-cec",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s5p_cec_resources),
+ .resource = s5p_cec_resources,
+};
+
static struct resource s5p_sdo_resources[] = {
[0] = DEFINE_RES_MEM(S5P_PA_SDO, SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_SDO),
@@ -1385,6 +1400,22 @@ struct platform_device s5p_device_mixer = {
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
+
+void __init s5p_hdmi_cec_set_platdata(struct s5p_platform_cec *pd)
+{
+ struct s5p_platform_cec *npd;
+ printk(KERN_INFO "s5p_hdmi_cec_set_platdata()\n");
+
+ npd = kmemdup(pd, sizeof(struct s5p_platform_cec), GFP_KERNEL);
+ if (!npd)
+ printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+ else {
+ if (!npd->cfg_gpio)
+ npd->cfg_gpio = s5p_cec_cfg_gpio;
+
+ s5p_device_cec.dev.platform_data = npd;
+ }
+}
#endif /* CONFIG_S5P_DEV_TV */
/* USB */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 92641bb13ef8d1..98b1a96b520bf2 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -87,6 +87,7 @@ extern struct platform_device mali_gpu_device;
extern struct platform_device s5p_device_fimd0;
extern struct platform_device s5p_device_hdmi;
+extern struct platform_device s5p_device_cec;
extern struct platform_device s5p_device_i2c_hdmiphy;
extern struct platform_device s5p_device_mfc;
extern struct platform_device s5p_device_mfc_l;
diff --git a/arch/arm/plat-samsung/include/plat/hdmi.h b/arch/arm/plat-samsung/include/plat/hdmi.h
index 331d046ac2c574..3dcca2f493c29c 100644
--- a/arch/arm/plat-samsung/include/plat/hdmi.h
+++ b/arch/arm/plat-samsung/include/plat/hdmi.h
@@ -10,7 +10,17 @@
#ifndef __PLAT_SAMSUNG_HDMI_H
#define __PLAT_SAMSUNG_HDMI_H __FILE__
+struct s5p_platform_cec {
+
+ void (*cfg_gpio)(struct platform_device *pdev);
+};
+
extern void s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info,
struct i2c_board_info *mhl_info, int mhl_bus);
+extern void s5p_hdmi_cec_set_platdata(struct s5p_platform_cec *pd);
+
+/* defined by architecture to configure gpio */
+extern void s5p_cec_cfg_gpio(struct platform_device *pdev);
+
#endif /* __PLAT_SAMSUNG_HDMI_H */
diff --git a/arch/arm/plat-samsung/include/plat/tv-core.h b/arch/arm/plat-samsung/include/plat/tv-core.h
index 3bc34f3ce28fb6..cc0b2265bfad09 100644
--- a/arch/arm/plat-samsung/include/plat/tv-core.h
+++ b/arch/arm/plat-samsung/include/plat/tv-core.h
@@ -27,6 +27,13 @@ static inline void s5p_hdmi_setname(char *name)
#endif
}
+static inline void s5p_cec_setname(char *name)
+{
+#ifdef CONFIG_S5P_DEV_TV
+ s5p_device_cec.name = name;
+#endif
+}
+
static inline void s5p_mixer_setname(char *name)
{
#ifdef CONFIG_S5P_DEV_TV
diff --git a/build.sh b/build.sh
new file mode 100755
index 00000000000000..f7cb298d1c65f1
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+export CROSS_COMPILE=arm-linux-gnueabihf-
+export ARCH=arm
+
+make M=drivers/media/platform/s5p-tv modules
+scp drivers/media/platform/s5p-tv/s5p-cec.ko root@x2_wifi:/root
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index db7bd292410bad..1d4f7c9fe66189 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -422,6 +422,7 @@ void drm_vm_open_locked(struct drm_device *dev,
list_add(&vma_entry->head, &dev->vmalist);
}
}
+EXPORT_SYMBOL_GPL(drm_vm_open_locked);
static void drm_vm_open(struct vm_area_struct *vma)
{
diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig
index 9f2fbebc7ed19c..a819eaf0d2ddac 100644
--- a/drivers/media/platform/s5p-tv/Kconfig
+++ b/drivers/media/platform/s5p-tv/Kconfig
@@ -36,6 +36,15 @@ config VIDEO_SAMSUNG_S5P_HDMI_DEBUG
help
Enables debugging for HDMI driver.
+config VIDEO_SAMSUNG_S5P_HDMI_CEC
+ tristate "Enable CEC support for HDMI Driver"
+ depends on VIDEO_SAMSUNG_S5P_HDMI
+ default n
+ help
+ Enables CEC over the HDMI driver.
+ CEC enables tv-control, and reception of tv-remote
+ control commands over the HDMI interface
+
config VIDEO_SAMSUNG_S5P_HDMIPHY
tristate "Samsung HDMIPHY Driver"
depends on VIDEO_DEV && VIDEO_V4L2 && I2C
diff --git a/drivers/media/platform/s5p-tv/Makefile b/drivers/media/platform/s5p-tv/Makefile
index da2f98fe24abf9..375806412df0a6 100644
--- a/drivers/media/platform/s5p-tv/Makefile
+++ b/drivers/media/platform/s5p-tv/Makefile
@@ -8,14 +8,19 @@
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
s5p-hdmiphy-y += hdmiphy_drv.o
+
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o
s5p-sii9234-y += sii9234_drv.o
+
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
s5p-hdmi-$(CONFIG_CPU_EXYNOS4210) += hdmi_drv.o
s5p-hdmi-$(CONFIG_SOC_EXYNOS4412) += hdmi_v14_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI_CEC) += s5p-cec.o
+s5p-cec-y += cec_drv.o cec_hw.o
+
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
s5p-sdo-y += sdo_drv.o
+
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
-
diff --git a/drivers/media/platform/s5p-tv/cec_drv.c b/drivers/media/platform/s5p-tv/cec_drv.c
new file mode 100644
index 00000000000000..1847c9ebbae505
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/cec_drv.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * CEC Support for Samsung S5P TVOUT
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include
+#include
+#include
+#include
+
+// Modified includes:
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "cec_hw.h"
+
+
+MODULE_AUTHOR("KyungHwan Kim ");
+MODULE_DESCRIPTION("Samsung S5P CEC driver");
+MODULE_LICENSE("GPL");
+
+#define CEC_IOC_MAGIC 'c'
+#define CEC_IOC_SETLADDR _IOW(CEC_IOC_MAGIC, 0, unsigned int)
+
+/* /dev/cec (Major 10, Minor 242) */
+#define CEC_MINOR 242
+
+#define CEC_STATUS_TX_DONE (1 << 2)
+#define CEC_STATUS_TX_ERROR (1 << 3)
+#define CEC_STATUS_RX_DONE (1 << 18)
+#define CEC_STATUS_RX_ERROR (1 << 19)
+
+#define CEC_TX_BUFF_SIZE 16
+
+static atomic_t hdmi_on = ATOMIC_INIT(0);
+static DEFINE_MUTEX(cec_lock);
+struct clk *hdmi_cec_clk;
+
+static int s5p_cec_open(struct inode *inode, struct file *file)
+{
+ int ret = 0;
+ printk(KERN_INFO "s5p_cec_open\n");
+
+ mutex_lock(&cec_lock);
+ clk_enable(hdmi_cec_clk);
+
+ if (atomic_read(&hdmi_on)) {
+ tvout_dbg("do not allow multiple open for tvout cec\n");
+ ret = -EBUSY;
+ goto err_multi_open;
+ } else
+ atomic_inc(&hdmi_on);
+
+ s5p_cec_reset();
+
+ s5p_cec_set_divider();
+
+ s5p_cec_threshold();
+
+ s5p_cec_unmask_tx_interrupts();
+
+ s5p_cec_set_rx_state(STATE_RX);
+ s5p_cec_unmask_rx_interrupts();
+ s5p_cec_enable_rx();
+
+err_multi_open:
+ mutex_unlock(&cec_lock);
+
+ return ret;
+}
+
+static int s5p_cec_release(struct inode *inode, struct file *file)
+{
+ printk(KERN_INFO "s5p_cec_release, hdmi_on=%i\n", atomic_read(&hdmi_on));
+
+ atomic_dec(&hdmi_on);
+
+ s5p_cec_mask_tx_interrupts();
+ s5p_cec_mask_rx_interrupts();
+
+ clk_disable(hdmi_cec_clk);
+
+ return 0;
+}
+
+static ssize_t s5p_cec_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+ unsigned long spin_flags;
+
+ printk(KERN_INFO "s5p_cec_read, %li bytes\n", (long)count);
+
+ if (wait_event_interruptible(cec_rx_struct.waitq,
+ atomic_read(&cec_rx_struct.state) == STATE_DONE)) {
+ return -ERESTARTSYS;
+ }
+ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags);
+
+ if (cec_rx_struct.size > count) {
+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+
+ return -1;
+ }
+
+ if (copy_to_user(buffer, cec_rx_struct.buffer, cec_rx_struct.size)) {
+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+ printk(KERN_ERR " copy_to_user() failed!\n");
+
+ return -EFAULT;
+ }
+
+ retval = cec_rx_struct.size;
+
+ s5p_cec_set_rx_state(STATE_RX);
+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+
+ return retval;
+}
+
+
+static ssize_t s5p_cec_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char *data;
+
+ printk(KERN_INFO "s5p_cec_write, %li bytes\n", (long)count);
+
+ /* check data size */
+
+ if (count > CEC_TX_BUFF_SIZE || count == 0)
+ return -1;
+
+ data = kmalloc(count, GFP_KERNEL);
+
+ if (!data) {
+ printk(KERN_ERR " kmalloc() failed!\n");
+ return -1;
+ }
+
+ if (copy_from_user(data, buffer, count)) {
+ printk(KERN_ERR " copy_from_user() failed!\n");
+ kfree(data);
+ return -EFAULT;
+ }
+
+ s5p_cec_copy_packet(data, count);
+
+ kfree(data);
+
+ /* wait for interrupt */
+ if (wait_event_interruptible(cec_tx_struct.waitq,
+ atomic_read(&cec_tx_struct.state)
+ != STATE_TX))
+ {
+ printk(KERN_INFO "\ttx no interrupt received\n");
+ return -ERESTARTSYS;
+ }
+
+ if (atomic_read(&cec_tx_struct.state) == STATE_ERROR)
+ {
+ printk(KERN_INFO "\ttx error\n");
+ return -1;
+ }
+
+ printk(KERN_INFO "\twritten count: %i\n", count);
+ return count;
+}
+
+static long s5p_cec_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ u32 laddr;
+
+ printk(KERN_INFO "s5p_cec_ioctl, cmd = 0x%x, arg = 0x%lx\n", cmd, arg);
+
+ switch (cmd) {
+ case CEC_IOC_SETLADDR:
+ if (get_user(laddr, (u32 __user *) arg))
+ return -EFAULT;
+
+ tvout_dbg("logical address = 0x%02x\n", laddr);
+
+ s5p_cec_set_addr(laddr);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static u32 s5p_cec_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &cec_rx_struct.waitq, wait);
+
+ if (atomic_read(&cec_rx_struct.state) == STATE_DONE)
+ {
+ printk(KERN_INFO "s5p_cec_poll: rx = done\n");
+ return POLLIN | POLLRDNORM;
+ }
+ return 0;
+}
+
+static const struct file_operations cec_fops = {
+ .owner = THIS_MODULE,
+ .open = s5p_cec_open,
+ .release = s5p_cec_release,
+ .read = s5p_cec_read,
+ .write = s5p_cec_write,
+ .unlocked_ioctl = s5p_cec_ioctl,
+ .poll = s5p_cec_poll,
+};
+
+static struct miscdevice cec_misc_device = {
+ .minor = CEC_MINOR,
+ .name = "CEC",
+ .fops = &cec_fops,
+};
+
+static irqreturn_t s5p_cec_irq_handler(int irq, void *dev_id)
+{
+ u32 status = s5p_cec_get_status();
+ printk(KERN_INFO "s5p_cec_irq_handler on irq %i\n", irq);
+
+ if (status & CEC_STATUS_TX_DONE) {
+ if (status & CEC_STATUS_TX_ERROR) {
+ tvout_dbg(" CEC_STATUS_TX_ERROR!\n");
+ s5p_cec_set_tx_state(STATE_ERROR);
+ } else {
+ tvout_dbg(" CEC_STATUS_TX_DONE!\n");
+ s5p_cec_set_tx_state(STATE_DONE);
+ }
+
+ s5p_clr_pending_tx();
+
+ wake_up_interruptible(&cec_tx_struct.waitq);
+ }
+
+ if (status & CEC_STATUS_RX_DONE) {
+ if (status & CEC_STATUS_RX_ERROR) {
+ tvout_dbg(" CEC_STATUS_RX_ERROR!\n");
+ s5p_cec_rx_reset();
+
+ } else {
+ u32 size;
+
+ tvout_dbg(" CEC_STATUS_RX_DONE!\n");
+
+ /* copy data from internal buffer */
+ size = status >> 24;
+
+ spin_lock(&cec_rx_struct.lock);
+
+ s5p_cec_get_rx_buf(size, cec_rx_struct.buffer);
+
+ cec_rx_struct.size = size;
+
+ s5p_cec_set_rx_state(STATE_DONE);
+
+ spin_unlock(&cec_rx_struct.lock);
+
+ s5p_cec_enable_rx();
+ }
+
+ /* clear interrupt pending bit */
+ s5p_clr_pending_rx();
+
+ wake_up_interruptible(&cec_rx_struct.waitq);
+ }
+ return IRQ_HANDLED;
+}
+
+static int s5p_cec_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct s5p_platform_cec *pdata;
+ u8 *buffer = NULL;
+ int irq_num;
+ int ret = 0;
+ struct resource *res;
+
+ dev_info(dev, "Probe start\n");
+
+ pdata = to_platform_device(&pdev->dev)->dev.platform_data;
+ dev_info(dev, "s5p_cec_probe: pdata=%p\n", pdata);
+ if (pdata && pdata->cfg_gpio)
+ pdata->cfg_gpio(pdev);
+
+ /* get ioremap addr */
+ ret = s5p_cec_mem_probe(pdev);
+ if (ret != 0) {
+ dev_err(dev, "Failed to s5p_cec_mem_probe(). ret = %d\n", ret);
+ goto err_mem_probe;
+ }
+
+ if (misc_register(&cec_misc_device)) {
+ dev_err(dev, "Couldn't register device 10, %d.\n", CEC_MINOR);
+ ret = -EBUSY;
+ goto err_misc_register;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Failed to get irq resource.\n");
+ ret = -ENODEV;
+ goto err_get_irq;
+ }
+ irq_num = res->start;
+
+ dev_info(dev, "Requesting irq %i for %s\n", irq_num, pdev->name);
+ ret = request_irq(irq_num, s5p_cec_irq_handler, IRQF_DISABLED, pdev->name, &pdev->id);
+ if (ret != 0) {
+ dev_err(dev, "Failed to install irq (%d), error %i\n", irq_num, ret);
+ goto err_request_irq;
+ }
+
+ init_waitqueue_head(&cec_rx_struct.waitq);
+ spin_lock_init(&cec_rx_struct.lock);
+ init_waitqueue_head(&cec_tx_struct.waitq);
+
+ buffer = kmalloc(CEC_TX_BUFF_SIZE, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(dev, "kmalloc() failed\n");
+ ret = -EIO;
+ goto err_kmalloc;
+ }
+
+ cec_rx_struct.buffer = buffer;
+ cec_rx_struct.size = 0;
+
+ hdmi_cec_clk = clk_get(&pdev->dev, "hdmicec");
+ if (IS_ERR(hdmi_cec_clk)) {
+ dev_err(dev, "failed to find clock 'hdmicec'\n");
+ ret = -ENOENT;
+ goto err_clock;
+ }
+
+ dev_info(&pdev->dev, "probe successful\n");
+ return ret; // All good
+
+ // Unwind the allocations on error
+err_clock:
+ kfree(cec_rx_struct.buffer);
+ cec_rx_struct.buffer = NULL;
+err_kmalloc:
+ free_irq(irq_num, &pdev->id);
+err_request_irq:
+err_get_irq:
+ misc_deregister(&cec_misc_device);
+err_misc_register:
+ s5p_cec_mem_release(pdev);
+err_mem_probe:
+ return ret;
+}
+
+static int s5p_cec_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ dev_info(dev, "s5p_cec_remove, putting clk to sleep\n");
+ clk_put(hdmi_cec_clk);
+
+ dev_info(dev, "s5p_cec_remove, cec_rx_struct.buffer=%p\n", cec_rx_struct.buffer);
+ if(cec_rx_struct.buffer)
+ {
+ kfree(cec_rx_struct.buffer);
+ cec_rx_struct.buffer = NULL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if(res)
+ {
+ int irq_num = res->start;
+ printk(KERN_INFO "s5p_cec_remove, irq=%i\n", irq_num);
+ free_irq(irq_num, &pdev->id);
+ }
+
+ misc_deregister(&cec_misc_device);
+
+ s5p_cec_mem_release(pdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+ static int s5p_cec_suspend(struct platform_device *dev, pm_message_t state)
+ {
+ printk(KERN_INFO "s5p_cec_suspend is a NOP\n");
+ return 0;
+ }
+
+ static int s5p_cec_resume(struct platform_device *dev)
+ {
+ printk(KERN_INFO "s5p_cec_resume is a NOP\n");
+ return 0;
+ }
+#else
+ #define s5p_cec_suspend NULL
+ #define s5p_cec_resume NULL
+#endif
+
+static struct platform_driver s5p_cec_driver = {
+ .probe = s5p_cec_probe,
+ .remove = s5p_cec_remove,
+ .suspend = s5p_cec_suspend,
+ .resume = s5p_cec_resume,
+ .driver = {
+ .name = "s5p-cec",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(s5p_cec_driver);
diff --git a/drivers/media/platform/s5p-tv/cec_hw.c b/drivers/media/platform/s5p-tv/cec_hw.c
new file mode 100644
index 00000000000000..108e5b3da04bc3
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/cec_hw.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * CEC for Samsung S5P TVOUT driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include
+#include
+#include
+
+#include
+
+#include "cec_hw.h"
+#include "regs-cec.h"
+
+#define S5P_HDMI_FIN 24000000
+#define CEC_DIV_RATIO 320000
+
+#define CEC_MESSAGE_BROADCAST_MASK 0x0F
+#define CEC_MESSAGE_BROADCAST 0x0F
+#define CEC_FILTER_THRESHOLD 0x15
+
+static struct resource *cec_mem;
+void __iomem *cec_base;
+
+struct cec_rx_struct cec_rx_struct;
+struct cec_tx_struct cec_tx_struct;
+
+void s5p_cec_set_divider(void)
+{
+ u32 div_ratio, reg, div_val;
+
+ div_ratio = (S5P_HDMI_FIN / CEC_DIV_RATIO) - 1;
+
+ reg = readl(S5P_HDMI_PHY_CONTROL);
+ reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
+
+ writel(reg, S5P_HDMI_PHY_CONTROL);
+
+ div_val = (CEC_DIV_RATIO * 0.00005) - 1;
+
+ writeb(0x0, cec_base + S5P_CEC_DIVISOR_3);
+ writeb(0x0, cec_base + S5P_CEC_DIVISOR_2);
+ writeb(0x0, cec_base + S5P_CEC_DIVISOR_1);
+ writeb(div_val, cec_base + S5P_CEC_DIVISOR_0);
+}
+
+void s5p_cec_enable_rx(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CEC_RX_CTRL);
+ reg |= S5P_CEC_RX_CTRL_ENABLE;
+ writeb(reg, cec_base + S5P_CEC_RX_CTRL);
+}
+
+void s5p_cec_mask_rx_interrupts(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CEC_IRQ_MASK);
+ reg |= S5P_CEC_IRQ_RX_DONE;
+ reg |= S5P_CEC_IRQ_RX_ERROR;
+ writeb(reg, cec_base + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_unmask_rx_interrupts(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CEC_IRQ_MASK);
+ reg &= ~S5P_CEC_IRQ_RX_DONE;
+ reg &= ~S5P_CEC_IRQ_RX_ERROR;
+ writeb(reg, cec_base + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_mask_tx_interrupts(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CEC_IRQ_MASK);
+ reg |= S5P_CEC_IRQ_TX_DONE;
+ reg |= S5P_CEC_IRQ_TX_ERROR;
+ writeb(reg, cec_base + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_unmask_tx_interrupts(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CEC_IRQ_MASK);
+ reg &= ~S5P_CEC_IRQ_TX_DONE;
+ reg &= ~S5P_CEC_IRQ_TX_ERROR;
+ writeb(reg, cec_base + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_tx_reset(void)
+{
+ writeb(S5P_CEC_TX_CTRL_RESET, cec_base + S5P_CEC_TX_CTRL);
+}
+
+void s5p_cec_rx_reset(void)
+{
+ writeb(S5P_CEC_RX_CTRL_RESET, cec_base + S5P_CEC_RX_CTRL);
+}
+
+void s5p_cec_reset(void)
+{
+ s5p_cec_rx_reset();
+ s5p_cec_tx_reset();
+}
+
+void s5p_cec_threshold(void)
+{
+ writeb(CEC_FILTER_THRESHOLD, cec_base + S5P_CEC_RX_FILTER_TH);
+ writeb(0, cec_base + S5P_CEC_RX_FILTER_CTRL);
+}
+
+void s5p_cec_set_tx_state(enum cec_state state)
+{
+ atomic_set(&cec_tx_struct.state, state);
+}
+
+void s5p_cec_set_rx_state(enum cec_state state)
+{
+ atomic_set(&cec_rx_struct.state, state);
+}
+
+void s5p_cec_copy_packet(char *data, size_t count)
+{
+ int i = 0;
+ u8 reg;
+
+ while (i < count) {
+ writeb(data[i], cec_base + (S5P_CEC_TX_BUFF0 + (i * 4)));
+ i++;
+ }
+ printk(KERN_INFO "s5p_cec_copy_packet(): written %i bytes to cec_base\n", count);
+
+ writeb(count, cec_base + S5P_CEC_TX_BYTES);
+ s5p_cec_set_tx_state(STATE_TX);
+ reg = readb(cec_base + S5P_CEC_TX_CTRL);
+ reg |= S5P_CEC_TX_CTRL_START;
+
+ if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST)
+ reg |= S5P_CEC_TX_CTRL_BCAST;
+ else
+ reg &= ~S5P_CEC_TX_CTRL_BCAST;
+
+ reg |= 0x50;
+ writeb(reg, cec_base + S5P_CEC_TX_CTRL);
+}
+
+void s5p_cec_set_addr(u32 addr)
+{
+ writeb(addr & 0x0F, cec_base + S5P_CEC_LOGIC_ADDR);
+}
+
+u32 s5p_cec_get_status(void)
+{
+ u32 status = 0;
+
+ status = readb(cec_base + S5P_CEC_STATUS_0);
+ status |= readb(cec_base + S5P_CEC_STATUS_1) << 8;
+ status |= readb(cec_base + S5P_CEC_STATUS_2) << 16;
+ status |= readb(cec_base + S5P_CEC_STATUS_3) << 24;
+
+ return status;
+}
+
+void s5p_clr_pending_tx(void)
+{
+ writeb(S5P_CEC_IRQ_TX_DONE | S5P_CEC_IRQ_TX_ERROR,
+ cec_base + S5P_CEC_IRQ_CLEAR);
+}
+
+void s5p_clr_pending_rx(void)
+{
+ writeb(S5P_CEC_IRQ_RX_DONE | S5P_CEC_IRQ_RX_ERROR,
+ cec_base + S5P_CEC_IRQ_CLEAR);
+}
+
+void s5p_cec_get_rx_buf(u32 size, u8 *buffer)
+{
+ u32 i = 0;
+
+ while (i < size) {
+ buffer[i] = readb(cec_base + S5P_CEC_RX_BUFF0 + (i * 4));
+ i++;
+ }
+}
+
+int s5p_cec_mem_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ size_t size = 0;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev,
+ "Failed to get memory region resource for cec\n");
+ return -ENOENT;
+ } else
+ size = resource_size(res);
+
+ cec_mem = request_mem_region(res->start, size, pdev->name);
+ if (cec_mem == NULL) {
+ dev_err(&pdev->dev, "Failed to get memory at size %i, name %s\n", size, pdev->name);
+ return -ENOENT;
+ }
+
+ cec_base = ioremap(res->start, size);
+ if (cec_base == NULL) {
+ dev_err(&pdev->dev,
+ "Failed to ioremap address region for cec\n");
+ return -ENOENT;
+ }
+ dev_info(&pdev->dev, "s5p_cec_mem_probe(): mapped cec_base to %p, size 0x%x\n", cec_base, size);
+ return ret;
+}
+
+int s5p_cec_mem_release(struct platform_device *pdev)
+{
+ dev_info(&pdev->dev, "Releasing memory\n");
+ iounmap(cec_base);
+ if (cec_mem != NULL) {
+ if (release_resource(cec_mem))
+ dev_err(&pdev->dev, "Can't remove s5p-cec driver\n");
+
+ kfree(cec_mem);
+
+ cec_mem = NULL;
+ }
+ return 0;
+}
diff --git a/drivers/media/platform/s5p-tv/cec_hw.h b/drivers/media/platform/s5p-tv/cec_hw.h
new file mode 100644
index 00000000000000..3a0e4c13f6e193
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/cec_hw.h
@@ -0,0 +1,68 @@
+
+#ifndef CEC_HW_H_
+#define CEC_HW_H_
+
+#include
+
+#define to_tvout_plat(d) (to_platform_device(d)->dev.platform_data)
+
+#define tvout_err(fmt, ...) \
+ printk(KERN_ERR "[%s] %s(): " fmt, \
+ DRV_NAME, __func__, ##__VA_ARGS__)
+
+#ifndef tvout_dbg
+#ifdef CONFIG_S5P_TVOUT_DEBUG
+#define tvout_dbg(fmt, ...) \
+ printk(KERN_INFO "[%s] %s(): " fmt, \
+ DRV_NAME, __func__, ##__VA_ARGS__)
+#else
+#define tvout_dbg(fmt, ...)
+#endif
+#endif
+
+
+enum cec_state {
+ STATE_RX,
+ STATE_TX,
+ STATE_DONE,
+ STATE_ERROR
+};
+
+struct cec_rx_struct {
+ spinlock_t lock;
+ wait_queue_head_t waitq;
+ atomic_t state;
+ u8 *buffer;
+ unsigned int size;
+};
+
+struct cec_tx_struct {
+ wait_queue_head_t waitq;
+ atomic_t state;
+};
+
+extern struct cec_rx_struct cec_rx_struct;
+extern struct cec_tx_struct cec_tx_struct;
+
+void s5p_cec_set_divider(void);
+void s5p_cec_enable_rx(void);
+void s5p_cec_mask_rx_interrupts(void);
+void s5p_cec_unmask_rx_interrupts(void);
+void s5p_cec_mask_tx_interrupts(void);
+void s5p_cec_unmask_tx_interrupts(void);
+void s5p_cec_reset(void);
+void s5p_cec_tx_reset(void);
+void s5p_cec_rx_reset(void);
+void s5p_cec_threshold(void);
+void s5p_cec_set_tx_state(enum cec_state state);
+void s5p_cec_set_rx_state(enum cec_state state);
+void s5p_cec_copy_packet(char *data, size_t count);
+void s5p_cec_set_addr(u32 addr);
+u32 s5p_cec_get_status(void);
+void s5p_clr_pending_tx(void);
+void s5p_clr_pending_rx(void);
+void s5p_cec_get_rx_buf(u32 size, u8 *buffer);
+int s5p_cec_mem_probe(struct platform_device *pdev);
+int s5p_cec_mem_release(struct platform_device *pdev);
+
+#endif
\ No newline at end of file
diff --git a/drivers/media/platform/s5p-tv/regs-cec.h b/drivers/media/platform/s5p-tv/regs-cec.h
new file mode 100644
index 00000000000000..6a86d6e153a263
--- /dev/null
+++ b/drivers/media/platform/s5p-tv/regs-cec.h
@@ -0,0 +1,95 @@
+/* linux/drivers/media/video/samsung/tv20/s5pc100/regs/regs-cec.h
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * CEC register header file for Samsung TVOut driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/*
+ * Source:
+ * http://code.google.com/p/openwrt-for-embedded/source/browse/trunk/target/linux/s5pv210/files-2.6.35/arch/arm/plat-s5p/include/plat/regs-cec.h?r=56
+ */
+
+#ifndef __REGS_CEC_H
+#define __REGS_CEC_H
+
+#define HDMIDP_CECREG(x) (x)
+
+#define S5P_CEC_STATUS_0 HDMIDP_CECREG(0x0000)
+#define S5P_CEC_STATUS_1 HDMIDP_CECREG(0x0004)
+#define S5P_CEC_STATUS_2 HDMIDP_CECREG(0x0008)
+#define S5P_CEC_STATUS_3 HDMIDP_CECREG(0x000C)
+#define S5P_CEC_IRQ_MASK HDMIDP_CECREG(0x0010)
+#define S5P_CEC_IRQ_CLEAR HDMIDP_CECREG(0x0014)
+#define S5P_CEC_LOGIC_ADDR HDMIDP_CECREG(0x0020)
+#define S5P_CEC_DIVISOR_0 HDMIDP_CECREG(0x0030)
+#define S5P_CEC_DIVISOR_1 HDMIDP_CECREG(0x0034)
+#define S5P_CEC_DIVISOR_2 HDMIDP_CECREG(0x0038)
+#define S5P_CEC_DIVISOR_3 HDMIDP_CECREG(0x003C)
+
+#define S5P_CEC_TX_CTRL HDMIDP_CECREG(0x0040)
+#define S5P_CEC_TX_BYTES HDMIDP_CECREG(0x0044)
+#define S5P_CEC_TX_STAT0 HDMIDP_CECREG(0x0060)
+#define S5P_CEC_TX_STAT1 HDMIDP_CECREG(0x0064)
+#define S5P_CEC_TX_BUFF0 HDMIDP_CECREG(0x0080)
+#define S5P_CEC_TX_BUFF1 HDMIDP_CECREG(0x0084)
+#define S5P_CEC_TX_BUFF2 HDMIDP_CECREG(0x0088)
+#define S5P_CEC_TX_BUFF3 HDMIDP_CECREG(0x008C)
+#define S5P_CEC_TX_BUFF4 HDMIDP_CECREG(0x0090)
+#define S5P_CEC_TX_BUFF5 HDMIDP_CECREG(0x0094)
+#define S5P_CEC_TX_BUFF6 HDMIDP_CECREG(0x0098)
+#define S5P_CEC_TX_BUFF7 HDMIDP_CECREG(0x009C)
+#define S5P_CEC_TX_BUFF8 HDMIDP_CECREG(0x00A0)
+#define S5P_CEC_TX_BUFF9 HDMIDP_CECREG(0x00A4)
+#define S5P_CEC_TX_BUFF10 HDMIDP_CECREG(0x00A8)
+#define S5P_CEC_TX_BUFF11 HDMIDP_CECREG(0x00AC)
+#define S5P_CEC_TX_BUFF12 HDMIDP_CECREG(0x00B0)
+#define S5P_CEC_TX_BUFF13 HDMIDP_CECREG(0x00B4)
+#define S5P_CEC_TX_BUFF14 HDMIDP_CECREG(0x00B8)
+#define S5P_CEC_TX_BUFF15 HDMIDP_CECREG(0x00BC)
+
+#define S5P_CEC_RX_CTRL HDMIDP_CECREG(0x00C0)
+#define S5P_CEC_RX_STAT0 HDMIDP_CECREG(0x00E0)
+#define S5P_CEC_RX_STAT1 HDMIDP_CECREG(0x00E4)
+#define S5P_CEC_RX_BUFF0 HDMIDP_CECREG(0x0100)
+#define S5P_CEC_RX_BUFF1 HDMIDP_CECREG(0x0104)
+#define S5P_CEC_RX_BUFF2 HDMIDP_CECREG(0x0108)
+#define S5P_CEC_RX_BUFF3 HDMIDP_CECREG(0x010C)
+#define S5P_CEC_RX_BUFF4 HDMIDP_CECREG(0x0110)
+#define S5P_CEC_RX_BUFF5 HDMIDP_CECREG(0x0114)
+#define S5P_CEC_RX_BUFF6 HDMIDP_CECREG(0x0118)
+#define S5P_CEC_RX_BUFF7 HDMIDP_CECREG(0x011C)
+#define S5P_CEC_RX_BUFF8 HDMIDP_CECREG(0x0120)
+#define S5P_CEC_RX_BUFF9 HDMIDP_CECREG(0x0124)
+#define S5P_CEC_RX_BUFF10 HDMIDP_CECREG(0x0128)
+#define S5P_CEC_RX_BUFF11 HDMIDP_CECREG(0x012C)
+#define S5P_CEC_RX_BUFF12 HDMIDP_CECREG(0x0130)
+#define S5P_CEC_RX_BUFF13 HDMIDP_CECREG(0x0134)
+#define S5P_CEC_RX_BUFF14 HDMIDP_CECREG(0x0138)
+#define S5P_CEC_RX_BUFF15 HDMIDP_CECREG(0x013C)
+
+#define S5P_CEC_RX_FILTER_CTRL HDMIDP_CECREG(0x0180)
+#define S5P_CEC_RX_FILTER_TH HDMIDP_CECREG(0x0184)
+
+#define S5P_CEC_IRQ_TX_DONE (1<<0)
+#define S5P_CEC_IRQ_TX_ERROR (1<<1)
+#define S5P_CEC_IRQ_RX_DONE (1<<4)
+#define S5P_CEC_IRQ_RX_ERROR (1<<5)
+
+#define S5P_CEC_TX_CTRL_START (1<<0)
+#define S5P_CEC_TX_CTRL_BCAST (1<<1)
+#define S5P_CEC_TX_CTRL_RETRY (0x04<<4)
+#define S5P_CEC_TX_CTRL_RESET (1<<7)
+
+#define S5P_CEC_RX_CTRL_ENABLE (1<<0)
+#define S5P_CEC_RX_CTRL_RESET (1<<7)
+
+#define S5P_CEC_LOGIC_ADDR_MASK 0x0F
+
+#endif /* __REGS_CEC_H */
+