diff options
Diffstat (limited to 'drivers/media/platform/st/stm32/stm32-dcmi.c')
| -rw-r--r-- | drivers/media/platform/st/stm32/stm32-dcmi.c | 135 |
1 files changed, 38 insertions, 97 deletions
diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index ad8e9742e1ae..13762861b769 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/of_graph.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> @@ -134,6 +133,7 @@ struct stm32_dcmi { struct video_device *vdev; struct v4l2_async_notifier notifier; struct v4l2_subdev *source; + struct v4l2_subdev *s_subdev; struct v4l2_format fmt; struct v4l2_rect crop; bool do_crop; @@ -388,9 +388,9 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi) ((dcmi->crop.left << 1)); reg_write(dcmi->regs, DCMI_CWSTRT, start); - dev_dbg(dcmi->dev, "Cropping to %ux%u@%u:%u\n", - dcmi->crop.width, dcmi->crop.height, - dcmi->crop.left, dcmi->crop.top); + dev_dbg(dcmi->dev, "Cropping to (%d,%d)/%ux%u\n", + dcmi->crop.left, dcmi->crop.top, + dcmi->crop.width, dcmi->crop.height); /* Enable crop */ reg_set(dcmi->regs, DCMI_CR, CR_CROP); @@ -692,51 +692,6 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, return 0; } -static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state) -{ - struct media_entity *entity = &dcmi->vdev->entity; - struct v4l2_subdev *subdev; - struct media_pad *pad; - int ret; - - /* Start/stop all entities within pipeline */ - while (1) { - pad = &entity->pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - pad = media_pad_remote_pad_first(pad); - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) - break; - - entity = pad->entity; - subdev = media_entity_to_v4l2_subdev(entity); - - ret = v4l2_subdev_call(subdev, video, s_stream, state); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_err(dcmi->dev, "%s: \"%s\" failed to %s streaming (%d)\n", - __func__, subdev->name, - state ? "start" : "stop", ret); - return ret; - } - - dev_dbg(dcmi->dev, "\"%s\" is %s\n", - subdev->name, state ? "started" : "stopped"); - } - - return 0; -} - -static int dcmi_pipeline_start(struct stm32_dcmi *dcmi) -{ - return dcmi_pipeline_s_stream(dcmi, 1); -} - -static void dcmi_pipeline_stop(struct stm32_dcmi *dcmi) -{ - dcmi_pipeline_s_stream(dcmi, 0); -} - static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) { struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); @@ -758,9 +713,12 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_pm_put; } - ret = dcmi_pipeline_start(dcmi); - if (ret) + ret = v4l2_subdev_call(dcmi->s_subdev, video, s_stream, 1); + if (ret < 0) { + dev_err(dcmi->dev, "%s: Failed to start source subdev, error (%d)\n", + __func__, ret); goto err_media_pipeline_stop; + } spin_lock_irq(&dcmi->irqlock); @@ -862,7 +820,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; err_pipeline_stop: - dcmi_pipeline_stop(dcmi); + v4l2_subdev_call(dcmi->s_subdev, video, s_stream, 0); err_media_pipeline_stop: video_device_pipeline_stop(dcmi->vdev); @@ -889,8 +847,12 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) { struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); struct dcmi_buf *buf, *node; + int ret; - dcmi_pipeline_stop(dcmi); + ret = v4l2_subdev_call(dcmi->s_subdev, video, s_stream, 0); + if (ret < 0) + dev_err(dcmi->dev, "%s: Failed to stop source subdev, error (%d)\n", + __func__, ret); video_device_pipeline_stop(dcmi->vdev); @@ -936,8 +898,6 @@ static const struct vb2_ops dcmi_video_qops = { .buf_queue = dcmi_buf_queue, .start_streaming = dcmi_start_streaming, .stop_streaming = dcmi_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int dcmi_g_fmt_vid_cap(struct file *file, void *priv, @@ -1332,8 +1292,8 @@ static int dcmi_s_selection(struct file *file, void *priv, /* Crop if request is different than sensor resolution */ dcmi->do_crop = true; dcmi->crop = r; - dev_dbg(dcmi->dev, "s_selection: crop %ux%u@(%u,%u) from %ux%u\n", - r.width, r.height, r.left, r.top, + dev_dbg(dcmi->dev, "s_selection: crop (%d,%d)/%ux%u from %ux%u\n", + r.left, r.top, r.width, r.height, pix.width, pix.height); } else { /* Disable crop */ @@ -1722,18 +1682,14 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) return -ENXIO; dcmi->num_of_sd_formats = num_fmts; - dcmi->sd_formats = devm_kcalloc(dcmi->dev, - num_fmts, sizeof(struct dcmi_format *), - GFP_KERNEL); + dcmi->sd_formats = devm_kmemdup_array(dcmi->dev, sd_fmts, num_fmts, + sizeof(*sd_fmts), GFP_KERNEL); if (!dcmi->sd_formats) { dev_err(dcmi->dev, "Could not allocate memory\n"); return -ENOMEM; } - memcpy(dcmi->sd_formats, sd_fmts, - num_fmts * sizeof(struct dcmi_format *)); dcmi->sd_format = dcmi->sd_formats[0]; - return 0; } @@ -1745,8 +1701,8 @@ static int dcmi_framesizes_init(struct stm32_dcmi *dcmi) .which = V4L2_SUBDEV_FORMAT_ACTIVE, .code = dcmi->sd_format->mbus_code, }; - unsigned int ret; unsigned int i; + int ret; /* Allocate discrete framesizes array */ while (!v4l2_subdev_call(subdev, pad, enum_frame_size, @@ -1837,7 +1793,7 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) static void dcmi_graph_notify_unbind(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) + struct v4l2_async_connection *asd) { struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); @@ -1849,11 +1805,11 @@ static void dcmi_graph_notify_unbind(struct v4l2_async_notifier *notifier, static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) + struct v4l2_async_connection *asd) { struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); - unsigned int ret; int src_pad; + int ret; dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); @@ -1876,6 +1832,8 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n", subdev->name); + dcmi->s_subdev = subdev; + return ret; } @@ -1887,21 +1845,21 @@ static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = { static int dcmi_graph_init(struct stm32_dcmi *dcmi) { - struct v4l2_async_subdev *asd; + struct v4l2_async_connection *asd; struct device_node *ep; int ret; - ep = of_graph_get_next_endpoint(dcmi->dev->of_node, NULL); + ep = of_graph_get_endpoint_by_regs(dcmi->dev->of_node, 0, -1); if (!ep) { dev_err(dcmi->dev, "Failed to get next endpoint\n"); return -EINVAL; } - v4l2_async_nf_init(&dcmi->notifier); + v4l2_async_nf_init(&dcmi->notifier, &dcmi->v4l2_dev); asd = v4l2_async_nf_add_fwnode_remote(&dcmi->notifier, of_fwnode_handle(ep), - struct v4l2_async_subdev); + struct v4l2_async_connection); of_node_put(ep); @@ -1912,7 +1870,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) dcmi->notifier.ops = &dcmi_graph_notify_ops; - ret = v4l2_async_nf_register(&dcmi->v4l2_dev, &dcmi->notifier); + ret = v4l2_async_nf_register(&dcmi->notifier); if (ret < 0) { dev_err(dcmi->dev, "Failed to register notifier\n"); v4l2_async_nf_cleanup(&dcmi->notifier); @@ -1925,22 +1883,14 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) static int dcmi_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match = NULL; struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; struct stm32_dcmi *dcmi; struct vb2_queue *q; struct dma_chan *chan; struct dma_slave_caps caps; struct clk *mclk; - int irq; int ret = 0; - match = of_match_device(of_match_ptr(stm32_dcmi_of_match), &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Could not find a match in devicetree\n"); - return -ENODEV; - } - dcmi = devm_kzalloc(&pdev->dev, sizeof(struct stm32_dcmi), GFP_KERNEL); if (!dcmi) return -ENOMEM; @@ -1951,7 +1901,7 @@ static int dcmi_probe(struct platform_device *pdev) "Could not get reset control\n"); /* Get bus characteristics from devicetree */ - np = of_graph_get_next_endpoint(np, NULL); + np = of_graph_get_endpoint_by_regs(np, 0, -1); if (!np) { dev_err(&pdev->dev, "Could not find the endpoint\n"); return -ENODEV; @@ -1981,19 +1931,11 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->bus.data_shift = ep.bus.parallel.data_shift; dcmi->bus_type = ep.bus_type; - irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return irq ? irq : -ENXIO; + dcmi->irq = platform_get_irq(pdev, 0); + if (dcmi->irq < 0) + return dcmi->irq; - dcmi->irq = irq; - - dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!dcmi->res) { - dev_err(&pdev->dev, "Could not get resource\n"); - return -ENODEV; - } - - dcmi->regs = devm_ioremap_resource(&pdev->dev, dcmi->res); + dcmi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &dcmi->res); if (IS_ERR(dcmi->regs)) return PTR_ERR(dcmi->regs); @@ -2083,7 +2025,8 @@ static int dcmi_probe(struct platform_device *pdev) q->ops = &dcmi_video_qops; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; + q->min_queued_buffers = 2; + q->allow_cache_hints = 1; q->dev = &pdev->dev; ret = vb2_queue_init(q); @@ -2134,7 +2077,7 @@ err_media_device_cleanup: return ret; } -static int dcmi_remove(struct platform_device *pdev) +static void dcmi_remove(struct platform_device *pdev) { struct stm32_dcmi *dcmi = platform_get_drvdata(pdev); @@ -2147,8 +2090,6 @@ static int dcmi_remove(struct platform_device *pdev) media_device_cleanup(&dcmi->mdev); dma_release_channel(dcmi->dma_chan); - - return 0; } static __maybe_unused int dcmi_runtime_suspend(struct device *dev) |
