int hdmi_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; int ret = 0; dev_dbg(dev, "%s start\n", __func__); switch (ctrl->id) { case V4L2_CID_TV_SET_DVI_MODE: hdev->dvi_mode = ctrl->value; break; case V4L2_CID_TV_SET_ASPECT_RATIO: hdev->aspect = ctrl->value; break; case V4L2_CID_TV_ENABLE_HDMI_AUDIO: mutex_lock(&hdev->mutex); hdev->audio_enable = !!ctrl->value; if (is_hdmi_streaming(hdev)) { hdmi_set_infoframe(hdev); hdmi_audio_enable(hdev, hdev->audio_enable); } mutex_unlock(&hdev->mutex); break; case V4L2_CID_TV_SET_NUM_CHANNELS: mutex_lock(&hdev->mutex); hdmi_audio_information(hdev, ctrl->value); if (is_hdmi_streaming(hdev)) { hdmi_audio_enable(hdev, 0); hdmi_set_infoframe(hdev); hdmi_reg_i2s_audio_init(hdev); hdmi_audio_enable(hdev, 1); } mutex_unlock(&hdev->mutex); break; case V4L2_CID_TV_SET_COLOR_RANGE: hdev->color_range = ctrl->value; break; case V4L2_CID_TV_HDCP_ENABLE: hdev->hdcp_info.hdcp_enable = ctrl->value; dev_dbg(hdev->dev, "HDCP %s\n", ctrl->value ? "enable" : "disable"); #ifdef CONFIG_SEC_MHL_HDCP hdev->hdcp_info.hdcp_enable = false; /*MHL8240 control the HDCP*/ dev_dbg(hdev->dev, "MHL control the HDCP\n"); #endif break; default: dev_err(dev, "invalid control id\n"); ret = -EINVAL; break; } return ret; }
static int hdmi_streamoff(struct hdmi_device *hdev) { struct device *dev = hdev->dev; dev_dbg(dev, "%s\n", __func__); if (hdev->hdcp_info.hdcp_enable && hdev->hdcp_info.hdcp_start) hdcp_stop(hdev); hdmi_audio_enable(hdev, 0); hdmi_enable(hdev, 0); hdmi_tg_enable(hdev, 0); hdev->streaming = HDMI_STOP; /* change the HPD interrupt: Internal -> External */ disable_irq(hdev->int_irq); cancel_work_sync(&hdev->hpd_work); hdmi_reg_set_ext_hpd(hdev); enable_irq(hdev->ext_irq); dev_info(hdev->dev, "HDMI interrupt changed to external\n"); hdmi_dumpregs(hdev, "streamoff"); return 0; }
static int hdmi_streamoff(struct hdmi_device *hdev) { struct device *dev = hdev->dev; struct hdmi_resources *res = &hdev->res; dev_dbg(dev, "%s\n", __func__); if (hdev->hdcp_info.hdcp_enable) hdcp_stop(hdev); hdmi_audio_enable(hdev, 0); hdmi_enable(hdev, 0); hdmi_tg_enable(hdev, 0); /* pixel(vpll) clock is used for HDMI in config mode */ clk_disable(res->sclk_hdmi); clk_set_parent(res->sclk_hdmi, res->sclk_pixel); clk_enable(res->sclk_hdmi); v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); hdev->streaming = 0; hdmi_dumpregs(hdev, "streamoff"); return 0; }
static int hdmi_streamon(struct hdmi_device *hdev) { struct device *dev = hdev->dev; int ret; u32 val0, val1, val2; dev_dbg(dev, "%s\n", __func__); /* 3D test */ hdmi_set_infoframe(hdev); /* set packets for audio */ hdmi_set_packets(hdev); /* init audio */ #if defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_I2S) hdmi_reg_i2s_audio_init(hdev); #elif defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_SPDIF) hdmi_reg_spdif_audio_init(hdev); #endif /* enbale HDMI audio */ if (hdev->audio_enable) hdmi_audio_enable(hdev, 1); hdmi_set_dvi_mode(hdev); /* controls the pixel value limitation */ hdmi_reg_set_limits(hdev); /* enable HDMI and timing generator */ hdmi_enable(hdev, 1); hdmi_tg_enable(hdev, 1); hdev->streaming = HDMI_STREAMING; /* change the HPD interrupt: External -> Internal */ disable_irq(hdev->ext_irq); cancel_delayed_work_sync(&hdev->hpd_work_ext); hdmi_reg_set_int_hpd(hdev); enable_irq(hdev->int_irq); dev_info(hdev->dev, "HDMI interrupt changed to internal\n"); /* start HDCP if enabled */ if (hdev->hdcp_info.hdcp_enable) { ret = hdcp_start(hdev); if (ret) return ret; } val0 = hdmi_read(hdev, HDMI_ACR_MCTS0); val1 = hdmi_read(hdev, HDMI_ACR_MCTS1); val2 = hdmi_read(hdev, HDMI_ACR_MCTS2); dev_dbg(dev, "HDMI_ACR_MCTS0 : 0x%08x\n", val0); dev_dbg(dev, "HDMI_ACR_MCTS1 : 0x%08x\n", val1); dev_dbg(dev, "HDMI_ACR_MCTS2 : 0x%08x\n", val2); hdmi_dumpregs(hdev, "streamon"); return 0; }
int hdmi_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; int ret = 0; dev_dbg(dev, "%s start\n", __func__); switch (ctrl->id) { case V4L2_CID_TV_SET_DVI_MODE: hdev->dvi_mode = ctrl->value; break; case V4L2_CID_TV_SET_ASPECT_RATIO: hdev->aspect = ctrl->value; break; case V4L2_CID_TV_ENABLE_HDMI_AUDIO: mutex_lock(&hdev->mutex); hdev->audio_enable = !!ctrl->value; if (is_hdmi_streaming(hdev)) { hdmi_set_infoframe(hdev); hdmi_audio_enable(hdev, hdev->audio_enable); } mutex_unlock(&hdev->mutex); break; case V4L2_CID_TV_SET_NUM_CHANNELS: mutex_lock(&hdev->mutex); if ((ctrl->value == 2) || (ctrl->value == 6) || (ctrl->value == 8)) { hdev->audio_channel_count = ctrl->value; } else { dev_err(dev, "invalid channel count\n"); hdev->audio_channel_count = 2; } if (is_hdmi_streaming(hdev)) hdmi_set_infoframe(hdev); mutex_unlock(&hdev->mutex); break; case V4L2_CID_TV_SET_COLOR_RANGE: hdev->color_range = ctrl->value; break; case V4L2_CID_TV_HDCP_ENABLE: hdev->hdcp_info.hdcp_enable = ctrl->value; dev_dbg(hdev->dev, "HDCP %s\n", ctrl->value ? "enable" : "disable"); break; default: dev_err(dev, "invalid control id\n"); ret = -EINVAL; break; } return ret; }
int lpa_if_start(struct lpa_if *lpa_if) { pr_debug("buf1 0x%x, buf2 0x%x dma_ch %d\n", (unsigned int)lpa_if->audio_buf[0].data, (unsigned int)lpa_if->audio_buf[1].data, lpa_if->dma_ch); dai_start_hdmi(lpa_if->dma_ch); hdmi_audio_enable(1, HDMI_AUDIO_FIFO_WATER_MARK); hdmi_audio_packet_enable(1); return 0; }
static int hdmi_streamoff(struct hdmi_device *hdev) { struct device *dev = hdev->dev; dev_dbg(dev, "%s\n", __func__); hdmi_reg_set_ext_hpd(hdev); // if (edid_supports_hdmi(hdev)) { #if 1 if (hdev->hdcp_info.hdcp_enable && hdev->hdcp_info.hdcp_start) hdcp_stop(hdev); #endif // } hdmi_audio_enable(hdev, 0); hdmi_enable(hdev, 0); hdmi_tg_enable(hdev, 0); hdev->streaming = HDMI_STOP; hdmi_dumpregs(hdev, "streamoff"); return 0; }
static ssize_t lpa_if_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct lpa_if *lpa_if = file->private_data; struct audio_buffer *ab; const char __user *start = buf; int xfer, rc; struct sched_param s = { .sched_priority = 1 }; int old_prio = current->rt_priority; int old_policy = current->policy; int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE); /* just for this write, set us real-time */ if (!task_has_rt_policy(current)) { struct cred *new = prepare_creds(); cap_raise(new->cap_effective, CAP_SYS_NICE); commit_creds(new); if ((sched_setscheduler(current, SCHED_RR, &s)) < 0) pr_err("sched_setscheduler failed\n"); } mutex_lock(&lpa_if->lock); if (dma_buf_index < 2) { ab = lpa_if->audio_buf + dma_buf_index; if (copy_from_user(ab->data, buf, count)) { pr_err("copy from user failed\n"); rc = 0; goto end; } mb(); pr_debug("prefill: count %u audio_buf[%u].size %u\n", count, dma_buf_index, ab->size); ab->used = 1; dma_buf_index++; rc = count; goto end; } if (lpa_if->config != 1) { pr_err("AUDIO_START did not happen\n"); rc = 0; goto end; } while (count > 0) { ab = lpa_if->audio_buf + lpa_if->cpu_buf; rc = wait_event_timeout(lpa_if->wait, (ab->used == 0), 10 * HZ); if (!rc) { pr_err("wait_event_timeout failed\n"); rc = buf - start; goto end; } xfer = count; if (xfer > lpa_if->dma_period_sz) xfer = lpa_if->dma_period_sz; if (copy_from_user(ab->data, buf, xfer)) { pr_err("copy from user failed\n"); rc = buf - start; goto end; } mb(); buf += xfer; count -= xfer; ab->used = 1; pr_debug("xfer %d, size %d, used %d cpu_buf %d\n", xfer, ab->size, ab->used, lpa_if->cpu_buf); lpa_if->cpu_buf++; lpa_if->cpu_buf = lpa_if->cpu_buf % lpa_if->cfg.buffer_count; } rc = buf - start; end: mutex_unlock(&lpa_if->lock); /* restore old scheduling policy */ if (!rt_policy(old_policy)) { struct sched_param v = { .sched_priority = old_prio }; if ((sched_setscheduler(current, old_policy, &v)) < 0) pr_err("sched_setscheduler failed\n"); if (likely(!cap_nice)) { struct cred *new = prepare_creds(); cap_lower(new->cap_effective, CAP_SYS_NICE); commit_creds(new); } } return rc; } static int lpa_if_release(struct inode *inode, struct file *file) { struct lpa_if *lpa_if = file->private_data; hdmi_audio_packet_enable(0); wait_for_dma_cnt_stop(lpa_if->dma_ch); hdmi_audio_enable(0, HDMI_AUDIO_FIFO_WATER_MARK); if (lpa_if->config) { unregister_dma_irq_handler(lpa_if->dma_ch); dai_stop_hdmi(lpa_if->dma_ch); lpa_if->config = 0; } core_req_bus_bandwith(AUDIO_IF_BUS_ID, 0, 0); if (hdmi_msm_audio_get_sample_rate() != HDMI_SAMPLE_RATE_48KHZ) hdmi_msm_audio_sample_rate_reset(HDMI_SAMPLE_RATE_48KHZ); return 0; } static const struct file_operations lpa_if_fops = { .owner = THIS_MODULE, .open = lpa_if_open, .write = lpa_if_write, .release = lpa_if_release, .unlocked_ioctl = lpa_if_ioctl, }; struct miscdevice lpa_if_misc = { .minor = MISC_DYNAMIC_MINOR, .name = "msm_lpa_if_out", .fops = &lpa_if_fops, }; static int __init lpa_if_init(void) { int rc; lpa_if_ptr = kzalloc(sizeof(struct lpa_if), GFP_KERNEL); if (!lpa_if_ptr) { pr_info("No mem for lpa-if\n"); return -ENOMEM; } mutex_init(&lpa_if_ptr->lock); init_waitqueue_head(&lpa_if_ptr->wait); lpa_if_ptr->buffer = dma_alloc_coherent(NULL, DMA_ALLOC_BUF_SZ, &(lpa_if_ptr->buffer_phys), GFP_KERNEL); if (!lpa_if_ptr->buffer) { pr_err("dma_alloc_coherent failed\n"); kfree(lpa_if_ptr); return -ENOMEM; } pr_info("lpa_if_ptr 0x%08x buf_vir 0x%08x buf_phy 0x%08x " " buf_zise %u\n", (u32)lpa_if_ptr, (u32)(lpa_if_ptr->buffer), lpa_if_ptr->buffer_phys, DMA_ALLOC_BUF_SZ); rc = misc_register(&lpa_if_misc); if (rc < 0) { pr_err("misc_register failed\n"); dma_free_coherent(NULL, DMA_ALLOC_BUF_SZ, lpa_if_ptr->buffer, lpa_if_ptr->buffer_phys); kfree(lpa_if_ptr); } return rc; } device_initcall(lpa_if_init);
static int hdmi_streamon(struct hdmi_device *hdev) { struct device *dev = hdev->dev; int ret; u32 val0, val1, val2; dev_dbg(dev, "%s\n", __func__); /* 3D test */ hdmi_set_infoframe(hdev); /* set packets for audio */ hdmi_set_packets(hdev); /* init audio */ #if defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_I2S) //printk("=============================> HDMI IIS\n"); hdmi_reg_i2s_audio_init(hdev); #elif defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_SPDIF) hdmi_reg_spdif_audio_init(hdev); #endif /* enbale HDMI audio */ if (hdev->audio_enable) { //printk("<+++++++++++++++++++++++++++++++++++++++++++ HDMI ENABLE\n"); hdmi_audio_enable(hdev, 1); //printk("<+++++++++++++++++++++++++++++++++++++++++++ HDMI ENABLE\n"); } hdmi_set_dvi_mode(hdev); /* controls the pixel value limitation */ hdmi_reg_set_limits(hdev); /* enable HDMI and timing generator */ hdmi_enable(hdev, 1); hdmi_tg_enable(hdev, 1); hdmi_reg_set_int_hpd(hdev); hdev->streaming = HDMI_STREAMING; // if (edid_supports_hdmi(hdev)) { #if 1 /* start HDCP if enabled */ if (hdev->hdcp_info.hdcp_enable) { ret = hdcp_start(hdev); if (ret) return ret; } #endif // } val0 = hdmi_read(hdev, HDMI_ACR_MCTS0); val1 = hdmi_read(hdev, HDMI_ACR_MCTS1); val2 = hdmi_read(hdev, HDMI_ACR_MCTS2); dev_dbg(dev, "HDMI_ACR_MCTS0 : 0x%08x\n", val0); dev_dbg(dev, "HDMI_ACR_MCTS1 : 0x%08x\n", val1); dev_dbg(dev, "HDMI_ACR_MCTS2 : 0x%08x\n", val2); hdmi_dumpregs(hdev, "streamon"); return 0; }
static int hdmi_streamon(struct hdmi_device *hdev) { struct device *dev = hdev->dev; struct hdmi_resources *res = &hdev->res; int ret, tries; u32 val0, val1, val2; dev_dbg(dev, "%s\n", __func__); hdev->streaming = 1; ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1); if (ret) return ret; /* waiting for HDMIPHY's PLL to get to steady state */ for (tries = 100; tries; --tries) { if (is_hdmiphy_ready(hdev)) break; mdelay(1); } /* steady state not achieved */ if (tries == 0) { dev_err(dev, "hdmiphy's pll could not reach steady state.\n"); v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); hdmi_dumpregs(hdev, "s_stream"); return -EIO; } /* hdmiphy clock is used for HDMI in streaming mode */ clk_disable(res->sclk_hdmi); clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy); clk_enable(res->sclk_hdmi); /* 3D test */ hdmi_set_infoframe(hdev); /* set packets for audio */ hdmi_set_packets(hdev); /* init audio */ #if defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_I2S) hdmi_reg_i2s_audio_init(hdev); #elif defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_SPDIF) hdmi_reg_spdif_audio_init(hdev); #endif /* enbale HDMI audio */ if (hdev->audio_enable) hdmi_audio_enable(hdev, 1); hdmi_set_dvi_mode(hdev); /* enable HDMI and timing generator */ hdmi_enable(hdev, 1); hdmi_tg_enable(hdev, 1); mdelay(5); val0 = hdmi_read(hdev, HDMI_ACR_MCTS0); val1 = hdmi_read(hdev, HDMI_ACR_MCTS1); val2 = hdmi_read(hdev, HDMI_ACR_MCTS2); dev_dbg(dev, "HDMI_ACR_MCTS0 : 0x%08x\n", val0); dev_dbg(dev, "HDMI_ACR_MCTS1 : 0x%08x\n", val1); dev_dbg(dev, "HDMI_ACR_MCTS2 : 0x%08x\n", val2); /* start HDCP if enabled */ if (hdev->hdcp_info.hdcp_enable) { ret = hdcp_start(hdev); if (ret) return ret; } hdmi_dumpregs(hdev, "streamon"); return 0; }