diff options
Diffstat (limited to 'drivers/media/platform/soc_camera/atmel-isi.c')
-rw-r--r-- | drivers/media/platform/soc_camera/atmel-isi.c | 90 |
1 files changed, 78 insertions, 12 deletions
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 38c723aca438..3408b045b3f1 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -25,6 +25,7 @@ #include <media/atmel-isi.h> #include <media/soc_camera.h> #include <media/soc_mediabus.h> +#include <media/v4l2-of.h> #include <media/videobuf2-dma-contig.h> #define MAX_BUFFER_NUM 32 @@ -33,6 +34,7 @@ #define VID_LIMIT_BYTES (16 * 1024 * 1024) #define MIN_FRAME_RATE 15 #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) +#define ISI_DEFAULT_MCLK_FREQ 25000000 /* Frame buffer descriptor */ struct fbd { @@ -84,7 +86,7 @@ struct atmel_isi { struct clk *mck; unsigned int irq; - struct isi_platform_data *pdata; + struct isi_platform_data pdata; u16 width_flags; /* max 12 bits */ struct list_head video_buffer_list; @@ -350,7 +352,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK; /* Enable linked list */ - cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR; + cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR; /* Enable codec path and ISI */ ctrl = ISI_CTRL_CDC | ISI_CTRL_EN; @@ -795,7 +797,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) /* Make choises, based on platform preferences */ if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { - if (isi->pdata->hsync_act_low) + if (isi->pdata.hsync_act_low) common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; else common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; @@ -803,7 +805,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { - if (isi->pdata->vsync_act_low) + if (isi->pdata.vsync_act_low) common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; else common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; @@ -811,7 +813,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { - if (isi->pdata->pclk_act_falling) + if (isi->pdata.pclk_act_falling) common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; else common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; @@ -833,9 +835,9 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; - if (isi->pdata->has_emb_sync) + if (isi->pdata.has_emb_sync) cfg1 |= ISI_CFG1_EMB_SYNC; - if (isi->pdata->full_mode) + if (isi->pdata.full_mode) cfg1 |= ISI_CFG1_FULL_MODE; isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); @@ -876,6 +878,51 @@ static int atmel_isi_remove(struct platform_device *pdev) return 0; } +static int atmel_isi_probe_dt(struct atmel_isi *isi, + struct platform_device *pdev) +{ + struct device_node *np= pdev->dev.of_node; + struct v4l2_of_endpoint ep; + int err; + + /* Default settings for ISI */ + isi->pdata.full_mode = 1; + isi->pdata.mck_hz = ISI_DEFAULT_MCLK_FREQ; + isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; + + np = of_graph_get_next_endpoint(np, NULL); + if (!np) { + dev_err(&pdev->dev, "Could not find the endpoint\n"); + return -EINVAL; + } + + err = v4l2_of_parse_endpoint(np, &ep); + if (err) { + dev_err(&pdev->dev, "Could not parse the endpoint\n"); + goto err_probe_dt; + } + + switch (ep.bus.parallel.bus_width) { + case 8: + isi->pdata.data_width_flags = ISI_DATAWIDTH_8; + break; + case 10: + isi->pdata.data_width_flags = + ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10; + break; + default: + dev_err(&pdev->dev, "Unsupported bus width: %d\n", + ep.bus.parallel.bus_width); + err = -EINVAL; + goto err_probe_dt; + } + +err_probe_dt: + of_node_put(np); + + return err; +} + static int atmel_isi_probe(struct platform_device *pdev) { unsigned int irq; @@ -887,7 +934,7 @@ static int 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) && !pdev->dev.of_node) { dev_err(&pdev->dev, "No config available for Atmel ISI\n"); return -EINVAL; @@ -903,7 +950,14 @@ static int atmel_isi_probe(struct platform_device *pdev) if (IS_ERR(isi->pclk)) return PTR_ERR(isi->pclk); - isi->pdata = pdata; + if (pdata) { + memcpy(&isi->pdata, pdata, sizeof(isi->pdata)); + } else { + ret = atmel_isi_probe_dt(isi, pdev); + if (ret) + return ret; + } + isi->active = NULL; spin_lock_init(&isi->lock); INIT_LIST_HEAD(&isi->video_buffer_list); @@ -919,7 +973,7 @@ static int atmel_isi_probe(struct platform_device *pdev) /* Set ISI_MCK's frequency, it should be faster than pixel * clock. */ - ret = clk_set_rate(isi->mck, pdata->mck_hz); + ret = clk_set_rate(isi->mck, isi->pdata.mck_hz); if (ret < 0) return ret; } @@ -953,9 +1007,9 @@ static int atmel_isi_probe(struct platform_device *pdev) goto err_ioremap; } - if (pdata->data_width_flags & ISI_DATAWIDTH_8) + if (isi->pdata.data_width_flags & ISI_DATAWIDTH_8) isi->width_flags = 1 << 7; - if (pdata->data_width_flags & ISI_DATAWIDTH_10) + if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10) isi->width_flags |= 1 << 9; isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); @@ -980,6 +1034,11 @@ static int atmel_isi_probe(struct platform_device *pdev) soc_host->v4l2_dev.dev = &pdev->dev; soc_host->nr = pdev->id; + if (isi->pdata.asd_sizes) { + soc_host->asd = isi->pdata.asd; + soc_host->asd_sizes = isi->pdata.asd_sizes; + } + ret = soc_camera_host_register(soc_host); if (ret) { dev_err(&pdev->dev, "Unable to register soc camera host\n"); @@ -1000,11 +1059,18 @@ err_alloc_ctx: return ret; } +static const struct of_device_id atmel_isi_of_match[] = { + { .compatible = "atmel,at91sam9g45-isi" }, + { } +}; +MODULE_DEVICE_TABLE(of, atmel_isi_of_match); + static struct platform_driver atmel_isi_driver = { .remove = atmel_isi_remove, .driver = { .name = "atmel_isi", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_isi_of_match), }, }; |