brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · eb981eb Raw
207 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c3 *4 * Copyright (c) 2009, 2014 Samsung Electronics5 *		http://www.samsung.com/6 *7 * cec ftn file for Samsung TVOUT driver8 */9 10#include <linux/io.h>11#include <linux/device.h>12 13#include "exynos_hdmi_cec.h"14#include "regs-cec.h"15 16#define S5P_HDMI_FIN			2400000017#define CEC_DIV_RATIO			32000018 19#define CEC_MESSAGE_BROADCAST_MASK	0x0F20#define CEC_MESSAGE_BROADCAST		0x0F21#define CEC_FILTER_THRESHOLD		0x1522 23void s5p_cec_set_divider(struct s5p_cec_dev *cec)24{25	u32 div_ratio, div_val;26	unsigned int reg;27 28	div_ratio  = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;29 30	if (regmap_read(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, &reg)) {31		dev_err(cec->dev, "failed to read phy control\n");32		return;33	}34 35	reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);36 37	if (regmap_write(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, reg)) {38		dev_err(cec->dev, "failed to write phy control\n");39		return;40	}41 42	div_val = CEC_DIV_RATIO * 0.00005 - 1;43 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);48}49 50void s5p_cec_enable_rx(struct s5p_cec_dev *cec)51{52	u8 reg;53 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);57}58 59void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec)60{61	u8 reg;62 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);67}68 69void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec)70{71	u8 reg;72 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);77}78 79void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec)80{81	u8 reg;82 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);87}88 89void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec)90{91	u8 reg;92 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);97}98 99void s5p_cec_reset(struct s5p_cec_dev *cec)100{101	u8 reg;102 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);105 106	reg = readb(cec->reg + 0xc4);107	reg &= ~0x1;108	writeb(reg, cec->reg + 0xc4);109}110 111void s5p_cec_tx_reset(struct s5p_cec_dev *cec)112{113	writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);114}115 116void s5p_cec_rx_reset(struct s5p_cec_dev *cec)117{118	u8 reg;119 120	writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);121 122	reg = readb(cec->reg + 0xc4);123	reg &= ~0x1;124	writeb(reg, cec->reg + 0xc4);125}126 127void s5p_cec_threshold(struct s5p_cec_dev *cec)128{129	writeb(CEC_FILTER_THRESHOLD, cec->reg + S5P_CEC_RX_FILTER_TH);130	writeb(0, cec->reg + S5P_CEC_RX_FILTER_CTRL);131}132 133void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data,134			 size_t count, u8 retries)135{136	int i = 0;137	u8 reg;138 139	while (i < count) {140		writeb(data[i], cec->reg + (S5P_CEC_TX_BUFF0 + (i * 4)));141		i++;142	}143 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;147	reg &= ~0x70;148	reg |= retries << 4;149 150	if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST) {151		dev_dbg(cec->dev, "Broadcast");152		reg |= S5P_CEC_TX_CTRL_BCAST;153	} else {154		dev_dbg(cec->dev, "No Broadcast");155		reg &= ~S5P_CEC_TX_CTRL_BCAST;156	}157 158	writeb(reg, cec->reg + S5P_CEC_TX_CTRL);159	dev_dbg(cec->dev, "cec-tx: cec count (%zu): %*ph", count,160		(int)count, data);161}162 163void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr)164{165	writeb(addr & 0x0F, cec->reg + S5P_CEC_LOGIC_ADDR);166}167 168u32 s5p_cec_get_status(struct s5p_cec_dev *cec)169{170	u32 status = 0;171 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;177 178	dev_dbg(cec->dev, "status = 0x%x!\n", status);179 180	return status;181}182 183void s5p_clr_pending_tx(struct s5p_cec_dev *cec)184{185	writeb(S5P_CEC_IRQ_TX_DONE | S5P_CEC_IRQ_TX_ERROR,186	       cec->reg + S5P_CEC_IRQ_CLEAR);187}188 189void s5p_clr_pending_rx(struct s5p_cec_dev *cec)190{191	writeb(S5P_CEC_IRQ_RX_DONE | S5P_CEC_IRQ_RX_ERROR,192	       cec->reg + S5P_CEC_IRQ_CLEAR);193}194 195void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer)196{197	u32 i = 0;198	char debug[40];199 200	while (i < size) {201		buffer[i] = readb(cec->reg + S5P_CEC_RX_BUFF0 + (i * 4));202		sprintf(debug + i * 2, "%02x ", buffer[i]);203		i++;204	}205	dev_dbg(cec->dev, "cec-rx: cec size(%d): %s", size, debug);206}207