From: yzq Date: Sat, 7 Sep 2013 06:11:14 +0000 (+0800) Subject: Qc880:optimize hdmi irq mode to avoid lose interrupt X-Git-Tag: firefly_0821_release~6650 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=1156a07ff80181d38c79c4cb49eb339e0ce8fb10;p=firefly-linux-kernel-4.4.55.git Qc880:optimize hdmi irq mode to avoid lose interrupt --- diff --git a/drivers/video/rockchip/hdmi/chips/cat66121/cat66121_hdmi.c b/drivers/video/rockchip/hdmi/chips/cat66121/cat66121_hdmi.c index 90d4a635f62c..891c0a56daf7 100755 --- a/drivers/video/rockchip/hdmi/chips/cat66121/cat66121_hdmi.c +++ b/drivers/video/rockchip/hdmi/chips/cat66121/cat66121_hdmi.c @@ -6,26 +6,24 @@ #include #include #include +#include +#if defined(CONFIG_DEBUG_FS) +#include +#include +#include +#endif + #include "cat66121_hdmi.h" #include "cat66121_hdmi_hw.h" +#define HDMI_POLL_MDELAY 100 struct cat66121_hdmi_pdata *cat66121_hdmi = NULL; struct hdmi *hdmi=NULL; extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name); extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent); extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi); -static void check_status_func(struct work_struct *work); static void cat66121_irq_work_func(struct work_struct *work); -static DECLARE_DELAYED_WORK(check_status_work,check_status_func); - -static void check_status_func(struct work_struct *work) -{ - if(HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS) & B_TX_INT_ACTIVE){ - cat66121_irq_work_func(NULL); - } - schedule_delayed_work(&check_status_work, msecs_to_jiffies(5000)); -} #if 0 int cat66121_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void), void (*hdcp_irq_cb)(int status), @@ -52,10 +50,8 @@ static void hdmi_early_suspend(struct early_suspend *h) return; } - #ifdef HDMI_USE_IRQ - if(hdmi->irq) + if(hdmi->irq != INVALID_GPIO) disable_irq(hdmi->irq); - #endif mutex_unlock(&hdmi->enable_mutex); hdmi->command = HDMI_CONFIG_ENABLE; @@ -65,7 +61,6 @@ static void hdmi_early_suspend(struct early_suspend *h) wait_for_completion_interruptible_timeout(&hdmi->complete, msecs_to_jiffies(5000)); flush_delayed_work(&hdmi->delay_work); - cancel_delayed_work_sync(&check_status_work); return; } @@ -75,15 +70,12 @@ static void hdmi_early_resume(struct early_suspend *h) mutex_lock(&hdmi->enable_mutex); hdmi->suspend = 0; - #ifdef HDMI_USE_IRQ - if(hdmi->enable && hdmi->irq) { + if(hdmi->irq == INVALID_GPIO){ + queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, HDMI_POLL_MDELAY); + }else if(hdmi->enable){ enable_irq(hdmi->irq); } - #else - queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, 100); - #endif queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10)); - schedule_delayed_work(&check_status_work, msecs_to_jiffies(5000)); mutex_unlock(&hdmi->enable_mutex); return; } @@ -97,21 +89,21 @@ static void cat66121_irq_work_func(struct work_struct *work) if(hdmi->hdcp_irq_cb) hdmi->hdcp_irq_cb(0); } - #ifndef HDMI_USE_IRQ - queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, 100); - #endif + if(hdmi->irq == INVALID_GPIO){ + queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, HDMI_POLL_MDELAY); + } } } -#ifdef HDMI_USE_IRQ -static irqreturn_t cat66121_irq(int irq, void *dev_id) +static irqreturn_t cat66121_thread_interrupt(int irq, void *dev_id) { - printk(KERN_INFO "cat66121 irq triggered.\n"); - schedule_work(&cat66121_hdmi->irq_work); - return IRQ_HANDLED; + cat66121_irq_work_func(NULL); + msleep(HDMI_POLL_MDELAY); + hdmi_dbg(hdmi->dev, "%s irq=%d\n", __func__,irq); + return IRQ_HANDLED; } -#endif -#ifdef HDMI_DEBUG + +#if defined(CONFIG_DEBUG_FS) static int hdmi_read_p0_reg(struct i2c_client *client, char reg, char *val) { return i2c_master_reg8_recv(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL; @@ -121,12 +113,10 @@ static int hdmi_write_p0_reg(struct i2c_client *client, char reg, char *val) { return i2c_master_reg8_send(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL; } -static ssize_t hdmi_show_reg_attrs(struct device *dev, - struct device_attribute *attr, - char *buf) +static int hdmi_reg_show(struct seq_file *s, void *v) { - int i,size=0; + int i; char val; struct i2c_client *client=cat66121_hdmi->client; @@ -134,41 +124,54 @@ static ssize_t hdmi_show_reg_attrs(struct device *dev, { hdmi_read_p0_reg(client, i, &val); if(i%16==0) - size += sprintf(buf+size,"\n>>>hdmi_hdmi %x:",i); - size += sprintf(buf+size," %2x",val); + seq_printf(s,"\n>>>hdmi_hdmi %x:",i); + seq_printf(s," %2x",val); } + seq_printf(s,"\n"); - return size; + return 0; } -static ssize_t hdmi_store_reg_attrs(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ + +static ssize_t hdmi_reg_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ struct i2c_client *client=NULL; - static char val=0,reg=0; + u32 reg,val; + char kbuf[25]; client = cat66121_hdmi->client; - printk("/**********hdmi reg config******/"); + + if (copy_from_user(kbuf, buf, count)) + return -EFAULT; + sscanf(kbuf, "%x%x", ®,&val); + hdmi_write_p0_reg(client, reg, (u8*)&val); - sscanf(buf, "%x%x", &val,®); - hdmi_write_p0_reg(client, reg, &val); - return size; + return count; } -static struct device_attribute hdmi_attrs[] = { - __ATTR(reg_ctl, 0777,hdmi_show_reg_attrs,hdmi_store_reg_attrs), +static int hdmi_reg_open(struct inode *inode, struct file *file) +{ + return single_open(file,hdmi_reg_show,hdmi); +} + +static const struct file_operations hdmi_reg_fops = { + .owner = THIS_MODULE, + .open = hdmi_reg_open, + .read = seq_read, + .write = hdmi_reg_write, + .llseek = seq_lseek, + .release = single_release, }; #endif static int cat66121_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id) { - int rc = 0; + int rc = 0; struct rk_hdmi_platform_data *pdata = client->dev.platform_data; cat66121_hdmi = kzalloc(sizeof(struct cat66121_hdmi_pdata), GFP_KERNEL); if(!cat66121_hdmi) { - dev_err(&client->dev, "no memory for state\n"); - return -ENOMEM; - } + dev_err(&client->dev, "no memory for state\n"); + return -ENOMEM; + } cat66121_hdmi->client = client; i2c_set_clientdata(client, cat66121_hdmi); @@ -197,12 +200,20 @@ static int cat66121_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_de goto err_request_lcdc; } } + if(cat66121_detect_device()!=1){ - dev_err(hdmi->dev, "can't find it6610 device \n"); + dev_err(hdmi->dev, "can't find it66121 device \n"); rc = -ENXIO; goto err_request_lcdc; } + if(client->irq == 0){ + dev_err(hdmi->dev, "can't find it66121 irq\n"); + dev_err(hdmi->dev, " please set irq or use irq INVALID_GPIO for poll mode\n"); + rc = -ENXIO; + goto err_request_lcdc; + } + hdmi->irq = gpio_to_irq(client->irq); hdmi->xscale = 100; hdmi->yscale = 100; hdmi->insert = cat66121_hdmi_sys_insert; @@ -235,39 +246,40 @@ static int cat66121_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_de cat66121_hdmi_sys_init(); -#ifdef HDMI_DEBUG - device_create_file(&(client->dev), &hdmi_attrs[0]); + +#if defined(CONFIG_DEBUG_FS) + { + struct dentry *debugfs_dir = debugfs_create_dir("it66121", NULL); + if (IS_ERR(debugfs_dir)) + { + dev_err(&client->dev,"failed to create debugfs dir for it66121!\n"); + } + else + debugfs_create_file("hdmi", S_IRUSR,debugfs_dir,hdmi,&hdmi_reg_fops); + } #endif -#ifdef HDMI_USE_IRQ if(client->irq != INVALID_GPIO) { - INIT_WORK(&cat66121_hdmi->irq_work, cat66121_irq_work_func); - schedule_work(&cat66121_hdmi->irq_work); + cat66121_irq_work_func(NULL); if((rc = gpio_request(client->irq, "hdmi gpio")) < 0) - { - dev_err(&client->dev, "fail to request gpio %d\n", client->irq); - goto err_request_lcdc; - } + { + dev_err(&client->dev, "fail to request gpio %d\n", client->irq); + goto err_request_lcdc; + } - schedule_delayed_work(&check_status_work, msecs_to_jiffies(5000)); - hdmi->irq = gpio_to_irq(client->irq); cat66121_hdmi->gpio = client->irq; - gpio_pull_updown(client->irq, GPIOPullUp); - gpio_direction_input(client->irq); - if((rc = request_irq(hdmi->irq, cat66121_irq, IRQF_TRIGGER_FALLING, NULL, hdmi)) < 0) - { - dev_err(&client->dev, "fail to request hdmi irq\n"); - goto err_request_irq; - } - } - else -#else - { + gpio_pull_updown(client->irq, GPIOPullUp); + gpio_direction_input(client->irq); + if((rc = request_threaded_irq(hdmi->irq, NULL ,cat66121_thread_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, dev_name(&client->dev), hdmi)) < 0) + { + dev_err(&client->dev, "fail to request hdmi irq\n"); + goto err_request_irq; + } + }else{ cat66121_hdmi->workqueue = create_singlethread_workqueue("cat66121 irq"); INIT_DELAYED_WORK(&(cat66121_hdmi->delay_work), cat66121_irq_work_func); cat66121_irq_work_func(NULL); } -#endif dev_info(&client->dev, "cat66121 hdmi i2c probe ok\n"); diff --git a/drivers/video/rockchip/hdmi/chips/cat66121/cat66121_hdmi.h b/drivers/video/rockchip/hdmi/chips/cat66121/cat66121_hdmi.h index 8ba11fa9b94f..18213ae3d114 100755 --- a/drivers/video/rockchip/hdmi/chips/cat66121/cat66121_hdmi.h +++ b/drivers/video/rockchip/hdmi/chips/cat66121/cat66121_hdmi.h @@ -8,18 +8,12 @@ #define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC0 #endif -//#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC0 -#define HDMI_USE_IRQ struct cat66121_hdmi_pdata { int gpio; struct i2c_client *client; struct delayed_work delay_work; - #ifdef HDMI_USE_IRQ - struct work_struct irq_work; - #else struct workqueue_struct *workqueue; - #endif }; extern struct cat66121_hdmi_pdata *cat66121_hdmi;