[PATCH 13/13] atmel-isi: use an hw_data structure according compatible string

Josh Wu rainyfeeling at gmail.com
Mon Jan 18 04:52:25 PST 2016


From: Josh Wu <josh.wu at atmel.com>

The hw_data can define new hw_ops, hw_regs, which has all hardware related
data. That can make us easy to add another hardware support.

Also rename the hw related function with 'isi_' prefix.

Signed-off-by: Josh Wu <rainyfeeling at gmail.com>
---

 drivers/media/platform/soc_camera/atmel-isi.c | 88 ++++++++++++++++++++++-----
 1 file changed, 72 insertions(+), 16 deletions(-)

diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index b4c1f38..7f7be7d 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
@@ -91,6 +92,8 @@ struct atmel_isi {
 	struct frame_buffer		*active;
 
 	struct soc_camera_host		soc_host;
+	struct at91_camera_hw_ops	*hw_ops;
+	struct at91_camera_hw_regs	*hw_regs;
 };
 
 static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val)
@@ -102,6 +105,29 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg)
 	return readl(isi->regs + reg);
 }
 
+struct at91_camera_hw_ops {
+	/* start dma transfer */
+	void (*hw_start_dma)(struct atmel_isi *isi, struct frame_buffer *buf);
+	/* start ISI hardware capture */
+	void (*hw_start)(struct atmel_isi *isi);
+	int  (*hw_initialize)(struct atmel_isi *isi);
+	void (*hw_uninitialize)(struct atmel_isi *isi);
+	void (*hw_configure)(struct atmel_isi *isi, u32 width, u32 height,
+			     const struct soc_camera_format_xlate *xlate);
+	irqreturn_t (*hw_interrupt)(int irq, void *dev_id);
+	void (*hw_init_dma_desc)(union fbd *p_fdb, u32 fb_addr,
+			      u32 next_fbd_addr);
+};
+
+struct at91_camera_hw_regs {
+	u32 status_reg_offset;
+};
+
+struct at91_camera_hw_data {
+	struct at91_camera_hw_ops *hw_ops;
+	struct at91_camera_hw_regs *hw_regs;
+};
+
 static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi,
 		const struct soc_camera_format_xlate *xlate)
 {
@@ -140,7 +166,7 @@ static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi,
 	return ISI_CFG2_YCC_SWAP_DEFAULT;
 }
 
-static void configure_geometry(struct atmel_isi *isi, u32 width,
+static void isi_configure_geometry(struct atmel_isi *isi, u32 width,
 		u32 height, const struct soc_camera_format_xlate *xlate)
 {
 	u32 cfg2, psize;
@@ -192,8 +218,8 @@ static int isi_hw_wait_status(struct atmel_isi *isi, int status_flag,
 {
 	unsigned long timeout = jiffies + wait_ms * HZ;
 
-	while ((isi_readl(isi, ISI_STATUS) & status_flag) &&
-			time_before(jiffies, timeout))
+	while ((isi_readl(isi, isi->hw_regs->status_reg_offset) & status_flag)
+			&& time_before(jiffies, timeout))
 		msleep(1);
 
 	if (time_after(jiffies, timeout))
@@ -274,7 +300,7 @@ static void isi_hw_uninitialize(struct atmel_isi *isi)
 		dev_err(isi->soc_host.icd->parent, "Disable ISI timed out\n");
 }
 
-static void start_isi(struct atmel_isi *isi)
+static void isi_start(struct atmel_isi *isi)
 {
 	u32 ctrl;
 
@@ -288,7 +314,7 @@ static void start_isi(struct atmel_isi *isi)
 	isi_writel(isi, ISI_CTRL, ctrl);
 }
 
-static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
+static void isi_start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
 {
 	/* Check if already in a frame */
 	if (!isi->enable_preview_path) {
@@ -330,7 +356,8 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
 		/* start next dma frame. */
 		isi->active = list_entry(isi->video_buffer_list.next,
 					struct frame_buffer, list);
-		start_dma(isi, isi->active);
+
+		(*isi->hw_ops->hw_start_dma)(isi, isi->active);
 	}
 	return IRQ_HANDLED;
 }
@@ -419,6 +446,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
 	struct atmel_isi *isi = ici->priv;
 	unsigned long size;
 	struct isi_dma_desc *desc;
+	u32 vb_addr;
 
 	size = icd->sizeimage;
 
@@ -442,7 +470,8 @@ static int buffer_prepare(struct vb2_buffer *vb)
 			list_del_init(&desc->list);
 
 			/* Initialize the dma descriptor */
-			isi_hw_init_dma_desc(desc->p_fbd, vb2_dma_contig_plane_dma_addr(vb, 0), 0);
+			vb_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+			(*isi->hw_ops->hw_init_dma_desc)(desc->p_fbd, vb_addr, 0);
 
 			buf->p_dma_desc = desc;
 		}
@@ -478,7 +507,7 @@ static void buffer_queue(struct vb2_buffer *vb)
 	if (isi->active == NULL) {
 		isi->active = buf;
 		if (vb2_is_streaming(vb->vb2_queue))
-			start_dma(isi, buf);
+			(*isi->hw_ops->hw_start_dma)(isi, buf);
 	}
 	spin_unlock_irqrestore(&isi->lock, flags);
 }
@@ -492,20 +521,20 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
 
 	pm_runtime_get_sync(ici->v4l2_dev.dev);
 
-	ret = isi_hw_initialize(isi);
+	ret = (*isi->hw_ops->hw_initialize)(isi);
 	if (ret) {
 		pm_runtime_put(ici->v4l2_dev.dev);
 		return ret;
 	}
 
-	configure_geometry(isi, icd->user_width, icd->user_height,
-				icd->current_fmt);
+	(*isi->hw_ops->hw_configure)(isi, icd->user_width, icd->user_height,
+				     icd->current_fmt);
 
 	spin_lock_irq(&isi->lock);
 
 	if (count) {
-		start_dma(isi, isi->active);
-		start_isi(isi);
+		(*isi->hw_ops->hw_start_dma)(isi, isi->active);
+		(*isi->hw_ops->hw_start)(isi);
 	}
 
 	spin_unlock_irq(&isi->lock);
@@ -530,7 +559,7 @@ static void stop_streaming(struct vb2_queue *vq)
 	}
 	spin_unlock_irq(&isi->lock);
 
-	isi_hw_uninitialize(isi);
+	(*isi->hw_ops->hw_uninitialize)(isi);
 
 	pm_runtime_put(ici->v4l2_dev.dev);
 }
@@ -993,6 +1022,7 @@ static int atmel_isi_parse_dt(struct atmel_isi *isi,
 	return 0;
 }
 
+static const struct of_device_id atmel_isi_of_match[];
 static int atmel_isi_probe(struct platform_device *pdev)
 {
 	unsigned int irq;
@@ -1000,6 +1030,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
 	struct resource *regs;
 	int ret, i;
 	struct soc_camera_host *soc_host;
+	struct at91_camera_hw_data *hw_data;
 
 	isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL);
 	if (!isi) {
@@ -1015,6 +1046,11 @@ static int atmel_isi_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	hw_data = (struct at91_camera_hw_data *)
+		of_match_device(atmel_isi_of_match, &pdev->dev)->data;
+	isi->hw_ops = hw_data->hw_ops;
+	isi->hw_regs = hw_data->hw_regs;
+
 	isi->active = NULL;
 	spin_lock_init(&isi->lock);
 	INIT_LIST_HEAD(&isi->video_buffer_list);
@@ -1060,7 +1096,8 @@ static int atmel_isi_probe(struct platform_device *pdev)
 		goto err_req_irq;
 	}
 
-	ret = devm_request_irq(&pdev->dev, irq, isi_interrupt, 0, "isi", isi);
+	ret = devm_request_irq(&pdev->dev, irq, isi->hw_ops->hw_interrupt, 0,
+			       "isi", isi);
 	if (ret) {
 		dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
 		goto err_req_irq;
@@ -1119,13 +1156,32 @@ static int atmel_isi_runtime_resume(struct device *dev)
 }
 #endif /* CONFIG_PM */
 
+static struct at91_camera_hw_ops at91sam9g45_ops = {
+	.hw_initialize = isi_hw_initialize,
+	.hw_uninitialize = isi_hw_uninitialize,
+	.hw_configure = isi_configure_geometry,
+	.hw_start = isi_start,
+	.hw_start_dma = isi_start_dma,
+	.hw_interrupt = isi_interrupt,
+	.hw_init_dma_desc = isi_hw_init_dma_desc,
+};
+
+static struct at91_camera_hw_regs at91sam9g45_regs = {
+	.status_reg_offset = ISI_STATUS,
+};
+
+static struct at91_camera_hw_data at91sam9g45_data = {
+	.hw_ops = &at91sam9g45_ops,
+	.hw_regs = &at91sam9g45_regs,
+};
+
 static const struct dev_pm_ops atmel_isi_dev_pm_ops = {
 	SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend,
 				atmel_isi_runtime_resume, NULL)
 };
 
 static const struct of_device_id atmel_isi_of_match[] = {
-	{ .compatible = "atmel,at91sam9g45-isi" },
+	{ .compatible = "atmel,at91sam9g45-isi", .data = &at91sam9g45_data },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, atmel_isi_of_match);
-- 
1.9.1




More information about the linux-arm-kernel mailing list