hdmi:cec:update driver to match android HDMI CEC HAL.
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rockchip-hdmiv2 / rockchip_hdmiv2_cec.c
1 #include <linux/delay.h>
2 #include "../rockchip-hdmi-cec.h"
3 #include "rockchip_hdmiv2.h"
4 #include "rockchip_hdmiv2_hw.h"
5
6 /* static wait_queue_head_t     wait;*/
7 static int init = 1;
8 void rockchip_hdmiv2_cec_isr(struct hdmi_dev *hdmi_dev, char cec_int)
9 {
10         CECDBG("%s cec 0x%x\n", __func__, cec_int);
11         if (cec_int & m_EOM)
12                 rockchip_hdmi_cec_submit_work(EVENT_RX_FRAME, 0, NULL);
13         if (cec_int & m_DONE)
14                 CECDBG("send frame success\n");
15 }
16
17 static int rockchip_hdmiv2_cec_readframe(struct hdmi *hdmi,
18                                          struct cec_framedata *frame)
19 {
20         struct hdmi_dev *hdmi_dev = hdmi->property->priv;
21         int i, count;
22         char *data = (char *)frame;
23
24         if (frame == NULL)
25                 return -1;
26         count = hdmi_readl(hdmi_dev, CEC_RX_CNT);
27         CECDBG("%s count %d\n", __func__, count);
28         for (i = 0; i < count; i++) {
29                 data[i] = hdmi_readl(hdmi_dev, CEC_RX_DATA0 + i);
30                 CECDBG("%02x\n", data[i]);
31         }
32         frame->argcount = count - 2;
33         hdmi_writel(hdmi_dev, CEC_LOCK, 0x0);
34         return 0;
35 }
36
37
38 void rockchip_hdmiv2_cec_setcecla(struct hdmi *hdmi, int ceclgaddr)
39 {
40         struct hdmi_dev *hdmi_dev = hdmi->property->priv;
41         short val;
42
43         if (ceclgaddr < 0 || ceclgaddr > 16)
44                 return;
45         val = 1 << ceclgaddr;
46         hdmi_writel(hdmi_dev, CEC_ADDR_L, val & 0xff);
47         hdmi_writel(hdmi_dev, CEC_ADDR_H, val>>8);
48 }
49
50 static int rockchip_hdmiv2_cec_sendframe(struct hdmi *hdmi,
51                                          struct cec_framedata *frame)
52 {
53         struct hdmi_dev *hdmi_dev = hdmi->property->priv;
54         int i, interrupt;
55
56         CECDBG("TX srcdestaddr %02x opcode %02x ",
57                frame->srcdestaddr, frame->opcode);
58         if (frame->argcount) {
59                 CECDBG("args:");
60                 for (i = 0; i < frame->argcount; i++)
61                         CECDBG("%02x ", frame->args[i]);
62         }
63         CECDBG("\n");
64         if ((frame->srcdestaddr & 0x0f) == ((frame->srcdestaddr >> 4) & 0x0f)) {
65                 /*it is a ping command*/
66                 hdmi_writel(hdmi_dev, CEC_TX_DATA0, frame->srcdestaddr);
67                 hdmi_writel(hdmi_dev, CEC_TX_CNT, 1);
68         } else {
69                 hdmi_writel(hdmi_dev, CEC_TX_DATA0, frame->srcdestaddr);
70                 hdmi_writel(hdmi_dev, CEC_TX_DATA0 + 1, frame->opcode);
71                 for (i = 0; i < frame->argcount; i++)
72                         hdmi_writel(hdmi_dev,
73                                     CEC_TX_DATA0 + 2 + i, frame->args[i]);
74                 hdmi_writel(hdmi_dev, CEC_TX_CNT, frame->argcount + 2);
75         }
76         /*Start TX*/
77         hdmi_msk_reg(hdmi_dev, CEC_CTRL, m_CEC_SEND, v_CEC_SEND(1));
78         i = 400;
79         /* time = 2.4(ms)*(1 + 16)(head + param)*11(bit)*/
80         /*11bit =  start bit(4.5ms) + data bit(2.4ms) */
81         while (i--) {
82                 usleep_range(900, 1000);
83                 interrupt = hdmi_readl(hdmi_dev, IH_CEC_STAT0);
84                 if (interrupt & (m_ERR_INITIATOR | m_ARB_LOST |
85                                         m_NACK | m_DONE)) {
86                         hdmi_writel(hdmi_dev, IH_CEC_STAT0,
87                                     interrupt & (m_ERR_INITIATOR |
88                                     m_ARB_LOST | m_NACK | m_DONE));
89                         break;
90                 }
91         }
92         CECDBG("%s interrupt 0x%02x\n", __func__, interrupt);
93         if (interrupt & m_DONE)
94                 return 0;
95         else if (interrupt & m_NACK)
96                 return 1;
97         else
98                 return  -1;
99 }
100
101 void rockchip_hdmiv2_cec_init(struct hdmi *hdmi)
102 {
103         struct hdmi_dev *hdmi_dev = hdmi->property->priv;
104
105         if (init) {
106                 rockchip_hdmi_cec_init(hdmi,
107                                        rockchip_hdmiv2_cec_sendframe,
108                                        rockchip_hdmiv2_cec_readframe,
109                                        rockchip_hdmiv2_cec_setcecla);
110                 init = 0;
111                 /* init_waitqueue_head(&wait); */
112         }
113         hdmi_writel(hdmi_dev, IH_MUTE_CEC_STAT0, m_ERR_INITIATOR |
114                         m_ARB_LOST | m_NACK | m_DONE);
115         CECDBG("%s", __func__);
116 }