1 // SPDX-License-Identifier: GPL-2.0-only
2 /* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
4 * Copyright (c) 2009, 2014 Samsung Electronics
5 * http://www.samsung.com/
7 * cec ftn file for Samsung TVOUT driver
11 #include <linux/device.h>
13 #include "exynos_hdmi_cec.h"
16 #define S5P_HDMI_FIN 24000000
17 #define CEC_DIV_RATIO 320000
19 #define CEC_MESSAGE_BROADCAST_MASK 0x0F
20 #define CEC_MESSAGE_BROADCAST 0x0F
21 #define CEC_FILTER_THRESHOLD 0x15
23 void s5p_cec_set_divider(struct s5p_cec_dev
*cec
)
25 u32 div_ratio
, div_val
;
28 div_ratio
= S5P_HDMI_FIN
/ CEC_DIV_RATIO
- 1;
30 if (regmap_read(cec
->pmu
, EXYNOS_HDMI_PHY_CONTROL
, ®
)) {
31 dev_err(cec
->dev
, "failed to read phy control\n");
35 reg
= (reg
& ~(0x3FF << 16)) | (div_ratio
<< 16);
37 if (regmap_write(cec
->pmu
, EXYNOS_HDMI_PHY_CONTROL
, reg
)) {
38 dev_err(cec
->dev
, "failed to write phy control\n");
42 div_val
= CEC_DIV_RATIO
* 0.00005 - 1;
44 writeb(0x0, cec
->reg
+ S5P_CEC_DIVISOR_3
);
45 writeb(0x0, cec
->reg
+ S5P_CEC_DIVISOR_2
);
46 writeb(0x0, cec
->reg
+ S5P_CEC_DIVISOR_1
);
47 writeb(div_val
, cec
->reg
+ S5P_CEC_DIVISOR_0
);
50 void s5p_cec_enable_rx(struct s5p_cec_dev
*cec
)
54 reg
= readb(cec
->reg
+ S5P_CEC_RX_CTRL
);
55 reg
|= S5P_CEC_RX_CTRL_ENABLE
;
56 writeb(reg
, cec
->reg
+ S5P_CEC_RX_CTRL
);
59 void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev
*cec
)
63 reg
= readb(cec
->reg
+ S5P_CEC_IRQ_MASK
);
64 reg
|= S5P_CEC_IRQ_RX_DONE
;
65 reg
|= S5P_CEC_IRQ_RX_ERROR
;
66 writeb(reg
, cec
->reg
+ S5P_CEC_IRQ_MASK
);
69 void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev
*cec
)
73 reg
= readb(cec
->reg
+ S5P_CEC_IRQ_MASK
);
74 reg
&= ~S5P_CEC_IRQ_RX_DONE
;
75 reg
&= ~S5P_CEC_IRQ_RX_ERROR
;
76 writeb(reg
, cec
->reg
+ S5P_CEC_IRQ_MASK
);
79 void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev
*cec
)
83 reg
= readb(cec
->reg
+ S5P_CEC_IRQ_MASK
);
84 reg
|= S5P_CEC_IRQ_TX_DONE
;
85 reg
|= S5P_CEC_IRQ_TX_ERROR
;
86 writeb(reg
, cec
->reg
+ S5P_CEC_IRQ_MASK
);
89 void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev
*cec
)
93 reg
= readb(cec
->reg
+ S5P_CEC_IRQ_MASK
);
94 reg
&= ~S5P_CEC_IRQ_TX_DONE
;
95 reg
&= ~S5P_CEC_IRQ_TX_ERROR
;
96 writeb(reg
, cec
->reg
+ S5P_CEC_IRQ_MASK
);
99 void s5p_cec_reset(struct s5p_cec_dev
*cec
)
103 writeb(S5P_CEC_RX_CTRL_RESET
, cec
->reg
+ S5P_CEC_RX_CTRL
);
104 writeb(S5P_CEC_TX_CTRL_RESET
, cec
->reg
+ S5P_CEC_TX_CTRL
);
106 reg
= readb(cec
->reg
+ 0xc4);
108 writeb(reg
, cec
->reg
+ 0xc4);
111 void s5p_cec_tx_reset(struct s5p_cec_dev
*cec
)
113 writeb(S5P_CEC_TX_CTRL_RESET
, cec
->reg
+ S5P_CEC_TX_CTRL
);
116 void s5p_cec_rx_reset(struct s5p_cec_dev
*cec
)
120 writeb(S5P_CEC_RX_CTRL_RESET
, cec
->reg
+ S5P_CEC_RX_CTRL
);
122 reg
= readb(cec
->reg
+ 0xc4);
124 writeb(reg
, cec
->reg
+ 0xc4);
127 void s5p_cec_threshold(struct s5p_cec_dev
*cec
)
129 writeb(CEC_FILTER_THRESHOLD
, cec
->reg
+ S5P_CEC_RX_FILTER_TH
);
130 writeb(0, cec
->reg
+ S5P_CEC_RX_FILTER_CTRL
);
133 void s5p_cec_copy_packet(struct s5p_cec_dev
*cec
, char *data
,
134 size_t count
, u8 retries
)
140 writeb(data
[i
], cec
->reg
+ (S5P_CEC_TX_BUFF0
+ (i
* 4)));
144 writeb(count
, cec
->reg
+ S5P_CEC_TX_BYTES
);
145 reg
= readb(cec
->reg
+ S5P_CEC_TX_CTRL
);
146 reg
|= S5P_CEC_TX_CTRL_START
;
150 if ((data
[0] & CEC_MESSAGE_BROADCAST_MASK
) == CEC_MESSAGE_BROADCAST
) {
151 dev_dbg(cec
->dev
, "Broadcast");
152 reg
|= S5P_CEC_TX_CTRL_BCAST
;
154 dev_dbg(cec
->dev
, "No Broadcast");
155 reg
&= ~S5P_CEC_TX_CTRL_BCAST
;
158 writeb(reg
, cec
->reg
+ S5P_CEC_TX_CTRL
);
159 dev_dbg(cec
->dev
, "cec-tx: cec count (%zu): %*ph", count
,
163 void s5p_cec_set_addr(struct s5p_cec_dev
*cec
, u32 addr
)
165 writeb(addr
& 0x0F, cec
->reg
+ S5P_CEC_LOGIC_ADDR
);
168 u32
s5p_cec_get_status(struct s5p_cec_dev
*cec
)
172 status
= readb(cec
->reg
+ S5P_CEC_STATUS_0
) & 0xf;
173 status
|= (readb(cec
->reg
+ S5P_CEC_TX_STAT1
) & 0xf) << 4;
174 status
|= readb(cec
->reg
+ S5P_CEC_STATUS_1
) << 8;
175 status
|= readb(cec
->reg
+ S5P_CEC_STATUS_2
) << 16;
176 status
|= readb(cec
->reg
+ S5P_CEC_STATUS_3
) << 24;
178 dev_dbg(cec
->dev
, "status = 0x%x!\n", status
);
183 void s5p_clr_pending_tx(struct s5p_cec_dev
*cec
)
185 writeb(S5P_CEC_IRQ_TX_DONE
| S5P_CEC_IRQ_TX_ERROR
,
186 cec
->reg
+ S5P_CEC_IRQ_CLEAR
);
189 void s5p_clr_pending_rx(struct s5p_cec_dev
*cec
)
191 writeb(S5P_CEC_IRQ_RX_DONE
| S5P_CEC_IRQ_RX_ERROR
,
192 cec
->reg
+ S5P_CEC_IRQ_CLEAR
);
195 void s5p_cec_get_rx_buf(struct s5p_cec_dev
*cec
, u32 size
, u8
*buffer
)
201 buffer
[i
] = readb(cec
->reg
+ S5P_CEC_RX_BUFF0
+ (i
* 4));
202 sprintf(debug
+ i
* 2, "%02x ", buffer
[i
]);
205 dev_dbg(cec
->dev
, "cec-rx: cec size(%d): %s", size
, debug
);