1 /* linux/drivers/media/video/samsung/tvout/hw_if/cec.c
3 * Copyright (c) 2009 Samsung Electronics
4 * http://www.samsung.com/
6 * cec ftn file for Samsung TVOUT driver
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
14 #include <linux/slab.h>
15 #include <linux/platform_device.h>
16 #include <linux/videodev2.h>
17 #include <linux/videodev2_exynos_camera.h>
18 #include <linux/irqreturn.h>
19 #include <linux/stddef.h>
21 #include <mach/regs-clock.h>
22 #include <mach/regs-clock.h>
23 #include <mach/regs-cec.h>
29 #ifdef CONFIG_CEC_DEBUG
30 #define tvout_dbg(fmt, ...) \
31 printk(KERN_INFO "\t\t[CEC] %s(): " fmt, \
32 __func__, ##__VA_ARGS__)
34 #define tvout_dbg(fmt, ...)
37 #define S5P_HDMI_FIN 24000000
38 #define CEC_DIV_RATIO 320000
40 #define CEC_MESSAGE_BROADCAST_MASK 0x0F
41 #define CEC_MESSAGE_BROADCAST 0x0F
42 #define CEC_FILTER_THRESHOLD 0x15
44 static struct resource *cec_mem;
45 void __iomem *cec_base;
47 struct cec_rx_struct cec_rx_struct;
48 struct cec_tx_struct cec_tx_struct;
50 void s5p_cec_set_divider(void)
52 u32 div_ratio, reg, div_val;
54 div_ratio = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;
56 reg = readl(S5P_HDMI_PHY_CONTROL);
57 reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
59 writel(reg, S5P_HDMI_PHY_CONTROL);
61 div_val = CEC_DIV_RATIO * 0.00005 - 1;
63 writeb(0x0, cec_base + S5P_CES_DIVISOR_3);
64 writeb(0x0, cec_base + S5P_CES_DIVISOR_2);
65 writeb(0x0, cec_base + S5P_CES_DIVISOR_1);
66 writeb(div_val, cec_base + S5P_CES_DIVISOR_0);
69 void s5p_cec_enable_rx(void)
73 reg = readb(cec_base + S5P_CES_RX_CTRL);
74 reg |= S5P_CES_RX_CTRL_ENABLE;
75 writeb(reg, cec_base + S5P_CES_RX_CTRL);
78 void s5p_cec_mask_rx_interrupts(void)
82 reg = readb(cec_base + S5P_CES_IRQ_MASK);
83 reg |= S5P_CES_IRQ_RX_DONE;
84 reg |= S5P_CES_IRQ_RX_ERROR;
85 writeb(reg, cec_base + S5P_CES_IRQ_MASK);
88 void s5p_cec_unmask_rx_interrupts(void)
92 reg = readb(cec_base + S5P_CES_IRQ_MASK);
93 reg &= ~S5P_CES_IRQ_RX_DONE;
94 reg &= ~S5P_CES_IRQ_RX_ERROR;
95 writeb(reg, cec_base + S5P_CES_IRQ_MASK);
98 void s5p_cec_mask_tx_interrupts(void)
101 reg = readb(cec_base + S5P_CES_IRQ_MASK);
102 reg |= S5P_CES_IRQ_TX_DONE;
103 reg |= S5P_CES_IRQ_TX_ERROR;
104 writeb(reg, cec_base + S5P_CES_IRQ_MASK);
108 void s5p_cec_unmask_tx_interrupts(void)
112 reg = readb(cec_base + S5P_CES_IRQ_MASK);
113 reg &= ~S5P_CES_IRQ_TX_DONE;
114 reg &= ~S5P_CES_IRQ_TX_ERROR;
115 writeb(reg, cec_base + S5P_CES_IRQ_MASK);
118 void s5p_cec_reset(void)
120 writeb(S5P_CES_RX_CTRL_RESET, cec_base + S5P_CES_RX_CTRL);
121 writeb(S5P_CES_TX_CTRL_RESET, cec_base + S5P_CES_TX_CTRL);
124 void s5p_cec_tx_reset(void)
126 writeb(S5P_CES_TX_CTRL_RESET, cec_base + S5P_CES_TX_CTRL);
129 void s5p_cec_rx_reset(void)
131 writeb(S5P_CES_RX_CTRL_RESET, cec_base + S5P_CES_RX_CTRL);
134 void s5p_cec_threshold(void)
136 writeb(CEC_FILTER_THRESHOLD, cec_base + S5P_CES_RX_FILTER_TH);
137 writeb(0, cec_base + S5P_CES_RX_FILTER_CTRL);
140 void s5p_cec_set_tx_state(enum cec_state state)
142 atomic_set(&cec_tx_struct.state, state);
145 void s5p_cec_set_rx_state(enum cec_state state)
147 atomic_set(&cec_rx_struct.state, state);
150 void s5p_cec_copy_packet(char *data, size_t count)
156 writeb(data[i], cec_base + (S5P_CES_TX_BUFF0 + (i * 4)));
160 writeb(count, cec_base + S5P_CES_TX_BYTES);
161 s5p_cec_set_tx_state(STATE_TX);
162 reg = readb(cec_base + S5P_CES_TX_CTRL);
163 reg |= S5P_CES_TX_CTRL_START;
165 if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST)
166 reg |= S5P_CES_TX_CTRL_BCAST;
168 reg &= ~S5P_CES_TX_CTRL_BCAST;
171 writeb(reg, cec_base + S5P_CES_TX_CTRL);
174 void s5p_cec_set_addr(u32 addr)
176 writeb(addr & 0x0F, cec_base + S5P_CES_LOGIC_ADDR);
179 u32 s5p_cec_get_status(void)
183 status = readb(cec_base + S5P_CES_STATUS_0);
184 status |= readb(cec_base + S5P_CES_STATUS_1) << 8;
185 status |= readb(cec_base + S5P_CES_STATUS_2) << 16;
186 status |= readb(cec_base + S5P_CES_STATUS_3) << 24;
188 tvout_dbg("status = 0x%x!\n", status);
193 void s5p_clr_pending_tx(void)
195 writeb(S5P_CES_IRQ_TX_DONE | S5P_CES_IRQ_TX_ERROR,
196 cec_base + S5P_CES_IRQ_CLEAR);
199 void s5p_clr_pending_rx(void)
201 writeb(S5P_CES_IRQ_RX_DONE | S5P_CES_IRQ_RX_ERROR,
202 cec_base + S5P_CES_IRQ_CLEAR);
205 void s5p_cec_get_rx_buf(u32 size, u8 *buffer)
210 buffer[i] = readb(cec_base + S5P_CES_RX_BUFF0 + (i * 4));
215 int __init s5p_cec_mem_probe(struct platform_device *pdev)
217 struct resource *res;
221 dev_dbg(&pdev->dev, "%s\n", __func__);
223 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
227 "failed to get memory region resource for cec\n");
231 size = (res->end - res->start) + 1;
232 cec_mem = request_mem_region(res->start, size, pdev->name);
234 if (cec_mem == NULL) {
236 "failed to get memory region for cec\n");
240 cec_base = ioremap(res->start, size);
242 if (cec_base == NULL) {
244 "failed to ioremap address region for cec\n");
251 int __init s5p_cec_mem_release(struct platform_device *pdev)
255 if (cec_mem != NULL) {
256 if (release_resource(cec_mem))
258 "Can't remove tvout drv !!\n");