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; } if(pdata->io_init){ if(pdata->io_init()<0){ dev_err(&client->dev, "fail to rst chip\n"); goto err_request_lcdc; } } if(cat66121_detect_device()!=1){ dev_err(hdmi->dev, "can't find it6610 device \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); cat66121_hdmi_sys_init(); #ifdef HDMI_DEBUG device_create_file(&(client->dev), &hdmi_attrs[0]); #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); 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; } 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 { 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"); g_hdmi_data = pdata; 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 __devinit rk616_hdmi_probe (struct platform_device *pdev) { int ret; struct rk616_hdmi *rk616_hdmi; struct resource __maybe_unused *mem; struct resource __maybe_unused *res; rk616_hdmi = devm_kzalloc(&pdev->dev, sizeof(*rk616_hdmi), GFP_KERNEL); if(!rk616_hdmi) { dev_err(&pdev->dev, ">>rk616_hdmi kmalloc fail!"); return -ENOMEM; } hdmi = &rk616_hdmi->g_hdmi; #ifdef CONFIG_ARCH_RK3026 rk616_hdmi->rk616_drv = NULL; #else rk616_hdmi->rk616_drv = dev_get_drvdata(pdev->dev.parent); if(!(rk616_hdmi->rk616_drv)) { dev_err(&pdev->dev,"null mfd device rk616!\n"); return -ENODEV; } #endif hdmi->dev = &pdev->dev; platform_set_drvdata(pdev, hdmi); 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"); ret = -ENXIO; goto err0; } hdmi->xscale = 100; hdmi->yscale = 100; 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 #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); INIT_DELAYED_WORK(&rk616_hdmi->rk616_delay_work, rk616_delay_work_func); /* get the IRQ */ // if(rk616->pdata->hdmi_irq != INVALID_GPIO) #ifdef CONFIG_ARCH_RK3026 hdmi->hclk = clk_get(NULL,"pclk_hdmi"); if(IS_ERR(hdmi->hclk)) { dev_err(hdmi->dev, "Unable to get hdmi hclk\n"); ret = -ENXIO; goto err0; } clk_enable(hdmi->hclk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(hdmi->dev, "Unable to get register resource\n"); ret = -ENXIO; goto err0; } hdmi->regbase_phy = res->start; hdmi->regsize_phy = (res->end - res->start) + 1; mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name); if (!mem) { dev_err(hdmi->dev, "failed to request mem region for hdmi\n"); ret = -ENOENT; goto err0; } printk("res->start = 0x%x\n, xhc-------res->end = 0x%x\n", res->start, res->end); hdmi->regbase = (int)ioremap(res->start, (res->end - res->start) + 1); if (!hdmi->regbase) { dev_err(hdmi->dev, "cannot ioremap registers\n"); ret = -ENXIO; goto err1; } // rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA); // rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL); // rk30_mux_api_set(GPIO0B7_HDMI_HOTPLUGIN_NAME, GPIO0B_HDMI_HOTPLUGIN); iomux_set(HDMI_DDCSDA); iomux_set(HDMI_DDCSCL); iomux_set(HDMI_HOTPLUGIN); ret = rk616_hdmi_initial(); /* get the IRQ */ hdmi->irq = platform_get_irq(pdev, 0); if(hdmi->irq <= 0) { dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq); hdmi->irq = 0; } else { /* request the IRQ */ ret = request_irq(hdmi->irq, rk616_hdmi_irq, 0, dev_name(&pdev->dev), hdmi); if (ret) { dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret); goto err1; } } #else ret = rk616_hdmi_initial(); if(rk616_hdmi->rk616_drv->pdata->hdmi_irq != INVALID_GPIO) { INIT_WORK(&rk616_hdmi->rk616_irq_work_struct, rk616_irq_work_func); ret = gpio_request(rk616_hdmi->rk616_drv->pdata->hdmi_irq,"rk616_hdmi_irq"); if(ret < 0) { dev_err(hdmi->dev,"request gpio for rk616 hdmi irq fail\n"); } gpio_direction_input(rk616_hdmi->rk616_drv->pdata->hdmi_irq); hdmi->irq = gpio_to_irq(rk616_hdmi->rk616_drv->pdata->hdmi_irq); if(hdmi->irq <= 0) { dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq); ret = -ENXIO; goto err1; } /* request the IRQ */ ret = request_irq(hdmi->irq, rk616_hdmi_irq, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), &rk616_hdmi->rk616_irq_work_struct); if (ret) { dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret); goto err1; } } else { /* use roll polling method */ hdmi->irq = 0; } #endif hdmi_register_display_sysfs(hdmi, NULL); #if defined(CONFIG_DEBUG_FS) if(rk616_hdmi->rk616_drv && rk616_hdmi->rk616_drv->debugfs_dir) { debugfs_create_file("hdmi", S_IRUSR, rk616_hdmi->rk616_drv->debugfs_dir, rk616_hdmi->rk616_drv, &rk616_hdmi_reg_fops); } else { rk616_hdmi->debugfs_dir = debugfs_create_dir("rk616", NULL); if (IS_ERR(rk616_hdmi->debugfs_dir)) { dev_err(hdmi->dev,"failed to create debugfs dir for rk616!\n"); } else { debugfs_create_file("hdmi", S_IRUSR, rk616_hdmi->debugfs_dir, rk616_hdmi, &rk616_hdmi_reg_fops); } } #endif //rk616_delay_work_func(NULL); queue_delayed_work(hdmi->workqueue, &rk616_hdmi->rk616_delay_work, msecs_to_jiffies(0)); dev_info(hdmi->dev, "rk616 hdmi probe success.\n"); return 0; err1: #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 err0: hdmi_dbg(hdmi->dev, "rk616 hdmi probe error.\n"); kfree(hdmi); hdmi = NULL; return ret; }
int HDMI_task(struct hdmi *hdmi) { int rc, state, state_last, hpd, trytimes; // state = g_state; // hdmi_sys_show_state(hdmi, state); /* Process parametre changed */ state = hdmi_sys_change(hdmi); /* Initialize hdmi chips when system start.*/ if(state == HDMI_UNKNOWN) { rc = hdmi_sys_init(hdmi); state = WAIT_HOTPLUG; } if(!hdmi->enable) goto exit; /* Detect hdmi status */ state = hdmi_sys_detect_status(hdmi, state); /* Process HDMI status machine */ rc = 0; trytimes = 0; do { state_last = state; switch(state) { case HDMI_INITIAL: rc = hdmi_sys_init(hdmi); if(rc == HDMI_ERROR_SUCESS) { hdmi->rate = 0; state = WAIT_HOTPLUG; } else hdmi->rate = HDMI_TASK_INTERVAL; break; case WAIT_HOTPLUG: hdmi->rate = HDMI_TASK_INTERVAL; if(hdmi->hpd_status > HDMI_RECEIVER_REMOVE) { #ifdef HDMI_DEBUG_TIME hdmi_time_start = jiffies; #endif if(hdmi->ops->insert) { rc = hdmi->ops->insert(hdmi); } if(rc == HDMI_ERROR_SUCESS) { state = READ_PARSE_EDID; } else hdmi->rate = HDMI_TASK_INTERVAL; } break; case READ_PARSE_EDID: rc = hdmi_sys_parse_edid(hdmi); #ifdef HDMI_DEBUG_TIME hdmi_time_end = jiffies; if(hdmi_time_end > hdmi_time_start) hdmi_time_end -= hdmi_time_start; else hdmi_time_end += 0xFFFFFFFF - hdmi_time_start; dev_printk(KERN_INFO, hdmi->dev, "HDMI EDID parse cost %u ms\n", jiffies_to_msecs(hdmi_time_end)); #endif if(rc == HDMI_ERROR_SUCESS) { hdmi->rate = 0; state = WAIT_RX_SENSE; hdmi_sys_send_uevent(hdmi, KOBJ_ADD); } else hdmi->rate = HDMI_TASK_INTERVAL; break; case WAIT_RX_SENSE: if(hdmi->ops->detect_sink) { rc = hdmi->ops->detect_sink(hdmi, &hpd); hdmi->hpd_status = hpd; if(hpd == HDMI_RECEIVER_ACTIVE) { //Only when HDMI receiver is actived, //HDMI communication is successful. state = WAIT_HDMI_ENABLE; hdmi->rate = 0; } else { rc = HDMI_ERROR_FALSE; hdmi->rate = HDMI_TASK_INTERVAL; } } else { hdmi->hpd_status = HDMI_RECEIVER_ACTIVE; hdmi->rate = 0; state = WAIT_HDMI_ENABLE; if(hdmi->auto_switch) hdmi_enable(hdmi); } #ifdef HDMI_DEBUG_TIME hdmi_time_end = jiffies; if(hdmi_time_end > hdmi_time_start) hdmi_time_end -= hdmi_time_start; else hdmi_time_end += 0xFFFFFFFF - hdmi_time_start; dev_printk(KERN_INFO, hdmi->dev, "HDMI sink enable cost %u ms\n", jiffies_to_msecs(hdmi_time_end)); #endif break; case WAIT_HDMI_ENABLE: if(hdmi->config_set.display_on == HDMI_DISPLAY_OFF) hdmi->rate = HDMI_TASK_INTERVAL; else state = SYSTEM_CONFIG; break; case SYSTEM_CONFIG: if(hdmi->auto_switch) { rk_display_device_disable_other(hdmi->ddev); g_lcdcstatus = 1; } if(hdmi->auto_config) hdmi->config_set.resolution = ext_hdmi_find_best_mode(hdmi, 0); else hdmi->config_set.resolution = ext_hdmi_find_best_mode(hdmi, hdmi->config_set.resolution); rc = ext_hdmi_switch_fb(hdmi, 1); #ifdef HDMI_DEBUG_TIME hdmi_time_end = jiffies; if(hdmi_time_end > hdmi_time_start) hdmi_time_end -= hdmi_time_start; else hdmi_time_end += 0xFFFFFFFF - hdmi_time_start; dev_printk(KERN_INFO, hdmi->dev, "HDMI configure LCD cost %u ms\n", jiffies_to_msecs(hdmi_time_end)); #endif if(rc == HDMI_ERROR_SUCESS) { state = CONFIG_VIDEO; hdmi->rate = 0; } else hdmi->rate = HDMI_TASK_INTERVAL; break; case CONFIG_VIDEO: { hdmi->config_real.display_on = HDMI_DISABLE; if(hdmi->edid.is_hdmi) { if(hdmi->edid.ycbcr444) hdmi->config_set.color = HDMI_VIDEO_YCbCr444; else if(hdmi->edid.ycbcr422) hdmi->config_set.color = HDMI_VIDEO_YCbCr422; else hdmi->config_set.color = HDMI_VIDEO_RGB; } else hdmi->config_set.color = HDMI_VIDEO_RGB; if(hdmi->config_set.color > HDMI_VIDEO_RGB && (!hdmi->support_r2y)) hdmi->config_set.color = HDMI_VIDEO_RGB; rc = hdmi->ops->config_video(hdmi, hdmi->config_set.resolution, HDMI_VIDEO_RGB, /*HDMI_VIDEO_RGB*/hdmi->config_set.color); #ifdef HDMI_DEBUG_TIME hdmi_time_end = jiffies; if(hdmi_time_end > hdmi_time_start) hdmi_time_end -= hdmi_time_start; else hdmi_time_end += 0xFFFFFFFF - hdmi_time_start; dev_printk(KERN_INFO, hdmi->dev, "HDMI configure VIDEO cost %u ms\n", jiffies_to_msecs(hdmi_time_end)); #endif } if(rc == HDMI_ERROR_SUCESS) { hdmi->rate = 0; if(hdmi->edid.is_hdmi) state = CONFIG_AUDIO; else state = PLAY_BACK; } else hdmi->rate = HDMI_TASK_INTERVAL; break; case CONFIG_AUDIO: rc = hdmi->ops->config_audio(hdmi, &(hdmi->config_set.audio)); #ifdef HDMI_DEBUG_TIME hdmi_time_end = jiffies; if(hdmi_time_end > hdmi_time_start) hdmi_time_end -= hdmi_time_start; else hdmi_time_end += 0xFFFFFFFF - hdmi_time_start; dev_printk(KERN_INFO, hdmi->dev, "HDMI configure Audio cost %u ms\n", jiffies_to_msecs(hdmi_time_end)); #endif if(rc == HDMI_ERROR_SUCESS) { hdmi->rate = 0; state = PLAY_BACK; } else hdmi->rate = HDMI_TASK_INTERVAL; break; #if 0 case HDCP_AUTHENTICATION: if(hdmi->ops->config_hdcp) { rc = hdmi->ops->config_hdcp(hdmi, hdmi->config_set.hdcp_on); #ifdef HDMI_DEBUG_TIME hdmi_time_end = jiffies; if(hdmi_time_end > hdmi_time_start) hdmi_time_end -= hdmi_time_start; else hdmi_time_end += 0xFFFFFFFF - hdmi_time_start; dev_printk(KERN_INFO, hdmi->dev, "HDMI configure HDCP cost %u ms\n", jiffies_to_msecs(hdmi_time_end)); #endif } if(rc == HDMI_ERROR_SUCESS) { hdmi->rate = 0; state = PLAY_BACK; } else hdmi->rate = HDMI_TASK_INTERVAL; break; #endif case PLAY_BACK: // if(hdmi->config_real.display_on != hdmi->config_set.display_on) if( memcmp(&(hdmi->config_real), &(hdmi->config_set), sizeof(struct hdmi_configs)) ) { if(hdmi->config_set.display_on == HDMI_DISPLAY_ON) { if(hdmi->ops->config_hdcp) rc = hdmi->ops->config_hdcp(hdmi, hdmi->config_set.hdcp_on); rc |= hdmi->ops->enable(hdmi, HDMI_ENABLE); } else rc = hdmi->ops->enable(hdmi, HDMI_DISABLE); if(rc == HDMI_ERROR_SUCESS) { #ifdef HDMI_DEBUG_TIME hdmi_time_end = jiffies; if(hdmi_time_end > hdmi_time_start) hdmi_time_end -= hdmi_time_start; else hdmi_time_end += 0xFFFFFFFF - hdmi_time_start; dev_printk(KERN_INFO, hdmi->dev, "HDMI configuration cost %u ms\n", jiffies_to_msecs(hdmi_time_end)); #endif memcpy(&(hdmi->config_real), &(hdmi->config_set), sizeof(struct hdmi_configs)); } if(hdmi->config_set.display_on == HDMI_DISABLE) state = WAIT_HDMI_ENABLE; } if(hdmi->wait == 1) { complete(&hdmi->complete); hdmi->wait = 0; } hdmi->rate = HDMI_TASK_INTERVAL; break; default: state = HDMI_INITIAL; hdmi->rate = HDMI_TASK_INTERVAL; break; } if(rc != HDMI_ERROR_SUCESS) { trytimes++; msleep(10); } if(state != state_last) { trytimes = 0; hdmi_sys_show_state(hdmi, state); } }while((state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES); if(trytimes == HDMI_MAX_TRY_TIMES) { if(hdmi->hpd_status) { if(state == CONFIG_AUDIO) state = HDCP_AUTHENTICATION; else if(state > WAIT_RX_SENSE) { hdmi_sys_unplug(hdmi); if(hdmi->auto_switch && g_lcdcstatus) { rk_display_device_enable_other(hdmi->ddev); g_lcdcstatus = 0; } state = HDMI_UNKNOWN; } } } exit: if(state != g_state) g_state = state; return 0; }