brintos

brintos / linux-shallow public Read only

0
0
Text · 10.7 KiB · 2e9c88a Raw
397 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * adv7511_cec.c - Analog Devices ADV7511/33 cec driver4 *5 * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.6 */7 8#include <linux/device.h>9#include <linux/module.h>10#include <linux/slab.h>11#include <linux/clk.h>12 13#include <media/cec.h>14 15#include "adv7511.h"16 17static const u8 ADV7511_REG_CEC_RX_FRAME_HDR[] = {18	ADV7511_REG_CEC_RX1_FRAME_HDR,19	ADV7511_REG_CEC_RX2_FRAME_HDR,20	ADV7511_REG_CEC_RX3_FRAME_HDR,21};22 23static const u8 ADV7511_REG_CEC_RX_FRAME_LEN[] = {24	ADV7511_REG_CEC_RX1_FRAME_LEN,25	ADV7511_REG_CEC_RX2_FRAME_LEN,26	ADV7511_REG_CEC_RX3_FRAME_LEN,27};28 29#define ADV7511_INT1_CEC_MASK \30	(ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \31	 ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1 | \32	 ADV7511_INT1_CEC_RX_READY2 | ADV7511_INT1_CEC_RX_READY3)33 34static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)35{36	unsigned int offset = adv7511->info->reg_cec_offset;37	unsigned int val;38 39	if (regmap_read(adv7511->regmap_cec,40			ADV7511_REG_CEC_TX_ENABLE + offset, &val))41		return;42 43	if ((val & 0x01) == 0)44		return;45 46	if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) {47		cec_transmit_attempt_done(adv7511->cec_adap,48					  CEC_TX_STATUS_ARB_LOST);49		return;50	}51	if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) {52		u8 status;53		u8 err_cnt = 0;54		u8 nack_cnt = 0;55		u8 low_drive_cnt = 0;56		unsigned int cnt;57 58		/*59		 * We set this status bit since this hardware performs60		 * retransmissions.61		 */62		status = CEC_TX_STATUS_MAX_RETRIES;63		if (regmap_read(adv7511->regmap_cec,64			    ADV7511_REG_CEC_TX_LOW_DRV_CNT + offset, &cnt)) {65			err_cnt = 1;66			status |= CEC_TX_STATUS_ERROR;67		} else {68			nack_cnt = cnt & 0xf;69			if (nack_cnt)70				status |= CEC_TX_STATUS_NACK;71			low_drive_cnt = cnt >> 4;72			if (low_drive_cnt)73				status |= CEC_TX_STATUS_LOW_DRIVE;74		}75		cec_transmit_done(adv7511->cec_adap, status,76				  0, nack_cnt, low_drive_cnt, err_cnt);77		return;78	}79	if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) {80		cec_transmit_attempt_done(adv7511->cec_adap, CEC_TX_STATUS_OK);81		return;82	}83}84 85static void adv7511_cec_rx(struct adv7511 *adv7511, int rx_buf)86{87	unsigned int offset = adv7511->info->reg_cec_offset;88	struct cec_msg msg = {};89	unsigned int len;90	unsigned int val;91	u8 i;92 93	if (regmap_read(adv7511->regmap_cec,94			ADV7511_REG_CEC_RX_FRAME_LEN[rx_buf] + offset, &len))95		return;96 97	msg.len = len & 0x1f;98 99	if (msg.len > 16)100		msg.len = 16;101 102	if (!msg.len)103		return;104 105	for (i = 0; i < msg.len; i++) {106		regmap_read(adv7511->regmap_cec,107			    i + ADV7511_REG_CEC_RX_FRAME_HDR[rx_buf] + offset,108			    &val);109		msg.msg[i] = val;110	}111 112	/* Toggle RX Ready Clear bit to re-enable this RX buffer */113	regmap_update_bits(adv7511->regmap_cec,114			   ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf),115			   BIT(rx_buf));116	regmap_update_bits(adv7511->regmap_cec,117			   ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf), 0);118 119	cec_received_msg(adv7511->cec_adap, &msg);120}121 122int adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)123{124	unsigned int offset = adv7511->info->reg_cec_offset;125	const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |126				ADV7511_INT1_CEC_TX_ARBIT_LOST |127				ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;128	const u32 irq_rx_mask = ADV7511_INT1_CEC_RX_READY1 |129				ADV7511_INT1_CEC_RX_READY2 |130				ADV7511_INT1_CEC_RX_READY3;131	unsigned int rx_status;132	int rx_order[3] = { -1, -1, -1 };133	int i;134	int irq_status = IRQ_NONE;135 136	if (irq1 & irq_tx_mask) {137		adv_cec_tx_raw_status(adv7511, irq1);138		irq_status = IRQ_HANDLED;139	}140 141	if (!(irq1 & irq_rx_mask))142		return irq_status;143 144	if (regmap_read(adv7511->regmap_cec,145			ADV7511_REG_CEC_RX_STATUS + offset, &rx_status))146		return irq_status;147 148	/*149	 * ADV7511_REG_CEC_RX_STATUS[5:0] contains the reception order of RX150	 * buffers 0, 1, and 2 in bits [1:0], [3:2], and [5:4] respectively.151	 * The values are to be interpreted as follows:152	 *153	 *   0 = buffer unused154	 *   1 = buffer contains oldest received frame (if applicable)155	 *   2 = buffer contains second oldest received frame (if applicable)156	 *   3 = buffer contains third oldest received frame (if applicable)157	 *158	 * Fill rx_order with the sequence of RX buffer indices to159	 * read from in order, where -1 indicates that there are no160	 * more buffers to process.161	 */162	for (i = 0; i < 3; i++) {163		unsigned int timestamp = (rx_status >> (2 * i)) & 0x3;164 165		if (timestamp)166			rx_order[timestamp - 1] = i;167	}168 169	/* Read CEC RX buffers in the appropriate order as prescribed above */170	for (i = 0; i < 3; i++) {171		int rx_buf = rx_order[i];172 173		if (rx_buf < 0)174			break;175 176		adv7511_cec_rx(adv7511, rx_buf);177	}178 179	return IRQ_HANDLED;180}181 182static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)183{184	struct adv7511 *adv7511 = cec_get_drvdata(adap);185	unsigned int offset = adv7511->info->reg_cec_offset;186 187	if (adv7511->i2c_cec == NULL)188		return -EIO;189 190	if (!adv7511->cec_enabled_adap && enable) {191		/* power up cec section */192		regmap_update_bits(adv7511->regmap_cec,193				   ADV7511_REG_CEC_CLK_DIV + offset,194				   0x03, 0x01);195		/* non-legacy mode and clear all rx buffers */196		regmap_write(adv7511->regmap_cec,197			     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x0f);198		regmap_write(adv7511->regmap_cec,199			     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);200		/* initially disable tx */201		regmap_update_bits(adv7511->regmap_cec,202				   ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);203		/* enabled irqs: */204		/* tx: ready */205		/* tx: arbitration lost */206		/* tx: retry timeout */207		/* rx: ready 1-3 */208		regmap_update_bits(adv7511->regmap,209				   ADV7511_REG_INT_ENABLE(1), 0x3f,210				   ADV7511_INT1_CEC_MASK);211	} else if (adv7511->cec_enabled_adap && !enable) {212		regmap_update_bits(adv7511->regmap,213				   ADV7511_REG_INT_ENABLE(1), 0x3f, 0);214		/* disable address mask 1-3 */215		regmap_update_bits(adv7511->regmap_cec,216				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,217				   0x70, 0x00);218		/* power down cec section */219		regmap_update_bits(adv7511->regmap_cec,220				   ADV7511_REG_CEC_CLK_DIV + offset,221				   0x03, 0x00);222		adv7511->cec_valid_addrs = 0;223	}224	adv7511->cec_enabled_adap = enable;225	return 0;226}227 228static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)229{230	struct adv7511 *adv7511 = cec_get_drvdata(adap);231	unsigned int offset = adv7511->info->reg_cec_offset;232	unsigned int i, free_idx = ADV7511_MAX_ADDRS;233 234	if (!adv7511->cec_enabled_adap)235		return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;236 237	if (addr == CEC_LOG_ADDR_INVALID) {238		regmap_update_bits(adv7511->regmap_cec,239				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,240				   0x70, 0);241		adv7511->cec_valid_addrs = 0;242		return 0;243	}244 245	for (i = 0; i < ADV7511_MAX_ADDRS; i++) {246		bool is_valid = adv7511->cec_valid_addrs & (1 << i);247 248		if (free_idx == ADV7511_MAX_ADDRS && !is_valid)249			free_idx = i;250		if (is_valid && adv7511->cec_addr[i] == addr)251			return 0;252	}253	if (i == ADV7511_MAX_ADDRS) {254		i = free_idx;255		if (i == ADV7511_MAX_ADDRS)256			return -ENXIO;257	}258	adv7511->cec_addr[i] = addr;259	adv7511->cec_valid_addrs |= 1 << i;260 261	switch (i) {262	case 0:263		/* enable address mask 0 */264		regmap_update_bits(adv7511->regmap_cec,265				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,266				   0x10, 0x10);267		/* set address for mask 0 */268		regmap_update_bits(adv7511->regmap_cec,269				   ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,270				   0x0f, addr);271		break;272	case 1:273		/* enable address mask 1 */274		regmap_update_bits(adv7511->regmap_cec,275				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,276				   0x20, 0x20);277		/* set address for mask 1 */278		regmap_update_bits(adv7511->regmap_cec,279				   ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,280				   0xf0, addr << 4);281		break;282	case 2:283		/* enable address mask 2 */284		regmap_update_bits(adv7511->regmap_cec,285				   ADV7511_REG_CEC_LOG_ADDR_MASK + offset,286				   0x40, 0x40);287		/* set address for mask 1 */288		regmap_update_bits(adv7511->regmap_cec,289				   ADV7511_REG_CEC_LOG_ADDR_2 + offset,290				   0x0f, addr);291		break;292	}293	return 0;294}295 296static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,297				     u32 signal_free_time, struct cec_msg *msg)298{299	struct adv7511 *adv7511 = cec_get_drvdata(adap);300	unsigned int offset = adv7511->info->reg_cec_offset;301	u8 len = msg->len;302	unsigned int i;303 304	/*305	 * The number of retries is the number of attempts - 1, but retry306	 * at least once. It's not clear if a value of 0 is allowed, so307	 * let's do at least one retry.308	 */309	regmap_update_bits(adv7511->regmap_cec,310			   ADV7511_REG_CEC_TX_RETRY + offset,311			   0x70, max(1, attempts - 1) << 4);312 313	/* blocking, clear cec tx irq status */314	regmap_update_bits(adv7511->regmap, ADV7511_REG_INT(1), 0x38, 0x38);315 316	/* write data */317	for (i = 0; i < len; i++)318		regmap_write(adv7511->regmap_cec,319			     i + ADV7511_REG_CEC_TX_FRAME_HDR + offset,320			     msg->msg[i]);321 322	/* set length (data + header) */323	regmap_write(adv7511->regmap_cec,324		     ADV7511_REG_CEC_TX_FRAME_LEN + offset, len);325	/* start transmit, enable tx */326	regmap_write(adv7511->regmap_cec,327		     ADV7511_REG_CEC_TX_ENABLE + offset, 0x01);328	return 0;329}330 331static const struct cec_adap_ops adv7511_cec_adap_ops = {332	.adap_enable = adv7511_cec_adap_enable,333	.adap_log_addr = adv7511_cec_adap_log_addr,334	.adap_transmit = adv7511_cec_adap_transmit,335};336 337static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)338{339	adv7511->cec_clk = devm_clk_get(dev, "cec");340	if (IS_ERR(adv7511->cec_clk)) {341		int ret = PTR_ERR(adv7511->cec_clk);342 343		adv7511->cec_clk = NULL;344		return ret;345	}346	clk_prepare_enable(adv7511->cec_clk);347	adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);348	return 0;349}350 351int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)352{353	unsigned int offset = adv7511->info->reg_cec_offset;354	int ret = adv7511_cec_parse_dt(dev, adv7511);355 356	if (ret)357		goto err_cec_parse_dt;358 359	adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,360		adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);361	if (IS_ERR(adv7511->cec_adap)) {362		ret = PTR_ERR(adv7511->cec_adap);363		goto err_cec_alloc;364	}365 366	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, 0);367	/* cec soft reset */368	regmap_write(adv7511->regmap_cec,369		     ADV7511_REG_CEC_SOFT_RESET + offset, 0x01);370	regmap_write(adv7511->regmap_cec,371		     ADV7511_REG_CEC_SOFT_RESET + offset, 0x00);372 373	/* non-legacy mode - use all three RX buffers */374	regmap_write(adv7511->regmap_cec,375		     ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);376 377	regmap_write(adv7511->regmap_cec,378		     ADV7511_REG_CEC_CLK_DIV + offset,379		     ((adv7511->cec_clk_freq / 750000) - 1) << 2);380 381	ret = cec_register_adapter(adv7511->cec_adap, dev);382	if (ret)383		goto err_cec_register;384	return 0;385 386err_cec_register:387	cec_delete_adapter(adv7511->cec_adap);388	adv7511->cec_adap = NULL;389err_cec_alloc:390	dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",391		 ret);392err_cec_parse_dt:393	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,394		     ADV7511_CEC_CTRL_POWER_DOWN);395	return ret == -EPROBE_DEFER ? ret : 0;396}397