Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1233c7c4 authored by Venkata Prahlad Valluru's avatar Venkata Prahlad Valluru
Browse files

fbdev: msm: hdmi: read CEC msg before clearing interrupt



Read CEC msg in ISR itself and then trigger work queue.

Change-Id: Ib40e544849e3b3338a412b9fa5ba737bfc13dad9
Signed-off-by: default avatarVenkata Prahlad Valluru <vvalluru@codeaurora.org>
parent 9346632c
Loading
Loading
Loading
Loading
+46 −31
Original line number Diff line number Diff line
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2017, 2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,7 @@ struct hdmi_cec_ctrl {
	bool cec_device_suspend;

	u32 cec_msg_wr_status;
	struct cec_msg recv_msg;
	spinlock_t lock;
	struct work_struct cec_read_work;
	struct completion cec_msg_wr_done;
@@ -164,65 +165,75 @@ static void hdmi_cec_deinit_input_event(struct hdmi_cec_ctrl *cec_ctrl)
	cec_ctrl->input = NULL;
}

static void hdmi_cec_msg_recv(struct work_struct *work)
static int hdmi_cec_msg_read(struct hdmi_cec_ctrl *cec_ctrl)
{
	int i;
	u32 data;
	struct hdmi_cec_ctrl *cec_ctrl = NULL;
	struct dss_io_data *io = NULL;
	struct cec_msg msg;
	struct cec_cbs *cbs;
	struct cec_msg *msg;
	u32 data;
	int i;

	cec_ctrl = container_of(work, struct hdmi_cec_ctrl, cec_read_work);
	if (!cec_ctrl || !cec_ctrl->init_data.io) {
		DEV_ERR("%s: invalid input\n", __func__);
		return;
		return -EINVAL;
	}

	if (!cec_ctrl->cec_enabled) {
		DEV_ERR("%s: cec not enabled\n", __func__);
		return;
		return -ENODEV;
	}

	msg = &cec_ctrl->recv_msg;
	io = cec_ctrl->init_data.io;
	cbs = cec_ctrl->init_data.cbs;

	data = DSS_REG_R(io, HDMI_CEC_RD_DATA);

	msg.recvr_id   = (data & 0x000F);
	msg.sender_id  = (data & 0x00F0) >> 4;
	msg.frame_size = (data & 0x1F00) >> 8;
	DEV_DBG("%s: Recvd init=[%u] dest=[%u] size=[%u]\n", __func__,
		msg.sender_id, msg.recvr_id,
		msg.frame_size);

	if (msg.frame_size < 1 || msg.frame_size > MAX_CEC_FRAME_SIZE) {
	msg->recvr_id   = (data & 0x000F);
	msg->sender_id  = (data & 0x00F0) >> 4;
	msg->frame_size = (data & 0x1F00) >> 8;
	if (msg->frame_size < 1 || msg->frame_size > MAX_CEC_FRAME_SIZE) {
		DEV_ERR("%s: invalid message (frame length = %d)\n",
			__func__, msg.frame_size);
		return;
	} else if (msg.frame_size == 1) {
			__func__, msg->frame_size);
		return -EINVAL;
	} else if (msg->frame_size == 1) {
		DEV_DBG("%s: polling message (dest[%x] <- init[%x])\n",
			__func__, msg.recvr_id, msg.sender_id);
		return;
			__func__, msg->recvr_id, msg->sender_id);
		return -EINVAL;
	}

	/* data block 0 : opcode */
	data = DSS_REG_R_ND(io, HDMI_CEC_RD_DATA);
	msg.opcode = data & 0xFF;
	msg->opcode = data & 0xFF;

	/* data block 1-14 : operand 0-13 */
	for (i = 0; i < msg.frame_size - 2; i++) {
	for (i = 0; i < msg->frame_size - 2; i++) {
		data = DSS_REG_R_ND(io, HDMI_CEC_RD_DATA);
		msg.operand[i] = data & 0xFF;
		msg->operand[i] = data & 0xFF;
	}

	for (; i < MAX_OPERAND_SIZE; i++)
		msg.operand[i] = 0;
		msg->operand[i] = 0;

	DEV_DBG("%s: opcode 0x%x, wakup_en %d, device_suspend %d\n", __func__,
		msg.opcode, cec_ctrl->cec_wakeup_en,
		msg->opcode, cec_ctrl->cec_wakeup_en,
		cec_ctrl->cec_device_suspend);

	return 0;
}

static void hdmi_cec_msg_recv(struct work_struct *work)
{
	struct hdmi_cec_ctrl *cec_ctrl = NULL;
	struct cec_msg msg;
	struct cec_cbs *cbs;

	cec_ctrl = container_of(work, struct hdmi_cec_ctrl, cec_read_work);
	if (!cec_ctrl || !cec_ctrl->init_data.io) {
		DEV_ERR("%s: invalid input\n", __func__);
		return;
	}

	cbs = cec_ctrl->init_data.cbs;
	memcpy(&msg, &cec_ctrl->recv_msg, sizeof(msg));

	if ((msg.opcode == CEC_OP_SET_STREAM_PATH ||
		msg.opcode == CEC_OP_KEY_PRESS) &&
		cec_ctrl->input && cec_ctrl->cec_wakeup_en &&
@@ -308,8 +319,12 @@ int hdmi_cec_isr(void *input)
	if ((cec_intr & BIT(6)) && (cec_intr & BIT(7))) {
		DEV_DBG("%s: CEC_IRQ_FRAME_RD_DONE\n", __func__);

		rc = hdmi_cec_msg_read(cec_ctrl);
		if (!rc)
			queue_work(cec_ctrl->init_data.workq,
					&cec_ctrl->cec_read_work);

		DSS_REG_W(io, HDMI_CEC_INT, cec_intr | BIT(6));
		queue_work(cec_ctrl->init_data.workq, &cec_ctrl->cec_read_work);
	}

	return rc;