linux-cuboxi: update to linux-cuboxi-27bb585

Signed-off-by: Stephan Raue <stephan@openelec.tv>
This commit is contained in:
Stephan Raue 2014-07-11 05:25:37 +02:00
parent 12fda0ebcb
commit 42225b4a83
3 changed files with 1 additions and 808 deletions

View File

@ -19,7 +19,7 @@
PKG_NAME="linux"
case "$LINUX" in
imx6)
PKG_VERSION="cuboxi-592b2d9"
PKG_VERSION="cuboxi-27bb585"
PKG_URL="$DISTRO_SRC/$PKG_NAME-$PKG_VERSION.tar.xz"
;;
*)

View File

@ -1,731 +0,0 @@
From 74fc2e85c080b0ddc2a4b2565eda97c55300303d Mon Sep 17 00:00:00 2001
From: wolfgar <stephan.rafin@laposte.net>
Date: Sat, 26 Apr 2014 16:50:32 +0200
Subject: [PATCH] Merge all CEC driver changes to 3.10 This commit pushes all
changes I did in the 3.0.35 kernel to improve/fix its behavior with libcec
port for imx6
It also fixes CEC clock handling in case of FB mode change event
and of HDMI cable disconnection
---
drivers/mxc/hdmi-cec/mxc_hdmi-cec.c | 327 +++++++++++++++---------------------
drivers/video/mxc/mxc_hdmi.c | 14 +-
2 files changed, 147 insertions(+), 194 deletions(-)
diff --git a/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c b/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
index d0113ee..3a8aff4 100644
--- a/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
+++ b/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
@@ -55,6 +55,8 @@
#define MESSAGE_TYPE_CONNECTED 4
#define MESSAGE_TYPE_SEND_SUCCESS 5
+#define CEC_TX_INPROGRESS -1
+#define CEC_TX_AVAIL 0
struct hdmi_cec_priv {
int receive_error;
@@ -63,7 +65,9 @@ struct hdmi_cec_priv {
bool cec_state;
u8 last_msg[MAX_MESSAGE_LEN];
u8 msg_len;
- u8 latest_cec_stat;
+ int tx_answer;
+ u16 latest_cec_stat;
+ u8 link_status;
spinlock_t irq_lock;
struct delayed_work hdmi_cec_work;
struct mutex lock;
@@ -76,6 +80,7 @@ struct hdmi_cec_event {
struct list_head list;
};
+
static LIST_HEAD(head);
static int hdmi_cec_major;
@@ -84,11 +89,14 @@ static struct hdmi_cec_priv hdmi_cec_data;
static u8 open_count;
static wait_queue_head_t hdmi_cec_queue;
+static wait_queue_head_t tx_cec_queue;
+
static irqreturn_t mxc_hdmi_cec_isr(int irq, void *data)
{
struct hdmi_cec_priv *hdmi_cec = data;
- u8 cec_stat = 0;
+ u16 cec_stat = 0;
unsigned long flags;
+ u8 phy_stat0;
spin_lock_irqsave(&hdmi_cec->irq_lock, flags);
@@ -96,16 +104,24 @@ static irqreturn_t mxc_hdmi_cec_isr(int irq, void *data)
cec_stat = hdmi_readb(HDMI_IH_CEC_STAT0);
hdmi_writeb(cec_stat, HDMI_IH_CEC_STAT0);
-
+ phy_stat0 = hdmi_readb(HDMI_PHY_STAT0) & 0x02;
+ if (hdmi_cec->link_status ^ phy_stat0) {
+ /* HPD value changed */
+ hdmi_cec->link_status = phy_stat0;
+ if (hdmi_cec->link_status)
+ cec_stat |= 0x80; /* Connected */
+ else
+ cec_stat |= 0x100; /* Disconnected */
+ }
if ((cec_stat & (HDMI_IH_CEC_STAT0_ERROR_INIT | \
HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | \
- HDMI_IH_CEC_STAT0_DONE)) == 0) {
+ HDMI_IH_CEC_STAT0_DONE | 0x180)) == 0) {
spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
return IRQ_HANDLED;
}
-
pr_debug("HDMI CEC interrupt received\n");
- hdmi_cec->latest_cec_stat = cec_stat;
+ /* FIXME : there is a race with latest_cec_stat */
+ hdmi_cec->latest_cec_stat = cec_stat ;
schedule_delayed_work(&(hdmi_cec->hdmi_cec_work), msecs_to_jiffies(20));
@@ -118,115 +134,70 @@ void mxc_hdmi_cec_handle(u16 cec_stat)
{
u8 val = 0, i = 0;
struct hdmi_cec_event *event = NULL;
-
- /* The current transmission is successful (for initiator only). */
+ /*The current transmission is successful (for initiator only).*/
if (!open_count)
return;
if (cec_stat & HDMI_IH_CEC_STAT0_DONE) {
-
- event = vmalloc(sizeof(struct hdmi_cec_event));
- if (NULL == event) {
- pr_err("%s: Not enough memory!\n", __func__);
- return;
- }
-
- memset(event, 0, sizeof(struct hdmi_cec_event));
- event->event_type = MESSAGE_TYPE_SEND_SUCCESS;
-
- mutex_lock(&hdmi_cec_data.lock);
- list_add_tail(&event->list, &head);
- mutex_unlock(&hdmi_cec_data.lock);
-
- wake_up(&hdmi_cec_queue);
+ hdmi_cec_data.tx_answer = cec_stat;
+ wake_up(&tx_cec_queue);
}
-
- /* EOM is detected so that the received data is ready
- * in the receiver data buffer
- */
+ /*EOM is detected so that the received data is ready in the receiver data buffer*/
if (cec_stat & HDMI_IH_CEC_STAT0_EOM) {
-
hdmi_writeb(0x02, HDMI_IH_CEC_STAT0);
-
event = vmalloc(sizeof(struct hdmi_cec_event));
if (NULL == event) {
pr_err("%s: Not enough memory!\n", __func__);
return;
}
memset(event, 0, sizeof(struct hdmi_cec_event));
-
event->msg_len = hdmi_readb(HDMI_CEC_RX_CNT);
if (!event->msg_len) {
pr_err("%s: Invalid CEC message length!\n", __func__);
return;
}
event->event_type = MESSAGE_TYPE_RECEIVE_SUCCESS;
-
for (i = 0; i < event->msg_len; i++)
event->msg[i] = hdmi_readb(HDMI_CEC_RX_DATA0+i);
hdmi_writeb(0x0, HDMI_CEC_LOCK);
-
mutex_lock(&hdmi_cec_data.lock);
list_add_tail(&event->list, &head);
mutex_unlock(&hdmi_cec_data.lock);
-
wake_up(&hdmi_cec_queue);
}
-
- /* An error is detected on cec line (for initiator only). */
+ /*An error is detected on cec line (for initiator only). */
if (cec_stat & HDMI_IH_CEC_STAT0_ERROR_INIT) {
-
mutex_lock(&hdmi_cec_data.lock);
hdmi_cec_data.send_error++;
- if (hdmi_cec_data.send_error > 5) {
- pr_err("%s:Re-transmission is attempted more than 5 times!\n",
- __func__);
+ if (hdmi_cec_data.send_error > 2) {
+ pr_err("%s:Re-transmission is attempted more than 2 times!\n", __func__);
hdmi_cec_data.send_error = 0;
mutex_unlock(&hdmi_cec_data.lock);
+ hdmi_cec_data.tx_answer = cec_stat;
+ wake_up(&tx_cec_queue);
return;
}
-
- for (i = 0; i < hdmi_cec_data.msg_len; i++) {
- hdmi_writeb(hdmi_cec_data.last_msg[i],
- HDMI_CEC_TX_DATA0 + i);
- }
+ for (i = 0; i < hdmi_cec_data.msg_len; i++)
+ hdmi_writeb(hdmi_cec_data.last_msg[i], HDMI_CEC_TX_DATA0+i);
hdmi_writeb(hdmi_cec_data.msg_len, HDMI_CEC_TX_CNT);
-
val = hdmi_readb(HDMI_CEC_CTRL);
val |= 0x01;
hdmi_writeb(val, HDMI_CEC_CTRL);
mutex_unlock(&hdmi_cec_data.lock);
}
-
- /* A frame is not acknowledged in a directly addressed message.
- * Or a frame is negatively acknowledged in
- * a broadcast message (for initiator only).
- */
+ /*A frame is not acknowledged in a directly addressed message. Or a frame is negatively acknowledged in
+ a broadcast message (for initiator only).*/
if (cec_stat & HDMI_IH_CEC_STAT0_NACK) {
- event = vmalloc(sizeof(struct hdmi_cec_event));
- if (NULL == event) {
- pr_err("%s: Not enough memory\n", __func__);
- return;
- }
- memset(event, 0, sizeof(struct hdmi_cec_event));
- event->event_type = MESSAGE_TYPE_NOACK;
-
- mutex_lock(&hdmi_cec_data.lock);
- list_add_tail(&event->list, &head);
- mutex_unlock(&hdmi_cec_data.lock);
-
- wake_up(&hdmi_cec_queue);
+ hdmi_cec_data.tx_answer = cec_stat;
+ wake_up(&tx_cec_queue);
}
-
- /* An error is notified by a follower.
- * Abnormal logic data bit error (for follower).
- */
+ /*An error is notified by a follower. Abnormal logic data bit error (for follower).*/
if (cec_stat & HDMI_IH_CEC_STAT0_ERROR_FOLL) {
hdmi_cec_data.receive_error++;
}
-
- /* HDMI cable connected */
+ /*HDMI cable connected*/
if (cec_stat & 0x80) {
+ pr_info("HDMI link connected\n");
event = vmalloc(sizeof(struct hdmi_cec_event));
if (NULL == event) {
pr_err("%s: Not enough memory\n", __func__);
@@ -234,16 +205,14 @@ void mxc_hdmi_cec_handle(u16 cec_stat)
}
memset(event, 0, sizeof(struct hdmi_cec_event));
event->event_type = MESSAGE_TYPE_CONNECTED;
-
mutex_lock(&hdmi_cec_data.lock);
list_add_tail(&event->list, &head);
mutex_unlock(&hdmi_cec_data.lock);
-
wake_up(&hdmi_cec_queue);
}
-
- /* HDMI cable disconnected */
+ /*HDMI cable disconnected*/
if (cec_stat & 0x100) {
+ pr_info("HDMI link disconnected\n");
event = vmalloc(sizeof(struct hdmi_cec_event));
if (NULL == event) {
pr_err("%s: Not enough memory!\n", __func__);
@@ -251,30 +220,24 @@ void mxc_hdmi_cec_handle(u16 cec_stat)
}
memset(event, 0, sizeof(struct hdmi_cec_event));
event->event_type = MESSAGE_TYPE_DISCONNECTED;
-
mutex_lock(&hdmi_cec_data.lock);
list_add_tail(&event->list, &head);
mutex_unlock(&hdmi_cec_data.lock);
-
wake_up(&hdmi_cec_queue);
}
-
return;
}
EXPORT_SYMBOL(mxc_hdmi_cec_handle);
-
static void mxc_hdmi_cec_worker(struct work_struct *work)
{
u8 val;
-
mxc_hdmi_cec_handle(hdmi_cec_data.latest_cec_stat);
- val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
- HDMI_IH_CEC_STAT0_ARB_LOST;
+ val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL | HDMI_IH_CEC_STAT0_ARB_LOST;
hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
}
/*!
- * @brief open function for vpu file operation
+ * @brief open function for cec file operation
*
* @return 0 on success or negative error code on error
*/
@@ -285,13 +248,11 @@ static int hdmi_cec_open(struct inode *inode, struct file *filp)
mutex_unlock(&hdmi_cec_data.lock);
return -EBUSY;
}
-
open_count = 1;
filp->private_data = (void *)(&hdmi_cec_data);
hdmi_cec_data.Logical_address = 15;
hdmi_cec_data.cec_state = false;
mutex_unlock(&hdmi_cec_data.lock);
-
return 0;
}
@@ -299,36 +260,40 @@ static ssize_t hdmi_cec_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct hdmi_cec_event *event = NULL;
-
pr_debug("function : %s\n", __func__);
+
if (!open_count)
return -ENODEV;
-
mutex_lock(&hdmi_cec_data.lock);
if (false == hdmi_cec_data.cec_state) {
mutex_unlock(&hdmi_cec_data.lock);
return -EACCES;
}
- mutex_unlock(&hdmi_cec_data.lock);
- /* delete from list */
- mutex_lock(&hdmi_cec_data.lock);
if (list_empty(&head)) {
- mutex_unlock(&hdmi_cec_data.lock);
- return -EACCES;
+ if (file->f_flags & O_NONBLOCK) {
+ mutex_unlock(&hdmi_cec_data.lock);
+ return -EAGAIN;
+ } else {
+ do {
+ mutex_unlock(&hdmi_cec_data.lock);
+ if (wait_event_interruptible(hdmi_cec_queue, (!list_empty(&head))))
+ return -ERESTARTSYS;
+ mutex_lock(&hdmi_cec_data.lock);
+ } while (list_empty(&head));
+ }
}
+
event = list_first_entry(&head, struct hdmi_cec_event, list);
list_del(&event->list);
mutex_unlock(&hdmi_cec_data.lock);
-
if (copy_to_user(buf, event,
- sizeof(struct hdmi_cec_event) - sizeof(struct list_head))) {
+ sizeof(struct hdmi_cec_event) - sizeof(struct list_head))) {
vfree(event);
return -EFAULT;
}
vfree(event);
-
- return sizeof(struct hdmi_cec_event);
+ return (sizeof(struct hdmi_cec_event) - sizeof(struct list_head));
}
static ssize_t hdmi_cec_write(struct file *file, const char __user *buf,
@@ -339,58 +304,77 @@ static ssize_t hdmi_cec_write(struct file *file, const char __user *buf,
u8 msg_len = 0, val = 0;
pr_debug("function : %s\n", __func__);
+
if (!open_count)
return -ENODEV;
-
mutex_lock(&hdmi_cec_data.lock);
if (false == hdmi_cec_data.cec_state) {
mutex_unlock(&hdmi_cec_data.lock);
return -EACCES;
}
+ /* Ensure that there is only one writer who is the only listener of tx_cec_queue */
+ if (hdmi_cec_data.tx_answer != CEC_TX_AVAIL) {
+ mutex_unlock(&hdmi_cec_data.lock);
+ return -EBUSY;
+ }
mutex_unlock(&hdmi_cec_data.lock);
-
if (count > MAX_MESSAGE_LEN)
return -EINVAL;
-
- mutex_lock(&hdmi_cec_data.lock);
- hdmi_cec_data.send_error = 0;
memset(&msg, 0, MAX_MESSAGE_LEN);
ret = copy_from_user(&msg, buf, count);
- if (ret) {
- ret = -EACCES;
- goto end;
- }
-
+ if (ret)
+ return -EACCES;
+ mutex_lock(&hdmi_cec_data.lock);
+ hdmi_cec_data.send_error = 0;
+ hdmi_cec_data.tx_answer = CEC_TX_INPROGRESS;
msg_len = count;
hdmi_writeb(msg_len, HDMI_CEC_TX_CNT);
- for (i = 0; i < msg_len; i++) {
+ for (i = 0; i < msg_len; i++)
hdmi_writeb(msg[i], HDMI_CEC_TX_DATA0+i);
- }
-
val = hdmi_readb(HDMI_CEC_CTRL);
val |= 0x01;
hdmi_writeb(val, HDMI_CEC_CTRL);
memcpy(hdmi_cec_data.last_msg, msg, msg_len);
hdmi_cec_data.msg_len = msg_len;
+ mutex_unlock(&hdmi_cec_data.lock);
- i = 0;
- val = hdmi_readb(HDMI_CEC_CTRL);
- while ((val & 0x01) == 0x1) {
- msleep(50);
- i++;
- if (i > 3) {
- ret = -EIO;
- goto end;
- }
- val = hdmi_readb(HDMI_CEC_CTRL);
+ ret = wait_event_interruptible_timeout(tx_cec_queue, hdmi_cec_data.tx_answer != CEC_TX_INPROGRESS, HZ);
+
+ if (ret < 0) {
+ ret = -ERESTARTSYS;
+ goto tx_out;
}
-end:
- mutex_unlock(&hdmi_cec_data.lock);
+ if (hdmi_cec_data.tx_answer & HDMI_IH_CEC_STAT0_DONE)
+ /* msg correctly sent */
+ ret = msg_len;
+ else
+ ret = -EIO;
+ tx_out:
+ hdmi_cec_data.tx_answer = CEC_TX_AVAIL;
return ret;
}
+
+static void hdmi_stop_device(void)
+{
+ u8 val;
+
+ hdmi_writeb(0x10, HDMI_CEC_CTRL);
+ val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL | HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_ARB_LOST | \
+ HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | HDMI_IH_CEC_STAT0_DONE;
+ hdmi_writeb(val, HDMI_CEC_MASK);
+ hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
+ hdmi_writeb(0x0, HDMI_CEC_POLARITY);
+ val = hdmi_readb(HDMI_MC_CLKDIS);
+ val |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ hdmi_writeb(val, HDMI_MC_CLKDIS);
+ mutex_lock(&hdmi_cec_data.lock);
+ hdmi_cec_data.cec_state = false;
+ mutex_unlock(&hdmi_cec_data.lock);
+}
+
/*!
* @brief IO ctrl function for vpu file operation
* @param cmd IO ctrl command
@@ -402,93 +386,59 @@ static long hdmi_cec_ioctl(struct file *filp, u_int cmd,
int ret = 0, status = 0;
u8 val = 0, msg = 0;
struct mxc_edid_cfg hdmi_edid_cfg;
-
pr_debug("function : %s\n", __func__);
if (!open_count)
return -ENODEV;
-
switch (cmd) {
case HDMICEC_IOC_SETLOGICALADDRESS:
mutex_lock(&hdmi_cec_data.lock);
if (false == hdmi_cec_data.cec_state) {
mutex_unlock(&hdmi_cec_data.lock);
+ pr_err("Trying to set logical address while not started\n");
return -EACCES;
}
-
hdmi_cec_data.Logical_address = (u8)arg;
-
if (hdmi_cec_data.Logical_address <= 7) {
val = 1 << hdmi_cec_data.Logical_address;
hdmi_writeb(val, HDMI_CEC_ADDR_L);
hdmi_writeb(0, HDMI_CEC_ADDR_H);
- } else if (hdmi_cec_data.Logical_address > 7 &&
- hdmi_cec_data.Logical_address <= 15) {
+ } else if (hdmi_cec_data.Logical_address > 7 && hdmi_cec_data.Logical_address <= 15) {
val = 1 << (hdmi_cec_data.Logical_address - 8);
hdmi_writeb(val, HDMI_CEC_ADDR_H);
hdmi_writeb(0, HDMI_CEC_ADDR_L);
- } else {
+ } else
ret = -EINVAL;
- }
-
- /* Send Polling message with same source
- * and destination address
- */
+ /*Send Polling message with same source and destination address*/
if (0 == ret && 15 != hdmi_cec_data.Logical_address) {
- msg = (hdmi_cec_data.Logical_address << 4) |
- hdmi_cec_data.Logical_address;
+ msg = (hdmi_cec_data.Logical_address << 4)|hdmi_cec_data.Logical_address;
hdmi_writeb(1, HDMI_CEC_TX_CNT);
hdmi_writeb(msg, HDMI_CEC_TX_DATA0);
-
val = hdmi_readb(HDMI_CEC_CTRL);
val |= 0x01;
hdmi_writeb(val, HDMI_CEC_CTRL);
}
-
mutex_unlock(&hdmi_cec_data.lock);
break;
-
case HDMICEC_IOC_STARTDEVICE:
val = hdmi_readb(HDMI_MC_CLKDIS);
val &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
hdmi_writeb(val, HDMI_MC_CLKDIS);
-
hdmi_writeb(0x02, HDMI_CEC_CTRL);
-
- val = HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_NACK |
- HDMI_IH_CEC_STAT0_EOM | HDMI_IH_CEC_STAT0_DONE;
+ /* Force read unlock */
+ hdmi_writeb(0x0, HDMI_CEC_LOCK);
+ val = HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | HDMI_IH_CEC_STAT0_DONE;
hdmi_writeb(val, HDMI_CEC_POLARITY);
-
- val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
- HDMI_IH_CEC_STAT0_ARB_LOST;
+ val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL | HDMI_IH_CEC_STAT0_ARB_LOST;
hdmi_writeb(val, HDMI_CEC_MASK);
hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
-
+ hdmi_cec_data.link_status = hdmi_readb(HDMI_PHY_STAT0) & 0x02;
mutex_lock(&hdmi_cec_data.lock);
hdmi_cec_data.cec_state = true;
mutex_unlock(&hdmi_cec_data.lock);
break;
-
case HDMICEC_IOC_STOPDEVICE:
- hdmi_writeb(0x10, HDMI_CEC_CTRL);
-
- val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
- HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_ARB_LOST |
- HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM |
- HDMI_IH_CEC_STAT0_DONE;
- hdmi_writeb(val, HDMI_CEC_MASK);
- hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
-
- hdmi_writeb(0x0, HDMI_CEC_POLARITY);
-
- val = hdmi_readb(HDMI_MC_CLKDIS);
- val |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
- hdmi_writeb(val, HDMI_MC_CLKDIS);
-
- mutex_lock(&hdmi_cec_data.lock);
- hdmi_cec_data.cec_state = false;
- mutex_unlock(&hdmi_cec_data.lock);
+ hdmi_stop_device();
break;
-
case HDMICEC_IOC_GETPHYADDRESS:
hdmi_get_edid_cfg(&hdmi_edid_cfg);
status = copy_to_user((void __user *)arg,
@@ -497,29 +447,25 @@ static long hdmi_cec_ioctl(struct file *filp, u_int cmd,
if (status)
ret = -EFAULT;
break;
-
default:
ret = -EINVAL;
break;
}
-
- return ret;
+ return ret;
}
/*!
-* @brief Release function for vpu file operation
-* @return 0 on success or negative error code on error
-*/
+ * @brief Release function for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
static int hdmi_cec_release(struct inode *inode, struct file *filp)
{
mutex_lock(&hdmi_cec_data.lock);
-
if (open_count) {
open_count = 0;
hdmi_cec_data.cec_state = false;
hdmi_cec_data.Logical_address = 15;
}
-
mutex_unlock(&hdmi_cec_data.lock);
return 0;
@@ -531,20 +477,18 @@ static unsigned int hdmi_cec_poll(struct file *file, poll_table *wait)
pr_debug("function : %s\n", __func__);
- if (!open_count)
- return -ENODEV;
-
- if (false == hdmi_cec_data.cec_state)
- return -EACCES;
-
poll_wait(file, &hdmi_cec_queue, wait);
+ /* Always writable */
+ mask = (POLLOUT | POLLWRNORM);
+ mutex_lock(&hdmi_cec_data.lock);
if (!list_empty(&head))
- mask |= (POLLIN | POLLRDNORM);
-
+ mask |= (POLLIN | POLLRDNORM);
+ mutex_unlock(&hdmi_cec_data.lock);
return mask;
}
+
const struct file_operations hdmi_cec_fops = {
.owner = THIS_MODULE,
.read = hdmi_cec_read,
@@ -563,20 +507,18 @@ static int hdmi_cec_dev_probe(struct platform_device *pdev)
struct pinctrl *pinctrl;
int irq = platform_get_irq(pdev, 0);
- hdmi_cec_major = register_chrdev(hdmi_cec_major,
- "mxc_hdmi_cec", &hdmi_cec_fops);
+ hdmi_cec_major = register_chrdev(hdmi_cec_major, "mxc_hdmi_cec", &hdmi_cec_fops);
if (hdmi_cec_major < 0) {
dev_err(&pdev->dev, "hdmi_cec: unable to get a major for HDMI CEC\n");
err = -EBUSY;
goto out;
}
-
+
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (unlikely(res == NULL)) {
dev_err(&pdev->dev, "hdmi_cec:No HDMI irq line provided\n");
goto err_out_chrdev;
}
-
spin_lock_init(&hdmi_cec_data.irq_lock);
err = devm_request_irq(&pdev->dev, irq, mxc_hdmi_cec_isr, IRQF_SHARED,
@@ -592,8 +534,8 @@ static int hdmi_cec_dev_probe(struct platform_device *pdev)
goto err_out_chrdev;
}
- temp_class = device_create(hdmi_cec_class, NULL,
- MKDEV(hdmi_cec_major, 0), NULL, "mxc_hdmi_cec");
+ temp_class = device_create(hdmi_cec_class, NULL, MKDEV(hdmi_cec_major, 0),
+ NULL, "mxc_hdmi_cec");
if (IS_ERR(temp_class)) {
err = PTR_ERR(temp_class);
goto err_out_class;
@@ -606,15 +548,14 @@ static int hdmi_cec_dev_probe(struct platform_device *pdev)
}
init_waitqueue_head(&hdmi_cec_queue);
+ init_waitqueue_head(&tx_cec_queue);
INIT_LIST_HEAD(&head);
mutex_init(&hdmi_cec_data.lock);
-
hdmi_cec_data.Logical_address = 15;
-
+ hdmi_cec_data.tx_answer = CEC_TX_AVAIL;
platform_set_drvdata(pdev, &hdmi_cec_data);
-
INIT_DELAYED_WORK(&hdmi_cec_data.hdmi_cec_work, mxc_hdmi_cec_worker);
dev_info(&pdev->dev, "HDMI CEC initialized\n");
@@ -631,12 +572,14 @@ static int hdmi_cec_dev_probe(struct platform_device *pdev)
static int hdmi_cec_dev_remove(struct platform_device *pdev)
{
+ if (hdmi_cec_data.cec_state)
+ hdmi_stop_device();
if (hdmi_cec_major > 0) {
device_destroy(hdmi_cec_class, MKDEV(hdmi_cec_major, 0));
class_destroy(hdmi_cec_class);
unregister_chrdev(hdmi_cec_major, "mxc_hdmi_cec");
hdmi_cec_major = 0;
- }
+}
return 0;
}
@@ -650,9 +593,9 @@ static struct platform_driver mxc_hdmi_cec_driver = {
.probe = hdmi_cec_dev_probe,
.remove = hdmi_cec_dev_remove,
.driver = {
- .name = "mxc_hdmi_cec",
+ .name = "mxc_hdmi_cec",
.of_match_table = imx_hdmi_cec_match,
- },
+ },
};
module_platform_driver(mxc_hdmi_cec_driver);
diff --git a/drivers/video/mxc/mxc_hdmi.c b/drivers/video/mxc/mxc_hdmi.c
index 20c6d70..88d62ce 100644
--- a/drivers/video/mxc/mxc_hdmi.c
+++ b/drivers/video/mxc/mxc_hdmi.c
@@ -1708,8 +1708,12 @@ static void mxc_hdmi_enable_video_path(struct mxc_hdmi *hdmi)
hdmi_writeb(0x16, HDMI_FC_CH1PREAM);
hdmi_writeb(0x21, HDMI_FC_CH2PREAM);
+ /* Save CEC clock */
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS) & HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ clkdis |= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
+
/* Enable pixel clock and tmds data path */
- clkdis = 0x7F;
+ clkdis = 0x7F & clkdis;
clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
@@ -1990,10 +1994,16 @@ static void mxc_hdmi_power_off(struct mxc_dispdrv_handle *disp)
static void mxc_hdmi_cable_disconnected(struct mxc_hdmi *hdmi)
{
+ u8 clkdis;
+
dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+ /* Save CEC clock */
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS) & HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ clkdis |= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
+
/* Disable All HDMI clock */
- hdmi_writeb(0xff, HDMI_MC_CLKDIS);
+ hdmi_writeb(0xff & clkdis, HDMI_MC_CLKDIS);
mxc_hdmi_phy_disable(hdmi);
--
1.9.1

View File

@ -1,76 +0,0 @@
From 76796e32b20dd8f34aadad8fd91672017d143812 Mon Sep 17 00:00:00 2001
From: wolfgar <stephan.rafin@laposte.net>
Date: Tue, 29 Apr 2014 01:35:01 +0200
Subject: [PATCH] Fix a bug that could result in CEC interrupts to be
improperly muted in case the CEC_STAT register was 0, the worker was not
invoked and as a consequence the interrupts were not unmuted Also try to play
better with the interrupt sharing with hmdi_video
---
drivers/mxc/hdmi-cec/mxc_hdmi-cec.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c b/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
index 3a8aff4..85e259c 100644
--- a/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
+++ b/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
@@ -97,6 +97,7 @@ static irqreturn_t mxc_hdmi_cec_isr(int irq, void *data)
u16 cec_stat = 0;
unsigned long flags;
u8 phy_stat0;
+ irqreturn_t ret = IRQ_HANDLED;
spin_lock_irqsave(&hdmi_cec->irq_lock, flags);
@@ -105,6 +106,13 @@ static irqreturn_t mxc_hdmi_cec_isr(int irq, void *data)
cec_stat = hdmi_readb(HDMI_IH_CEC_STAT0);
hdmi_writeb(cec_stat, HDMI_IH_CEC_STAT0);
phy_stat0 = hdmi_readb(HDMI_PHY_STAT0) & 0x02;
+
+ if ((cec_stat & (HDMI_IH_CEC_STAT0_ERROR_INIT | \
+ HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | \
+ HDMI_IH_CEC_STAT0_DONE)) == 0) {
+ ret = IRQ_NONE;
+ cec_stat = 0;
+ }
if (hdmi_cec->link_status ^ phy_stat0) {
/* HPD value changed */
hdmi_cec->link_status = phy_stat0;
@@ -113,21 +121,14 @@ static irqreturn_t mxc_hdmi_cec_isr(int irq, void *data)
else
cec_stat |= 0x100; /* Disconnected */
}
- if ((cec_stat & (HDMI_IH_CEC_STAT0_ERROR_INIT | \
- HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | \
- HDMI_IH_CEC_STAT0_DONE | 0x180)) == 0) {
- spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
- return IRQ_HANDLED;
- }
pr_debug("HDMI CEC interrupt received\n");
- /* FIXME : there is a race with latest_cec_stat */
hdmi_cec->latest_cec_stat = cec_stat ;
schedule_delayed_work(&(hdmi_cec->hdmi_cec_work), msecs_to_jiffies(20));
spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
- return IRQ_HANDLED;
+ return ret;
}
void mxc_hdmi_cec_handle(u16 cec_stat)
@@ -479,9 +480,9 @@ static unsigned int hdmi_cec_poll(struct file *file, poll_table *wait)
poll_wait(file, &hdmi_cec_queue, wait);
- /* Always writable */
- mask = (POLLOUT | POLLWRNORM);
mutex_lock(&hdmi_cec_data.lock);
+ if (hdmi_cec_data.tx_answer == CEC_TX_AVAIL)
+ mask = (POLLOUT | POLLWRNORM);
if (!list_empty(&head))
mask |= (POLLIN | POLLRDNORM);
mutex_unlock(&hdmi_cec_data.lock);
--
1.9.1