-#include <linux/kernel.h>\r
-#include <linux/delay.h>\r
-#include <linux/module.h>\r
-#include <linux/platform_device.h>\r
-#include <linux/interrupt.h>\r
-#include <mach/gpio.h>\r
-#include <mach/iomux.h>\r
-#include <linux/i2c.h>\r
-#include "cat66121_hdmi.h"\r
-\r
-struct cat66121_hdmi_pdata *cat66121_hdmi = NULL;\r
-struct hdmi *hdmi=NULL;\r
-\r
-extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name);\r
-extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent);\r
-extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi);\r
-\r
-int cat66121_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),\r
- void (*hdcp_irq_cb)(int status),\r
- int (*hdcp_power_on_cb)(void),\r
- void (*hdcp_power_off_cb)(void))\r
-{\r
- hdmi->hdcp_cb = hdcp_cb;\r
- hdmi->hdcp_irq_cb = hdcp_irq_cb;\r
- hdmi->hdcp_power_on_cb = hdcp_power_on_cb;\r
- hdmi->hdcp_power_off_cb = hdcp_power_off_cb;\r
- \r
- return HDMI_ERROR_SUCESS;\r
-}\r
-\r
-#ifdef CONFIG_HAS_EARLYSUSPEND\r
-static void hdmi_early_suspend(struct early_suspend *h)\r
-{\r
- hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);\r
- flush_delayed_work(&hdmi->delay_work); \r
- mutex_lock(&hdmi->enable_mutex);\r
- hdmi->suspend = 1;\r
- if(!hdmi->enable) {\r
- mutex_unlock(&hdmi->enable_mutex);\r
- return;\r
- }\r
- \r
- #ifdef HDMI_USE_IRQ\r
- if(hdmi->irq)\r
- disable_irq(hdmi->irq);\r
- #endif\r
- \r
- mutex_unlock(&hdmi->enable_mutex);\r
- hdmi->command = HDMI_CONFIG_ENABLE;\r
- init_completion(&hdmi->complete);\r
- hdmi->wait = 1;\r
- queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);\r
- wait_for_completion_interruptible_timeout(&hdmi->complete,\r
- msecs_to_jiffies(5000));\r
- flush_delayed_work(&hdmi->delay_work);\r
- return;\r
-}\r
-\r
-static void hdmi_early_resume(struct early_suspend *h)\r
-{\r
- hdmi_dbg(hdmi->dev, "hdmi exit early resume\n");\r
- mutex_lock(&hdmi->enable_mutex);\r
- \r
- hdmi->suspend = 0;\r
- #ifdef HDMI_USE_IRQ\r
- if(hdmi->enable && hdmi->irq) {\r
- enable_irq(hdmi->irq);\r
- }\r
- #else\r
- queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, 100);\r
- #endif\r
- queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10)); \r
- mutex_unlock(&hdmi->enable_mutex);\r
- return;\r
-}\r
-#endif\r
-\r
-static void cat66121_irq_work_func(struct work_struct *work)\r
-{\r
- if(hdmi->suspend == 0) {\r
- if(hdmi->enable == 1) {\r
- cat66121_hdmi_interrupt();\r
- if(hdmi->hdcp_irq_cb)\r
- hdmi->hdcp_irq_cb(0);\r
- }\r
- #ifndef HDMI_USE_IRQ\r
- queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, 50);\r
- #endif\r
- }\r
-}\r
-\r
-#ifdef HDMI_USE_IRQ\r
-static irqreturn_t cat66121_irq(int irq, void *dev_id)\r
-{\r
- printk(KERN_INFO "cat66121 irq triggered.\n");\r
- schedule_work(&cat66121_hdmi->irq_work);\r
- return IRQ_HANDLED;\r
-}\r
-#endif\r
-static int rk610_read_p0_reg(struct i2c_client *client, char reg, char *val)\r
-{\r
- return i2c_master_reg8_recv(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;\r
-}\r
-\r
-static int rk610_write_p0_reg(struct i2c_client *client, char reg, char *val)\r
-{\r
- return i2c_master_reg8_send(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;\r
-}\r
-static ssize_t rk610_show_reg_attrs(struct device *dev,\r
- struct device_attribute *attr,\r
- char *buf)\r
-{\r
-\r
- int i,size=0;\r
- char val;\r
- struct i2c_client *client=cat66121_hdmi->client;\r
-\r
- for(i=0;i<256;i++)\r
- {\r
- rk610_read_p0_reg(client, i, &val);\r
- if(i%16==0)\r
- size += sprintf(buf+size,"\n>>>rk610_hdmi %x:",i);\r
- size += sprintf(buf+size," %2x",val);\r
- }\r
-\r
- return size;\r
-}\r
-static ssize_t rk610_store_reg_attrs(struct device *dev,\r
- struct device_attribute *attr,\r
- const char *buf, size_t size)\r
-{\r
- struct i2c_client *client=NULL;\r
- static char val=0,reg=0;\r
- client = cat66121_hdmi->client;\r
- printk("/**********rk610 reg config******/");\r
-\r
- sscanf(buf, "%x%x", &val,®);\r
- printk("reg=%x val=%x\n",reg,val);\r
- rk610_write_p0_reg(client, reg, &val);\r
- printk("val=%x\n",val);\r
- return size;\r
-}\r
-\r
-static struct device_attribute rk610_attrs[] = {\r
- __ATTR(reg_ctl, 0777,rk610_show_reg_attrs,rk610_store_reg_attrs),\r
-};\r
-static int cat66121_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)\r
-{\r
- int rc = 0;\r
- \r
- cat66121_hdmi = kzalloc(sizeof(struct cat66121_hdmi_pdata), GFP_KERNEL);\r
- if(!cat66121_hdmi)\r
- {\r
- dev_err(&client->dev, "no memory for state\n");\r
- return -ENOMEM;\r
- }\r
- cat66121_hdmi->client = client;\r
- i2c_set_clientdata(client, cat66121_hdmi);\r
- \r
- hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL);\r
- if(!hdmi)\r
- {\r
- dev_err(&client->dev, "cat66121 hdmi kmalloc fail!");\r
- goto err_kzalloc_hdmi;\r
- }\r
- memset(hdmi, 0, sizeof(struct hdmi));\r
- hdmi->dev = &client->dev;\r
- \r
- if(HDMI_SOURCE_DEFAULT == HDMI_SOURCE_LCDC0)\r
- hdmi->lcdc = rk_get_lcdc_drv("lcdc0");\r
- else\r
- hdmi->lcdc = rk_get_lcdc_drv("lcdc1");\r
- if(hdmi->lcdc == NULL)\r
- {\r
- dev_err(hdmi->dev, "can not connect to video source lcdc\n");\r
- rc = -ENXIO;\r
- goto err_request_lcdc;\r
- }\r
- hdmi->xscale = 100;\r
- hdmi->yscale = 100;\r
- hdmi->insert = cat66121_hdmi_sys_insert;\r
- hdmi->remove = cat66121_hdmi_sys_remove;\r
- hdmi->control_output = cat66121_hdmi_sys_enalbe_output;\r
- hdmi->config_video = cat66121_hdmi_sys_config_video;\r
- hdmi->config_audio = cat66121_hdmi_sys_config_audio;\r
- hdmi->detect_hotplug = cat66121_hdmi_sys_detect_hpd;\r
- hdmi->read_edid = cat66121_hdmi_sys_read_edid;\r
- hdmi_sys_init();\r
- \r
- hdmi->workqueue = create_singlethread_workqueue("hdmi");\r
- INIT_DELAYED_WORK(&(hdmi->delay_work), hdmi_work);\r
- \r
- #ifdef CONFIG_HAS_EARLYSUSPEND\r
- hdmi->early_suspend.suspend = hdmi_early_suspend;\r
- hdmi->early_suspend.resume = hdmi_early_resume;\r
- hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10;\r
- register_early_suspend(&hdmi->early_suspend);\r
- #endif\r
- \r
- hdmi_register_display_sysfs(hdmi, NULL);\r
- #ifdef CONFIG_SWITCH\r
- hdmi->switch_hdmi.name="hdmi";\r
- switch_dev_register(&(hdmi->switch_hdmi));\r
- #endif\r
- \r
- spin_lock_init(&hdmi->irq_lock);\r
- mutex_init(&hdmi->enable_mutex);\r
- \r
- cat66121_hdmi_sys_init();\r
- rc = gpio_request(client->irq, "cat66121 rst");\r
- if (rc != 0) {\r
- gpio_free(client->irq);\r
- printk("goodix power error\n");\r
- return -EIO;\r
- }\r
- gpio_direction_output(client->irq, GPIO_HIGH);\r
- gpio_set_value(client->irq, GPIO_HIGH);\r
- msleep(10);\r
- gpio_set_value(client->irq, GPIO_LOW);\r
- msleep(200);\r
- gpio_set_value(client->irq, GPIO_HIGH);\r
-#ifdef HDMI_USE_IRQ\r
- if(client->irq != INVALID_GPIO) {\r
- INIT_WORK(&cat66121_hdmi->irq_work, cat66121_irq_work_func);\r
- schedule_work(&cat66121_hdmi->irq_work);\r
- if((rc = gpio_request(client->irq, "hdmi gpio")) < 0)\r
- {\r
- dev_err(&client->dev, "fail to request gpio %d\n", client->irq);\r
- goto err_request_lcdc;\r
- }\r
- hdmi->irq = gpio_to_irq(client->irq);\r
- cat66121_hdmi->gpio = client->irq;\r
- gpio_pull_updown(client->irq, GPIOPullUp);\r
- gpio_direction_input(client->irq);\r
- if((rc = request_irq(hdmi->irq, cat66121_irq, IRQF_TRIGGER_RISING, NULL, hdmi)) < 0)\r
- {\r
- dev_err(&client->dev, "fail to request hdmi irq\n");\r
- goto err_request_irq;\r
- }\r
- }\r
- else\r
-#else\r
- {\r
- cat66121_hdmi->workqueue = create_singlethread_workqueue("cat66121 irq");\r
- INIT_DELAYED_WORK(&(cat66121_hdmi->delay_work), cat66121_irq_work_func);\r
- cat66121_irq_work_func(NULL);\r
- }\r
-#endif\r
-\r
- device_create_file(&(client->dev), &rk610_attrs[0]);\r
- dev_info(&client->dev, "cat66121 hdmi i2c probe ok\n");\r
- \r
- return 0;\r
- \r
-err_request_irq:\r
- gpio_free(client->irq);\r
-err_request_lcdc:\r
- kfree(hdmi);\r
- hdmi = NULL;\r
-err_kzalloc_hdmi:\r
- kfree(cat66121_hdmi);\r
- cat66121_hdmi = NULL;\r
- dev_err(&client->dev, "cat66121 hdmi probe error\n");\r
- return rc;\r
-\r
-}\r
-\r
-static int __devexit cat66121_hdmi_i2c_remove(struct i2c_client *client)\r
-{ \r
- hdmi_dbg(hdmi->dev, "%s\n", __func__);\r
- if(hdmi) {\r
- mutex_lock(&hdmi->enable_mutex);\r
- if(!hdmi->suspend && hdmi->enable && hdmi->irq)\r
- disable_irq(hdmi->irq);\r
- mutex_unlock(&hdmi->enable_mutex);\r
- if(hdmi->irq)\r
- free_irq(hdmi->irq, NULL);\r
- flush_workqueue(hdmi->workqueue);\r
- destroy_workqueue(hdmi->workqueue);\r
- #ifdef CONFIG_SWITCH\r
- switch_dev_unregister(&(hdmi->switch_hdmi));\r
- #endif\r
- hdmi_unregister_display_sysfs(hdmi);\r
- #ifdef CONFIG_HAS_EARLYSUSPEND\r
- unregister_early_suspend(&hdmi->early_suspend);\r
- #endif\r
- fb_destroy_modelist(&hdmi->edid.modelist);\r
- if(hdmi->edid.audio)\r
- kfree(hdmi->edid.audio);\r
- if(hdmi->edid.specs)\r
- {\r
- if(hdmi->edid.specs->modedb)\r
- kfree(hdmi->edid.specs->modedb);\r
- kfree(hdmi->edid.specs);\r
- }\r
- kfree(hdmi);\r
- hdmi = NULL;\r
- }\r
- return 0;\r
-}\r
-\r
-static void cat66121_hdmi_i2c_shutdown(struct i2c_client *client)\r
-{\r
- if(hdmi) {\r
- #ifdef CONFIG_HAS_EARLYSUSPEND\r
- unregister_early_suspend(&hdmi->early_suspend);\r
- #endif\r
- }\r
- printk(KERN_INFO "cat66121 hdmi shut down.\n");\r
-}\r
-\r
-static const struct i2c_device_id cat66121_hdmi_id[] = {\r
- { "cat66121_hdmi", 0 },\r
- { }\r
-};\r
-\r
-static struct i2c_driver cat66121_hdmi_i2c_driver = {\r
- .driver = {\r
- .name = "cat66121_hdmi",\r
- .owner = THIS_MODULE,\r
- },\r
- .probe = cat66121_hdmi_i2c_probe,\r
- .remove = cat66121_hdmi_i2c_remove,\r
- .shutdown = cat66121_hdmi_i2c_shutdown,\r
- .id_table = cat66121_hdmi_id,\r
-};\r
-\r
-static int __init cat66121_hdmi_init(void)\r
-{\r
- return i2c_add_driver(&cat66121_hdmi_i2c_driver);\r
-}\r
-\r
-static void __exit cat66121_hdmi_exit(void)\r
-{\r
- i2c_del_driver(&cat66121_hdmi_i2c_driver);\r
-}\r
-\r
-module_init(cat66121_hdmi_init);\r
-//fs_initcall(cat66121_init);\r
-module_exit(cat66121_hdmi_exit);\r
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+#include <linux/i2c.h>
+#include "cat66121_hdmi.h"
+
+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);
+
+int cat66121_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
+ void (*hdcp_irq_cb)(int status),
+ int (*hdcp_power_on_cb)(void),
+ void (*hdcp_power_off_cb)(void))
+{
+ hdmi->hdcp_cb = hdcp_cb;
+ hdmi->hdcp_irq_cb = hdcp_irq_cb;
+ hdmi->hdcp_power_on_cb = hdcp_power_on_cb;
+ hdmi->hdcp_power_off_cb = hdcp_power_off_cb;
+
+ return HDMI_ERROR_SUCESS;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void hdmi_early_suspend(struct early_suspend *h)
+{
+ hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);
+ flush_delayed_work(&hdmi->delay_work);
+ mutex_lock(&hdmi->enable_mutex);
+ hdmi->suspend = 1;
+ if(!hdmi->enable) {
+ mutex_unlock(&hdmi->enable_mutex);
+ return;
+ }
+
+ #ifdef HDMI_USE_IRQ
+ if(hdmi->irq)
+ disable_irq(hdmi->irq);
+ #endif
+
+ mutex_unlock(&hdmi->enable_mutex);
+ hdmi->command = HDMI_CONFIG_ENABLE;
+ init_completion(&hdmi->complete);
+ hdmi->wait = 1;
+ queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);
+ wait_for_completion_interruptible_timeout(&hdmi->complete,
+ msecs_to_jiffies(5000));
+ flush_delayed_work(&hdmi->delay_work);
+ return;
+}
+
+static void hdmi_early_resume(struct early_suspend *h)
+{
+ hdmi_dbg(hdmi->dev, "hdmi exit early resume\n");
+ mutex_lock(&hdmi->enable_mutex);
+
+ hdmi->suspend = 0;
+ #ifdef HDMI_USE_IRQ
+ if(hdmi->enable && hdmi->irq) {
+ 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));
+ mutex_unlock(&hdmi->enable_mutex);
+ return;
+}
+#endif
+
+static void cat66121_irq_work_func(struct work_struct *work)
+{
+ if(hdmi->suspend == 0) {
+ if(hdmi->enable == 1) {
+ cat66121_hdmi_interrupt();
+ if(hdmi->hdcp_irq_cb)
+ hdmi->hdcp_irq_cb(0);
+ }
+ #ifndef HDMI_USE_IRQ
+ queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, 50);
+ #endif
+ }
+}
+
+#ifdef HDMI_USE_IRQ
+static irqreturn_t cat66121_irq(int irq, void *dev_id)
+{
+ printk(KERN_INFO "cat66121 irq triggered.\n");
+ schedule_work(&cat66121_hdmi->irq_work);
+ return IRQ_HANDLED;
+}
+#endif
+#ifdef HDMI_DEBUG
+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;
+}
+
+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)
+{
+
+ int i,size=0;
+ char val;
+ struct i2c_client *client=cat66121_hdmi->client;
+
+ for(i=0;i<256;i++)
+ {
+ 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);
+ }
+
+ return size;
+}
+static ssize_t hdmi_store_reg_attrs(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct i2c_client *client=NULL;
+ static char val=0,reg=0;
+ client = cat66121_hdmi->client;
+ printk("/**********hdmi reg config******/");
+
+ sscanf(buf, "%x%x", &val,®);
+ hdmi_write_p0_reg(client, reg, &val);
+ return size;
+}
+
+static struct device_attribute hdmi_attrs[] = {
+ __ATTR(reg_ctl, 0777,hdmi_show_reg_attrs,hdmi_store_reg_attrs),
+};
+#endif
+static int cat66121_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
+{
+ 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;
+ }
+ cat66121_hdmi->client = client;
+ i2c_set_clientdata(client, cat66121_hdmi);
+
+ hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL);
+ if(!hdmi)
+ {
+ dev_err(&client->dev, "cat66121 hdmi kmalloc fail!");
+ goto err_kzalloc_hdmi;
+ }
+ memset(hdmi, 0, sizeof(struct hdmi));
+ hdmi->dev = &client->dev;
+
+ if(HDMI_SOURCE_DEFAULT == HDMI_SOURCE_LCDC0)
+ hdmi->lcdc = rk_get_lcdc_drv("lcdc0");
+ else
+ hdmi->lcdc = rk_get_lcdc_drv("lcdc1");
+ if(hdmi->lcdc == NULL)
+ {
+ dev_err(hdmi->dev, "can not connect to video source lcdc\n");
+ rc = -ENXIO;
+ goto err_request_lcdc;
+ }
+ hdmi->xscale = 100;
+ hdmi->yscale = 100;
+ hdmi->insert = cat66121_hdmi_sys_insert;
+ hdmi->remove = cat66121_hdmi_sys_remove;
+ hdmi->control_output = cat66121_hdmi_sys_enalbe_output;
+ hdmi->config_video = cat66121_hdmi_sys_config_video;
+ hdmi->config_audio = cat66121_hdmi_sys_config_audio;
+ hdmi->detect_hotplug = cat66121_hdmi_sys_detect_hpd;
+ hdmi->read_edid = cat66121_hdmi_sys_read_edid;
+ hdmi_sys_init();
+
+ hdmi->workqueue = create_singlethread_workqueue("hdmi");
+ INIT_DELAYED_WORK(&(hdmi->delay_work), hdmi_work);
+
+ #ifdef CONFIG_HAS_EARLYSUSPEND
+ hdmi->early_suspend.suspend = hdmi_early_suspend;
+ hdmi->early_suspend.resume = hdmi_early_resume;
+ hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10;
+ register_early_suspend(&hdmi->early_suspend);
+ #endif
+
+ hdmi_register_display_sysfs(hdmi, NULL);
+ #ifdef CONFIG_SWITCH
+ hdmi->switch_hdmi.name="hdmi";
+ switch_dev_register(&(hdmi->switch_hdmi));
+ #endif
+
+ spin_lock_init(&hdmi->irq_lock);
+ mutex_init(&hdmi->enable_mutex);
+
+ if(pdata->io_init){
+ if(pdata->io_init()<0){
+ dev_err(&client->dev, "fail to rst chip\n");
+ goto err_request_lcdc;
+ }
+ }
+ cat66121_hdmi_sys_init();
+#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);
+ 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;
+ }
+ 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_RISING, NULL, hdmi)) < 0)
+ {
+ dev_err(&client->dev, "fail to request hdmi irq\n");
+ goto err_request_irq;
+ }
+ }
+ else
+#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
+
+#ifdef HDMI_DEBUG
+ device_create_file(&(client->dev), &hdmi_attrs[0]);
+#endif
+ dev_info(&client->dev, "cat66121 hdmi i2c probe ok\n");
+
+ return 0;
+
+err_request_irq:
+ gpio_free(client->irq);
+err_request_lcdc:
+ kfree(hdmi);
+ hdmi = NULL;
+err_kzalloc_hdmi:
+ kfree(cat66121_hdmi);
+ cat66121_hdmi = NULL;
+ dev_err(&client->dev, "cat66121 hdmi probe error\n");
+ return rc;
+
+}
+
+static int __devexit cat66121_hdmi_i2c_remove(struct i2c_client *client)
+{
+ hdmi_dbg(hdmi->dev, "%s\n", __func__);
+ if(hdmi) {
+ mutex_lock(&hdmi->enable_mutex);
+ if(!hdmi->suspend && hdmi->enable && hdmi->irq)
+ disable_irq(hdmi->irq);
+ mutex_unlock(&hdmi->enable_mutex);
+ if(hdmi->irq)
+ free_irq(hdmi->irq, NULL);
+ flush_workqueue(hdmi->workqueue);
+ destroy_workqueue(hdmi->workqueue);
+ #ifdef CONFIG_SWITCH
+ switch_dev_unregister(&(hdmi->switch_hdmi));
+ #endif
+ hdmi_unregister_display_sysfs(hdmi);
+ #ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&hdmi->early_suspend);
+ #endif
+ fb_destroy_modelist(&hdmi->edid.modelist);
+ if(hdmi->edid.audio)
+ kfree(hdmi->edid.audio);
+ if(hdmi->edid.specs)
+ {
+ if(hdmi->edid.specs->modedb)
+ kfree(hdmi->edid.specs->modedb);
+ kfree(hdmi->edid.specs);
+ }
+ kfree(hdmi);
+ hdmi = NULL;
+ }
+ return 0;
+}
+
+static void cat66121_hdmi_i2c_shutdown(struct i2c_client *client)
+{
+ if(hdmi) {
+ #ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&hdmi->early_suspend);
+ #endif
+ }
+ printk(KERN_INFO "cat66121 hdmi shut down.\n");
+}
+
+static const struct i2c_device_id cat66121_hdmi_id[] = {
+ { "cat66121_hdmi", 0 },
+ { }
+};
+
+static struct i2c_driver cat66121_hdmi_i2c_driver = {
+ .driver = {
+ .name = "cat66121_hdmi",
+ .owner = THIS_MODULE,
+ },
+ .probe = cat66121_hdmi_i2c_probe,
+ .remove = cat66121_hdmi_i2c_remove,
+ .shutdown = cat66121_hdmi_i2c_shutdown,
+ .id_table = cat66121_hdmi_id,
+};
+
+static int __init cat66121_hdmi_init(void)
+{
+ return i2c_add_driver(&cat66121_hdmi_i2c_driver);
+}
+
+static void __exit cat66121_hdmi_exit(void)
+{
+ i2c_del_driver(&cat66121_hdmi_i2c_driver);
+}
+
+module_init(cat66121_hdmi_init);
+//fs_initcall(cat66121_init);
+module_exit(cat66121_hdmi_exit);