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>
16 #include <mach/regs-clock.h>
17 #include <mach/regs-clock.h>
18 #include <mach/regs-cec.h>
20 #include "../s5p_tvout_common_lib.h"
25 #ifdef CONFIG_CEC_DEBUG
26 #define tvout_dbg(fmt, ...) \
27 printk(KERN_INFO "\t\t[CEC] %s(): " fmt, \
28 __func__, ##__VA_ARGS__)
30 #define tvout_dbg(fmt, ...)
34 #define S5P_HDMI_FIN 24000000
35 #define CEC_DIV_RATIO 320000
37 #define CEC_MESSAGE_BROADCAST_MASK 0x0F
38 #define CEC_MESSAGE_BROADCAST 0x0F
39 #define CEC_FILTER_THRESHOLD 0x15
41 static struct resource *cec_mem;
42 void __iomem *cec_base;
44 struct cec_rx_struct cec_rx_struct;
45 struct cec_tx_struct cec_tx_struct;
48 void s5p_cec_set_divider(void)
50 u32 div_ratio, reg, div_val;
52 div_ratio = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;
54 reg = readl(S5P_HDMI_PHY_CONTROL);
55 reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
57 writel(reg, S5P_HDMI_PHY_CONTROL);
59 div_val = CEC_DIV_RATIO * 0.00005 - 1;
61 writeb(0x0, cec_base + S5P_CES_DIVISOR_3);
62 writeb(0x0, cec_base + S5P_CES_DIVISOR_2);
63 writeb(0x0, cec_base + S5P_CES_DIVISOR_1);
64 writeb(div_val, cec_base + S5P_CES_DIVISOR_0);
67 void s5p_cec_enable_rx(void)
71 reg = readb(cec_base + S5P_CES_RX_CTRL);
72 reg |= S5P_CES_RX_CTRL_ENABLE;
73 writeb(reg, cec_base + S5P_CES_RX_CTRL);
76 void s5p_cec_mask_rx_interrupts(void)
80 reg = readb(cec_base + S5P_CES_IRQ_MASK);
81 reg |= S5P_CES_IRQ_RX_DONE;
82 reg |= S5P_CES_IRQ_RX_ERROR;
83 writeb(reg, cec_base + S5P_CES_IRQ_MASK);
86 void s5p_cec_unmask_rx_interrupts(void)
90 reg = readb(cec_base + S5P_CES_IRQ_MASK);
91 reg &= ~S5P_CES_IRQ_RX_DONE;
92 reg &= ~S5P_CES_IRQ_RX_ERROR;
93 writeb(reg, cec_base + S5P_CES_IRQ_MASK);
96 void s5p_cec_mask_tx_interrupts(void)
99 reg = readb(cec_base + S5P_CES_IRQ_MASK);
100 reg |= S5P_CES_IRQ_TX_DONE;
101 reg |= S5P_CES_IRQ_TX_ERROR;
102 writeb(reg, cec_base + S5P_CES_IRQ_MASK);
106 void s5p_cec_unmask_tx_interrupts(void)
110 reg = readb(cec_base + S5P_CES_IRQ_MASK);
111 reg &= ~S5P_CES_IRQ_TX_DONE;
112 reg &= ~S5P_CES_IRQ_TX_ERROR;
113 writeb(reg, cec_base + S5P_CES_IRQ_MASK);
116 void s5p_cec_reset(void)
118 writeb(S5P_CES_RX_CTRL_RESET, cec_base + S5P_CES_RX_CTRL);
119 writeb(S5P_CES_TX_CTRL_RESET, cec_base + S5P_CES_TX_CTRL);
122 void s5p_cec_tx_reset(void)
124 writeb(S5P_CES_TX_CTRL_RESET, cec_base + S5P_CES_TX_CTRL);
127 void s5p_cec_rx_reset(void)
129 writeb(S5P_CES_RX_CTRL_RESET, cec_base + S5P_CES_RX_CTRL);
132 void s5p_cec_threshold(void)
134 writeb(CEC_FILTER_THRESHOLD, cec_base + S5P_CES_RX_FILTER_TH);
135 writeb(0, cec_base + S5P_CES_RX_FILTER_CTRL);
138 void s5p_cec_set_tx_state(enum cec_state state)
140 atomic_set(&cec_tx_struct.state, state);
143 void s5p_cec_set_rx_state(enum cec_state state)
145 atomic_set(&cec_rx_struct.state, state);
148 void s5p_cec_copy_packet(char *data, size_t count)
154 writeb(data[i], cec_base + (S5P_CES_TX_BUFF0 + (i * 4)));
158 writeb(count, cec_base + S5P_CES_TX_BYTES);
159 s5p_cec_set_tx_state(STATE_TX);
160 reg = readb(cec_base + S5P_CES_TX_CTRL);
161 reg |= S5P_CES_TX_CTRL_START;
163 if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST)
164 reg |= S5P_CES_TX_CTRL_BCAST;
166 reg &= ~S5P_CES_TX_CTRL_BCAST;
169 writeb(reg, cec_base + S5P_CES_TX_CTRL);
172 void s5p_cec_set_addr(u32 addr)
174 writeb(addr & 0x0F, cec_base + S5P_CES_LOGIC_ADDR);
177 u32 s5p_cec_get_status(void)
181 status = readb(cec_base + S5P_CES_STATUS_0);
182 status |= readb(cec_base + S5P_CES_STATUS_1) << 8;
183 status |= readb(cec_base + S5P_CES_STATUS_2) << 16;
184 status |= readb(cec_base + S5P_CES_STATUS_3) << 24;
186 tvout_dbg("status = 0x%x!\n", status);
191 void s5p_clr_pending_tx(void)
193 writeb(S5P_CES_IRQ_TX_DONE | S5P_CES_IRQ_TX_ERROR,
194 cec_base + S5P_CES_IRQ_CLEAR);
197 void s5p_clr_pending_rx(void)
199 writeb(S5P_CES_IRQ_RX_DONE | S5P_CES_IRQ_RX_ERROR,
200 cec_base + S5P_CES_IRQ_CLEAR);
203 void s5p_cec_get_rx_buf(u32 size, u8 *buffer)
208 buffer[i] = readb(cec_base + S5P_CES_RX_BUFF0 + (i * 4));
213 void __init s5p_cec_mem_probe(struct platform_device *pdev)
215 struct resource *res;
219 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
223 "failed to get memory region resource for cec\n");
227 size = resource_size(res);
228 cec_mem = request_mem_region(res->start, size, pdev->name);
230 if (cec_mem == NULL) {
232 "failed to get memory region for cec\n");
236 cec_base = ioremap(res->start, size);
238 if (cec_base == NULL) {
240 "failed to ioremap address region for cec\n");
245 int __init s5p_cec_mem_release(struct platform_device *pdev)
249 if (cec_mem != NULL) {
250 if (release_resource(cec_mem))
252 "Can't remove tvout drv !!\n");