rk3288 hdmi: If audio source if spdif, sclk/fs should be 128x.
[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         hdmi_writel(hdmi_dev, CEC_LOCK, 0x0);
33         return 0;
34 }
35
36
37 void rockchip_hdmiv2_cec_setcecla(struct hdmi *hdmi, int ceclgaddr)
38 {
39         struct hdmi_dev *hdmi_dev = hdmi->property->priv;
40         short val;
41
42         if (ceclgaddr < 0 || ceclgaddr > 16)
43                 return;
44         val = 1 << ceclgaddr;
45         hdmi_writel(hdmi_dev, CEC_ADDR_L, val & 0xff);
46         hdmi_writel(hdmi_dev, CEC_ADDR_H, val>>8);
47 }
48
49 static int rockchip_hdmiv2_cec_sendframe(struct hdmi *hdmi,
50                                          struct cec_framedata *frame)
51 {
52         struct hdmi_dev *hdmi_dev = hdmi->property->priv;
53         int i, interrupt;
54
55         CECDBG("TX srcdestaddr %02x opcode %02x ",
56                frame->srcdestaddr, frame->opcode);
57         if (frame->argcount) {
58                 CECDBG("args:");
59                 for (i = 0; i < frame->argcount; i++)
60                         CECDBG("%02x ", frame->args[i]);
61         }
62         CECDBG("\n");
63         if ((frame->srcdestaddr & 0x0f) == ((frame->srcdestaddr >> 4) & 0x0f)) {
64                 /*it is a ping command*/
65                 hdmi_writel(hdmi_dev, CEC_TX_DATA0, frame->srcdestaddr);
66                 hdmi_writel(hdmi_dev, CEC_TX_CNT, 1);
67         } else {
68                 hdmi_writel(hdmi_dev, CEC_TX_DATA0, frame->srcdestaddr);
69                 hdmi_writel(hdmi_dev, CEC_TX_DATA0 + 1, frame->opcode);
70                 for (i = 0; i < frame->argcount; i++)
71                         hdmi_writel(hdmi_dev,
72                                     CEC_TX_DATA0 + 2 + i, frame->args[i]);
73                 hdmi_writel(hdmi_dev, CEC_TX_CNT, frame->argcount + 2);
74         }
75         /*Start TX*/
76         hdmi_msk_reg(hdmi_dev, CEC_CTRL, m_CEC_SEND, v_CEC_SEND(1));
77         i = 20;
78         while (i--) {
79                 usleep_range(900, 1000);
80                 interrupt = hdmi_readl(hdmi_dev, IH_CEC_STAT0);
81                 if (interrupt & (m_ERR_INITIATOR | m_ARB_LOST |
82                                         m_NACK | m_DONE)) {
83                         hdmi_writel(hdmi_dev, IH_CEC_STAT0,
84                                     interrupt & (m_ERR_INITIATOR |
85                                     m_ARB_LOST | m_NACK | m_DONE));
86                         break;
87                 }
88         }
89         CECDBG("%s interrupt 0x%02x\n", __func__, interrupt);
90         if (interrupt & m_DONE)
91                 return 0;
92         else if (interrupt & m_NACK)
93                 return 1;
94         else
95                 return  -1;
96 }
97
98 void rockchip_hdmiv2_cec_init(struct hdmi *hdmi)
99 {
100         struct hdmi_dev *hdmi_dev = hdmi->property->priv;
101
102         if (init) {
103                 rockchip_hdmi_cec_init(hdmi,
104                                        rockchip_hdmiv2_cec_sendframe,
105                                        rockchip_hdmiv2_cec_readframe,
106                                        rockchip_hdmiv2_cec_setcecla);
107                 init = 0;
108                 /* init_waitqueue_head(&wait); */
109         }
110         hdmi_writel(hdmi_dev, IH_MUTE_CEC_STAT0, m_ERR_INITIATOR |
111                         m_ARB_LOST | m_NACK | m_DONE);
112         CECDBG("%s", __func__);
113 }