summaryrefslogtreecommitdiff
path: root/drivers/media/platform/st/stm32/stm32-dcmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/st/stm32/stm32-dcmi.c')
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmi.c135
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)