diff options
Diffstat (limited to 'drivers/media/video/atmel-isi.c')
-rw-r--r-- | drivers/media/video/atmel-isi.c | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 8c775c59e12..ec3f6a06f9c 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -90,7 +90,10 @@ struct atmel_isi { struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; struct completion complete; + /* ISI peripherial clock */ struct clk *pclk; + /* ISI_MCK, feed to camera sensor to generate pixel clock */ + struct clk *mck; unsigned int irq; struct isi_platform_data *pdata; @@ -766,6 +769,12 @@ static int isi_camera_add_device(struct soc_camera_device *icd) if (ret) return ret; + ret = clk_enable(isi->mck); + if (ret) { + clk_disable(isi->pclk); + return ret; + } + isi->icd = icd; dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n", icd->devnum); @@ -779,6 +788,7 @@ static void isi_camera_remove_device(struct soc_camera_device *icd) BUG_ON(icd != isi->icd); + clk_disable(isi->mck); clk_disable(isi->pclk); isi->icd = NULL; @@ -803,7 +813,7 @@ static int isi_camera_querycap(struct soc_camera_host *ici, return 0; } -static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) +static int isi_camera_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); @@ -874,7 +884,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) if (isi->pdata->has_emb_sync) cfg1 |= ISI_CFG1_EMB_SYNC; - if (isi->pdata->isi_full_mode) + if (isi->pdata->full_mode) cfg1 |= ISI_CFG1_FULL_MODE; isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); @@ -912,6 +922,9 @@ static int __devexit atmel_isi_remove(struct platform_device *pdev) isi->fb_descriptors_phys); iounmap(isi->regs); + clk_unprepare(isi->mck); + clk_put(isi->mck); + clk_unprepare(isi->pclk); clk_put(isi->pclk); kfree(isi); @@ -930,7 +943,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) struct isi_platform_data *pdata; pdata = dev->platform_data; - if (!pdata || !pdata->data_width_flags) { + if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) { dev_err(&pdev->dev, "No config available for Atmel ISI\n"); return -EINVAL; @@ -944,6 +957,10 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) if (IS_ERR(pclk)) return PTR_ERR(pclk); + ret = clk_prepare(pclk); + if (ret) + goto err_clk_prepare_pclk; + isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL); if (!isi) { ret = -ENOMEM; @@ -959,6 +976,23 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isi->video_buffer_list); INIT_LIST_HEAD(&isi->dma_desc_head); + /* Get ISI_MCK, provided by programmable clock or external clock */ + isi->mck = clk_get(dev, "isi_mck"); + if (IS_ERR(isi->mck)) { + dev_err(dev, "Failed to get isi_mck\n"); + ret = PTR_ERR(isi->mck); + goto err_clk_get; + } + + ret = clk_prepare(isi->mck); + if (ret) + goto err_clk_prepare_mck; + + /* Set ISI_MCK's frequency, it should be faster than pixel clock */ + ret = clk_set_rate(isi->mck, pdata->mck_hz); + if (ret < 0) + goto err_set_mck_rate; + isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, sizeof(struct fbd) * MAX_BUFFER_NUM, &isi->fb_descriptors_phys, @@ -1034,9 +1068,16 @@ err_alloc_ctx: isi->p_fb_descriptors, isi->fb_descriptors_phys); err_alloc_descriptors: +err_set_mck_rate: + clk_unprepare(isi->mck); +err_clk_prepare_mck: + clk_put(isi->mck); +err_clk_get: kfree(isi); err_alloc_isi: - clk_put(isi->pclk); + clk_unprepare(pclk); +err_clk_prepare_pclk: + clk_put(pclk); return ret; } |