drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c

Source file repositories/reference/linux-study-clean/drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c

File Facts

System
Linux kernel
Corpus path
drivers/media/platform/synopsys/hdmirx/snps_hdmirx_cec.c
Extension
.c
Size
6678 bytes
Lines
276
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
 *
 * Author: Shunqing Chen <csq@rock-chips.com>
 */

#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#include <media/cec.h>

#include "snps_hdmirx.h"
#include "snps_hdmirx_cec.h"

static void hdmirx_cec_write(struct hdmirx_cec *cec, int reg, u32 val)
{
	cec->ops->write(cec->hdmirx, reg, val);
}

static u32 hdmirx_cec_read(struct hdmirx_cec *cec, int reg)
{
	return cec->ops->read(cec->hdmirx, reg);
}

static void hdmirx_cec_update_bits(struct hdmirx_cec *cec, int reg, u32 mask,
				   u32 data)
{
	u32 val = hdmirx_cec_read(cec, reg) & ~mask;

	val |= (data & mask);
	hdmirx_cec_write(cec, reg, val);
}

static int hdmirx_cec_log_addr(struct cec_adapter *adap, u8 logical_addr)
{
	struct hdmirx_cec *cec = cec_get_drvdata(adap);

	if (logical_addr == CEC_LOG_ADDR_INVALID)
		cec->addresses = 0;
	else
		cec->addresses |= BIT(logical_addr) | BIT(15);

	hdmirx_cec_write(cec, CEC_ADDR, cec->addresses);

	return 0;
}

/* signal_free_time is handled by the Synopsys Designware
 * HDMIRX Controller hardware.
 */
static int hdmirx_cec_transmit(struct cec_adapter *adap, u8 attempts,
			       u32 signal_free_time, struct cec_msg *msg)
{
	struct hdmirx_cec *cec = cec_get_drvdata(adap);
	u32 data[4] = {0};
	int i, data_len, msg_len;

	msg_len = msg->len;

	hdmirx_cec_write(cec, CEC_TX_COUNT, msg_len - 1);
	for (i = 0; i < msg_len; i++)
		data[i / 4] |= msg->msg[i] << (i % 4) * 8;

	data_len = DIV_ROUND_UP(msg_len, 4);

	for (i = 0; i < data_len; i++)
		hdmirx_cec_write(cec, CEC_TX_DATA3_0 + i * 4, data[i]);

	hdmirx_cec_write(cec, CEC_TX_CONTROL, 0x1);

	return 0;
}

static irqreturn_t hdmirx_cec_hardirq(int irq, void *data)
{
	struct cec_adapter *adap = data;
	struct hdmirx_cec *cec = cec_get_drvdata(adap);
	u32 stat = hdmirx_cec_read(cec, CEC_INT_STATUS);
	irqreturn_t ret = IRQ_HANDLED;
	u32 val;

	if (!stat)
		return IRQ_NONE;

	hdmirx_cec_write(cec, CEC_INT_CLEAR, stat);

Annotation

Implementation Notes