diff options
Diffstat (limited to 'drivers/media/platform/soc_camera/atmel-isi.c')
| -rw-r--r-- | drivers/media/platform/soc_camera/atmel-isi.c | 187 | 
1 files changed, 56 insertions, 131 deletions
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 10448563250..38c723aca43 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -34,13 +34,6 @@  #define MIN_FRAME_RATE			15  #define FRAME_INTERVAL_MILLI_SEC	(1000 / MIN_FRAME_RATE) -/* ISI states */ -enum { -	ISI_STATE_IDLE = 0, -	ISI_STATE_READY, -	ISI_STATE_WAIT_SOF, -}; -  /* Frame buffer descriptor */  struct fbd {  	/* Physical address of the frame buffer */ @@ -75,11 +68,6 @@ struct atmel_isi {  	void __iomem			*regs;  	int				sequence; -	/* State of the ISI module in capturing mode */ -	int				state; - -	/* Wait queue for waiting for SOF */ -	wait_queue_head_t		vsync_wq;  	struct vb2_alloc_ctx		*alloc_ctx; @@ -124,16 +112,16 @@ static int configure_geometry(struct atmel_isi *isi, u32 width,  	case V4L2_MBUS_FMT_Y8_1X8:  		cr = ISI_CFG2_GRAYSCALE;  		break; -	case V4L2_MBUS_FMT_UYVY8_2X8: +	case V4L2_MBUS_FMT_VYUY8_2X8:  		cr = ISI_CFG2_YCC_SWAP_MODE_3;  		break; -	case V4L2_MBUS_FMT_VYUY8_2X8: +	case V4L2_MBUS_FMT_UYVY8_2X8:  		cr = ISI_CFG2_YCC_SWAP_MODE_2;  		break; -	case V4L2_MBUS_FMT_YUYV8_2X8: +	case V4L2_MBUS_FMT_YVYU8_2X8:  		cr = ISI_CFG2_YCC_SWAP_MODE_1;  		break; -	case V4L2_MBUS_FMT_YVYU8_2X8: +	case V4L2_MBUS_FMT_YUYV8_2X8:  		cr = ISI_CFG2_YCC_SWAP_DEFAULT;  		break;  	/* RGB, TODO */ @@ -144,6 +132,8 @@ static int configure_geometry(struct atmel_isi *isi, u32 width,  	isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);  	cfg2 = isi_readl(isi, ISI_CFG2); +	/* Set YCC swap mode */ +	cfg2 &= ~ISI_CFG2_YCC_SWAP_MODE_MASK;  	cfg2 |= cr;  	/* Set width */  	cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK); @@ -207,12 +197,6 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id)  		isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);  		ret = IRQ_HANDLED;  	} else { -		if ((pending & ISI_SR_VSYNC) && -				(isi->state == ISI_STATE_IDLE)) { -			isi->state = ISI_STATE_READY; -			wake_up_interruptible(&isi->vsync_wq); -			ret = IRQ_HANDLED; -		}  		if (likely(pending & ISI_SR_CXFR_DONE))  			ret = atmel_isi_handle_streaming(isi);  	} @@ -259,16 +243,6 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,  	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);  	struct atmel_isi *isi = ici->priv;  	unsigned long size; -	int ret; - -	/* Reset ISI */ -	ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); -	if (ret < 0) { -		dev_err(icd->parent, "Reset ISI timed out\n"); -		return ret; -	} -	/* Disable all interrupts */ -	isi_writel(isi, ISI_INTDIS, ~0UL);  	size = icd->sizeimage; @@ -374,6 +348,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)  	isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);  	isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); +	cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK;  	/* Enable linked list */  	cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR; @@ -407,47 +382,31 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)  	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);  	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);  	struct atmel_isi *isi = ici->priv; -  	u32 sr = 0;  	int ret; -	spin_lock_irq(&isi->lock); -	isi->state = ISI_STATE_IDLE; -	/* Clear any pending SOF interrupt */ -	sr = isi_readl(isi, ISI_STATUS); -	/* Enable VSYNC interrupt for SOF */ -	isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC); -	isi_writel(isi, ISI_CTRL, ISI_CTRL_EN); -	spin_unlock_irq(&isi->lock); - -	dev_dbg(icd->parent, "Waiting for SOF\n"); -	ret = wait_event_interruptible(isi->vsync_wq, -				       isi->state != ISI_STATE_IDLE); -	if (ret) -		goto err; - -	if (isi->state != ISI_STATE_READY) { -		ret = -EIO; -		goto err; +	/* Reset ISI */ +	ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); +	if (ret < 0) { +		dev_err(icd->parent, "Reset ISI timed out\n"); +		return ret;  	} +	/* Disable all interrupts */ +	isi_writel(isi, ISI_INTDIS, ~0UL);  	spin_lock_irq(&isi->lock); -	isi->state = ISI_STATE_WAIT_SOF; -	isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC); +	/* Clear any pending interrupt */ +	sr = isi_readl(isi, ISI_STATUS); +  	if (count)  		start_dma(isi, isi->active);  	spin_unlock_irq(&isi->lock);  	return 0; -err: -	isi->active = NULL; -	isi->sequence = 0; -	INIT_LIST_HEAD(&isi->video_buffer_list); -	return ret;  }  /* abort streaming and wait for last buffer */ -static int stop_streaming(struct vb2_queue *vq) +static void stop_streaming(struct vb2_queue *vq)  {  	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);  	struct soc_camera_host *ici = to_soc_camera_host(icd->parent); @@ -474,7 +433,7 @@ static int stop_streaming(struct vb2_queue *vq)  	if (time_after(jiffies, timeout)) {  		dev_err(icd->parent,  			"Timeout waiting for finishing codec request\n"); -		return -ETIMEDOUT; +		return;  	}  	/* Disable interrupts */ @@ -485,8 +444,6 @@ static int stop_streaming(struct vb2_queue *vq)  	ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE);  	if (ret < 0)  		dev_err(icd->parent, "Disable ISI timed out\n"); - -	return ret;  }  static struct vb2_ops isi_video_qops = { @@ -513,7 +470,7 @@ static int isi_camera_init_videobuf(struct vb2_queue *q,  	q->buf_struct_size = sizeof(struct frame_buffer);  	q->ops = &isi_video_qops;  	q->mem_ops = &vb2_dma_contig_memops; -	q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; +	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;  	return vb2_queue_init(q);  } @@ -765,14 +722,16 @@ static int isi_camera_clock_start(struct soc_camera_host *ici)  	struct atmel_isi *isi = ici->priv;  	int ret; -	ret = clk_enable(isi->pclk); +	ret = clk_prepare_enable(isi->pclk);  	if (ret)  		return ret; -	ret = clk_enable(isi->mck); -	if (ret) { -		clk_disable(isi->pclk); -		return ret; +	if (!IS_ERR(isi->mck)) { +		ret = clk_prepare_enable(isi->mck); +		if (ret) { +			clk_disable_unprepare(isi->pclk); +			return ret; +		}  	}  	return 0; @@ -783,8 +742,9 @@ static void isi_camera_clock_stop(struct soc_camera_host *ici)  {  	struct atmel_isi *isi = ici->priv; -	clk_disable(isi->mck); -	clk_disable(isi->pclk); +	if (!IS_ERR(isi->mck)) +		clk_disable_unprepare(isi->mck); +	clk_disable_unprepare(isi->pclk);  }  static unsigned int isi_camera_poll(struct file *file, poll_table *pt) @@ -906,7 +866,6 @@ static int atmel_isi_remove(struct platform_device *pdev)  	struct atmel_isi *isi = container_of(soc_host,  					struct atmel_isi, soc_host); -	free_irq(isi->irq, isi);  	soc_camera_host_unregister(soc_host);  	vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);  	dma_free_coherent(&pdev->dev, @@ -914,13 +873,6 @@ static int atmel_isi_remove(struct platform_device *pdev)  			isi->p_fb_descriptors,  			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); -  	return 0;  } @@ -928,7 +880,6 @@ static int atmel_isi_probe(struct platform_device *pdev)  {  	unsigned int irq;  	struct atmel_isi *isi; -	struct clk *pclk;  	struct resource *regs;  	int ret, i;  	struct device *dev = &pdev->dev; @@ -936,64 +887,50 @@ static int atmel_isi_probe(struct platform_device *pdev)  	struct isi_platform_data *pdata;  	pdata = dev->platform_data; -	if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) { +	if (!pdata || !pdata->data_width_flags) {  		dev_err(&pdev->dev,  			"No config available for Atmel ISI\n");  		return -EINVAL;  	} -	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!regs) -		return -ENXIO; - -	pclk = clk_get(&pdev->dev, "isi_clk"); -	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); +	isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL);  	if (!isi) { -		ret = -ENOMEM;  		dev_err(&pdev->dev, "Can't allocate interface!\n"); -		goto err_alloc_isi; +		return -ENOMEM;  	} -	isi->pclk = pclk; +	isi->pclk = devm_clk_get(&pdev->dev, "isi_clk"); +	if (IS_ERR(isi->pclk)) +		return PTR_ERR(isi->pclk); +  	isi->pdata = pdata;  	isi->active = NULL;  	spin_lock_init(&isi->lock); -	init_waitqueue_head(&isi->vsync_wq);  	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; +	/* ISI_MCK is the sensor master clock. It should be handled by the +	 * sensor driver directly, as the ISI has no use for that clock. Make +	 * the clock optional here while platforms transition to the correct +	 * model. +	 */ +	isi->mck = devm_clk_get(dev, "isi_mck"); +	if (!IS_ERR(isi->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) +			return ret;  	} -	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,  				GFP_KERNEL);  	if (!isi->p_fb_descriptors) { -		ret = -ENOMEM;  		dev_err(&pdev->dev, "Can't allocate descriptors!\n"); -		goto err_alloc_descriptors; +		return -ENOMEM;  	}  	for (i = 0; i < MAX_BUFFER_NUM; i++) { @@ -1009,9 +946,10 @@ static int atmel_isi_probe(struct platform_device *pdev)  		goto err_alloc_ctx;  	} -	isi->regs = ioremap(regs->start, resource_size(regs)); -	if (!isi->regs) { -		ret = -ENOMEM; +	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	isi->regs = devm_ioremap_resource(&pdev->dev, regs); +	if (IS_ERR(isi->regs)) { +		ret = PTR_ERR(isi->regs);  		goto err_ioremap;  	} @@ -1028,7 +966,7 @@ static int atmel_isi_probe(struct platform_device *pdev)  		goto err_req_irq;  	} -	ret = request_irq(irq, isi_interrupt, 0, "isi", isi); +	ret = devm_request_irq(&pdev->dev, irq, isi_interrupt, 0, "isi", isi);  	if (ret) {  		dev_err(&pdev->dev, "Unable to request irq %d\n", irq);  		goto err_req_irq; @@ -1050,9 +988,7 @@ static int atmel_isi_probe(struct platform_device *pdev)  	return 0;  err_register_soc_camera_host: -	free_irq(isi->irq, isi);  err_req_irq: -	iounmap(isi->regs);  err_ioremap:  	vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);  err_alloc_ctx: @@ -1060,17 +996,6 @@ err_alloc_ctx:  			sizeof(struct fbd) * MAX_BUFFER_NUM,  			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_unprepare(pclk); -err_clk_prepare_pclk: -	clk_put(pclk);  	return ret;  }  | 
