.. | .. |
---|
97 | 97 | |
---|
98 | 98 | #define TIMEOUT_MS 1000 |
---|
99 | 99 | |
---|
100 | | -struct dcmi_graph_entity { |
---|
101 | | - struct device_node *node; |
---|
| 100 | +#define OVERRUN_ERROR_THRESHOLD 3 |
---|
102 | 101 | |
---|
| 102 | +struct dcmi_graph_entity { |
---|
103 | 103 | struct v4l2_async_subdev asd; |
---|
104 | | - struct v4l2_subdev *subdev; |
---|
| 104 | + |
---|
| 105 | + struct device_node *remote_node; |
---|
| 106 | + struct v4l2_subdev *source; |
---|
105 | 107 | }; |
---|
106 | 108 | |
---|
107 | 109 | struct dcmi_format { |
---|
.. | .. |
---|
133 | 135 | int sequence; |
---|
134 | 136 | struct list_head buffers; |
---|
135 | 137 | struct dcmi_buf *active; |
---|
| 138 | + int irq; |
---|
136 | 139 | |
---|
137 | 140 | struct v4l2_device v4l2_dev; |
---|
138 | 141 | struct video_device *vdev; |
---|
.. | .. |
---|
167 | 170 | |
---|
168 | 171 | /* Ensure DMA operations atomicity */ |
---|
169 | 172 | struct mutex dma_lock; |
---|
| 173 | + |
---|
| 174 | + struct media_device mdev; |
---|
| 175 | + struct media_pad vid_cap_pad; |
---|
| 176 | + struct media_pipeline pipeline; |
---|
170 | 177 | }; |
---|
171 | 178 | |
---|
172 | 179 | static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) |
---|
.. | .. |
---|
446 | 453 | |
---|
447 | 454 | spin_lock_irq(&dcmi->irqlock); |
---|
448 | 455 | |
---|
449 | | - if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) { |
---|
450 | | - dcmi->errors_count++; |
---|
451 | | - if (dcmi->misr & IT_OVR) |
---|
452 | | - dcmi->overrun_count++; |
---|
| 456 | + if (dcmi->misr & IT_OVR) { |
---|
| 457 | + dcmi->overrun_count++; |
---|
| 458 | + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) |
---|
| 459 | + dcmi->errors_count++; |
---|
453 | 460 | } |
---|
| 461 | + if (dcmi->misr & IT_ERR) |
---|
| 462 | + dcmi->errors_count++; |
---|
454 | 463 | |
---|
455 | 464 | if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && |
---|
456 | 465 | dcmi->misr & IT_FRAME) { |
---|
.. | .. |
---|
576 | 585 | spin_unlock_irq(&dcmi->irqlock); |
---|
577 | 586 | } |
---|
578 | 587 | |
---|
| 588 | +static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi) |
---|
| 589 | +{ |
---|
| 590 | + struct media_entity *entity = &dcmi->vdev->entity; |
---|
| 591 | + struct media_pad *pad; |
---|
| 592 | + |
---|
| 593 | + /* Walk searching for entity having no sink */ |
---|
| 594 | + while (1) { |
---|
| 595 | + pad = &entity->pads[0]; |
---|
| 596 | + if (!(pad->flags & MEDIA_PAD_FL_SINK)) |
---|
| 597 | + break; |
---|
| 598 | + |
---|
| 599 | + pad = media_entity_remote_pad(pad); |
---|
| 600 | + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) |
---|
| 601 | + break; |
---|
| 602 | + |
---|
| 603 | + entity = pad->entity; |
---|
| 604 | + } |
---|
| 605 | + |
---|
| 606 | + return entity; |
---|
| 607 | +} |
---|
| 608 | + |
---|
| 609 | +static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, |
---|
| 610 | + struct v4l2_subdev_pad_config *pad_cfg, |
---|
| 611 | + struct v4l2_subdev_format *format) |
---|
| 612 | +{ |
---|
| 613 | + struct media_entity *entity = &dcmi->entity.source->entity; |
---|
| 614 | + struct v4l2_subdev *subdev; |
---|
| 615 | + struct media_pad *sink_pad = NULL; |
---|
| 616 | + struct media_pad *src_pad = NULL; |
---|
| 617 | + struct media_pad *pad = NULL; |
---|
| 618 | + struct v4l2_subdev_format fmt = *format; |
---|
| 619 | + bool found = false; |
---|
| 620 | + int ret; |
---|
| 621 | + |
---|
| 622 | + /* |
---|
| 623 | + * Starting from sensor subdevice, walk within |
---|
| 624 | + * pipeline and set format on each subdevice |
---|
| 625 | + */ |
---|
| 626 | + while (1) { |
---|
| 627 | + unsigned int i; |
---|
| 628 | + |
---|
| 629 | + /* Search if current entity has a source pad */ |
---|
| 630 | + for (i = 0; i < entity->num_pads; i++) { |
---|
| 631 | + pad = &entity->pads[i]; |
---|
| 632 | + if (pad->flags & MEDIA_PAD_FL_SOURCE) { |
---|
| 633 | + src_pad = pad; |
---|
| 634 | + found = true; |
---|
| 635 | + break; |
---|
| 636 | + } |
---|
| 637 | + } |
---|
| 638 | + if (!found) |
---|
| 639 | + break; |
---|
| 640 | + |
---|
| 641 | + subdev = media_entity_to_v4l2_subdev(entity); |
---|
| 642 | + |
---|
| 643 | + /* Propagate format on sink pad if any, otherwise source pad */ |
---|
| 644 | + if (sink_pad) |
---|
| 645 | + pad = sink_pad; |
---|
| 646 | + |
---|
| 647 | + dev_dbg(dcmi->dev, "\"%s\":%d pad format set to 0x%x %ux%u\n", |
---|
| 648 | + subdev->name, pad->index, format->format.code, |
---|
| 649 | + format->format.width, format->format.height); |
---|
| 650 | + |
---|
| 651 | + fmt.pad = pad->index; |
---|
| 652 | + ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt); |
---|
| 653 | + if (ret < 0) { |
---|
| 654 | + dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n", |
---|
| 655 | + __func__, format->format.code, |
---|
| 656 | + format->format.width, format->format.height, |
---|
| 657 | + subdev->name, pad->index, ret); |
---|
| 658 | + return ret; |
---|
| 659 | + } |
---|
| 660 | + |
---|
| 661 | + if (fmt.format.code != format->format.code || |
---|
| 662 | + fmt.format.width != format->format.width || |
---|
| 663 | + fmt.format.height != format->format.height) { |
---|
| 664 | + dev_dbg(dcmi->dev, "\"%s\":%d pad format has been changed to 0x%x %ux%u\n", |
---|
| 665 | + subdev->name, pad->index, fmt.format.code, |
---|
| 666 | + fmt.format.width, fmt.format.height); |
---|
| 667 | + } |
---|
| 668 | + |
---|
| 669 | + /* Walk to next entity */ |
---|
| 670 | + sink_pad = media_entity_remote_pad(src_pad); |
---|
| 671 | + if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity)) |
---|
| 672 | + break; |
---|
| 673 | + |
---|
| 674 | + entity = sink_pad->entity; |
---|
| 675 | + } |
---|
| 676 | + *format = fmt; |
---|
| 677 | + |
---|
| 678 | + return 0; |
---|
| 679 | +} |
---|
| 680 | + |
---|
| 681 | +static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state) |
---|
| 682 | +{ |
---|
| 683 | + struct media_entity *entity = &dcmi->vdev->entity; |
---|
| 684 | + struct v4l2_subdev *subdev; |
---|
| 685 | + struct media_pad *pad; |
---|
| 686 | + int ret; |
---|
| 687 | + |
---|
| 688 | + /* Start/stop all entities within pipeline */ |
---|
| 689 | + while (1) { |
---|
| 690 | + pad = &entity->pads[0]; |
---|
| 691 | + if (!(pad->flags & MEDIA_PAD_FL_SINK)) |
---|
| 692 | + break; |
---|
| 693 | + |
---|
| 694 | + pad = media_entity_remote_pad(pad); |
---|
| 695 | + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) |
---|
| 696 | + break; |
---|
| 697 | + |
---|
| 698 | + entity = pad->entity; |
---|
| 699 | + subdev = media_entity_to_v4l2_subdev(entity); |
---|
| 700 | + |
---|
| 701 | + ret = v4l2_subdev_call(subdev, video, s_stream, state); |
---|
| 702 | + if (ret < 0 && ret != -ENOIOCTLCMD) { |
---|
| 703 | + dev_err(dcmi->dev, "%s: \"%s\" failed to %s streaming (%d)\n", |
---|
| 704 | + __func__, subdev->name, |
---|
| 705 | + state ? "start" : "stop", ret); |
---|
| 706 | + return ret; |
---|
| 707 | + } |
---|
| 708 | + |
---|
| 709 | + dev_dbg(dcmi->dev, "\"%s\" is %s\n", |
---|
| 710 | + subdev->name, state ? "started" : "stopped"); |
---|
| 711 | + } |
---|
| 712 | + |
---|
| 713 | + return 0; |
---|
| 714 | +} |
---|
| 715 | + |
---|
| 716 | +static int dcmi_pipeline_start(struct stm32_dcmi *dcmi) |
---|
| 717 | +{ |
---|
| 718 | + return dcmi_pipeline_s_stream(dcmi, 1); |
---|
| 719 | +} |
---|
| 720 | + |
---|
| 721 | +static void dcmi_pipeline_stop(struct stm32_dcmi *dcmi) |
---|
| 722 | +{ |
---|
| 723 | + dcmi_pipeline_s_stream(dcmi, 0); |
---|
| 724 | +} |
---|
| 725 | + |
---|
579 | 726 | static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) |
---|
580 | 727 | { |
---|
581 | 728 | struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); |
---|
.. | .. |
---|
590 | 737 | goto err_pm_put; |
---|
591 | 738 | } |
---|
592 | 739 | |
---|
593 | | - /* Enable stream on the sub device */ |
---|
594 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 1); |
---|
595 | | - if (ret && ret != -ENOIOCTLCMD) { |
---|
596 | | - dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error", |
---|
597 | | - __func__); |
---|
| 740 | + ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); |
---|
| 741 | + if (ret < 0) { |
---|
| 742 | + dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n", |
---|
| 743 | + __func__, ret); |
---|
598 | 744 | goto err_pm_put; |
---|
599 | 745 | } |
---|
| 746 | + |
---|
| 747 | + ret = dcmi_pipeline_start(dcmi); |
---|
| 748 | + if (ret) |
---|
| 749 | + goto err_media_pipeline_stop; |
---|
600 | 750 | |
---|
601 | 751 | spin_lock_irq(&dcmi->irqlock); |
---|
602 | 752 | |
---|
.. | .. |
---|
669 | 819 | if (ret) { |
---|
670 | 820 | dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n", |
---|
671 | 821 | __func__); |
---|
672 | | - goto err_subdev_streamoff; |
---|
| 822 | + goto err_pipeline_stop; |
---|
673 | 823 | } |
---|
674 | 824 | |
---|
675 | 825 | /* Enable interruptions */ |
---|
676 | | - reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR); |
---|
| 826 | + if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) |
---|
| 827 | + reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR); |
---|
| 828 | + else |
---|
| 829 | + reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR); |
---|
677 | 830 | |
---|
678 | 831 | return 0; |
---|
679 | 832 | |
---|
680 | | -err_subdev_streamoff: |
---|
681 | | - v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); |
---|
| 833 | +err_pipeline_stop: |
---|
| 834 | + dcmi_pipeline_stop(dcmi); |
---|
| 835 | + |
---|
| 836 | +err_media_pipeline_stop: |
---|
| 837 | + media_pipeline_stop(&dcmi->vdev->entity); |
---|
682 | 838 | |
---|
683 | 839 | err_pm_put: |
---|
684 | 840 | pm_runtime_put(dcmi->dev); |
---|
.. | .. |
---|
701 | 857 | { |
---|
702 | 858 | struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); |
---|
703 | 859 | struct dcmi_buf *buf, *node; |
---|
704 | | - int ret; |
---|
705 | 860 | |
---|
706 | | - /* Disable stream on the sub device */ |
---|
707 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); |
---|
708 | | - if (ret && ret != -ENOIOCTLCMD) |
---|
709 | | - dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n", |
---|
710 | | - __func__, ret); |
---|
| 861 | + dcmi_pipeline_stop(dcmi); |
---|
| 862 | + |
---|
| 863 | + media_pipeline_stop(&dcmi->vdev->entity); |
---|
711 | 864 | |
---|
712 | 865 | spin_lock_irq(&dcmi->irqlock); |
---|
713 | 866 | |
---|
.. | .. |
---|
848 | 1001 | } |
---|
849 | 1002 | |
---|
850 | 1003 | v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); |
---|
851 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, |
---|
| 1004 | + ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt, |
---|
852 | 1005 | &pad_cfg, &format); |
---|
853 | 1006 | if (ret < 0) |
---|
854 | 1007 | return ret; |
---|
.. | .. |
---|
925 | 1078 | mf->width = sd_framesize.width; |
---|
926 | 1079 | mf->height = sd_framesize.height; |
---|
927 | 1080 | |
---|
928 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, |
---|
929 | | - set_fmt, NULL, &format); |
---|
| 1081 | + ret = dcmi_pipeline_s_fmt(dcmi, NULL, &format); |
---|
930 | 1082 | if (ret < 0) |
---|
931 | 1083 | return ret; |
---|
932 | 1084 | |
---|
.. | .. |
---|
982 | 1134 | }; |
---|
983 | 1135 | int ret; |
---|
984 | 1136 | |
---|
985 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_fmt, NULL, &fmt); |
---|
| 1137 | + ret = v4l2_subdev_call(dcmi->entity.source, pad, get_fmt, NULL, &fmt); |
---|
986 | 1138 | if (ret) |
---|
987 | 1139 | return ret; |
---|
988 | 1140 | |
---|
.. | .. |
---|
1011 | 1163 | } |
---|
1012 | 1164 | |
---|
1013 | 1165 | v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); |
---|
1014 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, |
---|
| 1166 | + ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt, |
---|
1015 | 1167 | &pad_cfg, &format); |
---|
1016 | 1168 | if (ret < 0) |
---|
1017 | 1169 | return ret; |
---|
.. | .. |
---|
1034 | 1186 | /* |
---|
1035 | 1187 | * Get sensor bounds first |
---|
1036 | 1188 | */ |
---|
1037 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_selection, |
---|
| 1189 | + ret = v4l2_subdev_call(dcmi->entity.source, pad, get_selection, |
---|
1038 | 1190 | NULL, &bounds); |
---|
1039 | 1191 | if (!ret) |
---|
1040 | 1192 | *r = bounds.r; |
---|
.. | .. |
---|
1167 | 1319 | static int dcmi_querycap(struct file *file, void *priv, |
---|
1168 | 1320 | struct v4l2_capability *cap) |
---|
1169 | 1321 | { |
---|
1170 | | - strlcpy(cap->driver, DRV_NAME, sizeof(cap->driver)); |
---|
1171 | | - strlcpy(cap->card, "STM32 Camera Memory Interface", |
---|
| 1322 | + strscpy(cap->driver, DRV_NAME, sizeof(cap->driver)); |
---|
| 1323 | + strscpy(cap->card, "STM32 Camera Memory Interface", |
---|
1172 | 1324 | sizeof(cap->card)); |
---|
1173 | | - strlcpy(cap->bus_info, "platform:dcmi", sizeof(cap->bus_info)); |
---|
| 1325 | + strscpy(cap->bus_info, "platform:dcmi", sizeof(cap->bus_info)); |
---|
1174 | 1326 | return 0; |
---|
1175 | 1327 | } |
---|
1176 | 1328 | |
---|
.. | .. |
---|
1181 | 1333 | return -EINVAL; |
---|
1182 | 1334 | |
---|
1183 | 1335 | i->type = V4L2_INPUT_TYPE_CAMERA; |
---|
1184 | | - strlcpy(i->name, "Camera", sizeof(i->name)); |
---|
| 1336 | + strscpy(i->name, "Camera", sizeof(i->name)); |
---|
1185 | 1337 | return 0; |
---|
1186 | 1338 | } |
---|
1187 | 1339 | |
---|
.. | .. |
---|
1215 | 1367 | |
---|
1216 | 1368 | fse.code = sd_fmt->mbus_code; |
---|
1217 | 1369 | |
---|
1218 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, enum_frame_size, |
---|
| 1370 | + ret = v4l2_subdev_call(dcmi->entity.source, pad, enum_frame_size, |
---|
1219 | 1371 | NULL, &fse); |
---|
1220 | 1372 | if (ret) |
---|
1221 | 1373 | return ret; |
---|
.. | .. |
---|
1232 | 1384 | { |
---|
1233 | 1385 | struct stm32_dcmi *dcmi = video_drvdata(file); |
---|
1234 | 1386 | |
---|
1235 | | - return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p); |
---|
| 1387 | + return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.source, p); |
---|
1236 | 1388 | } |
---|
1237 | 1389 | |
---|
1238 | 1390 | static int dcmi_s_parm(struct file *file, void *priv, |
---|
.. | .. |
---|
1240 | 1392 | { |
---|
1241 | 1393 | struct stm32_dcmi *dcmi = video_drvdata(file); |
---|
1242 | 1394 | |
---|
1243 | | - return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p); |
---|
| 1395 | + return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.source, p); |
---|
1244 | 1396 | } |
---|
1245 | 1397 | |
---|
1246 | 1398 | static int dcmi_enum_frameintervals(struct file *file, void *fh, |
---|
.. | .. |
---|
1262 | 1414 | |
---|
1263 | 1415 | fie.code = sd_fmt->mbus_code; |
---|
1264 | 1416 | |
---|
1265 | | - ret = v4l2_subdev_call(dcmi->entity.subdev, pad, |
---|
| 1417 | + ret = v4l2_subdev_call(dcmi->entity.source, pad, |
---|
1266 | 1418 | enum_frame_interval, NULL, &fie); |
---|
1267 | 1419 | if (ret) |
---|
1268 | 1420 | return ret; |
---|
.. | .. |
---|
1282 | 1434 | static int dcmi_open(struct file *file) |
---|
1283 | 1435 | { |
---|
1284 | 1436 | struct stm32_dcmi *dcmi = video_drvdata(file); |
---|
1285 | | - struct v4l2_subdev *sd = dcmi->entity.subdev; |
---|
| 1437 | + struct v4l2_subdev *sd = dcmi->entity.source; |
---|
1286 | 1438 | int ret; |
---|
1287 | 1439 | |
---|
1288 | 1440 | if (mutex_lock_interruptible(&dcmi->lock)) |
---|
.. | .. |
---|
1313 | 1465 | static int dcmi_release(struct file *file) |
---|
1314 | 1466 | { |
---|
1315 | 1467 | struct stm32_dcmi *dcmi = video_drvdata(file); |
---|
1316 | | - struct v4l2_subdev *sd = dcmi->entity.subdev; |
---|
| 1468 | + struct v4l2_subdev *sd = dcmi->entity.source; |
---|
1317 | 1469 | bool fh_singular; |
---|
1318 | 1470 | int ret; |
---|
1319 | 1471 | |
---|
.. | .. |
---|
1400 | 1552 | return 0; |
---|
1401 | 1553 | } |
---|
1402 | 1554 | |
---|
| 1555 | +/* |
---|
| 1556 | + * FIXME: For the time being we only support subdevices |
---|
| 1557 | + * which expose RGB & YUV "parallel form" mbus code (_2X8). |
---|
| 1558 | + * Nevertheless, this allows to support serial source subdevices |
---|
| 1559 | + * and serial to parallel bridges which conform to this. |
---|
| 1560 | + */ |
---|
1403 | 1561 | static const struct dcmi_format dcmi_formats[] = { |
---|
1404 | 1562 | { |
---|
1405 | 1563 | .fourcc = V4L2_PIX_FMT_RGB565, |
---|
.. | .. |
---|
1424 | 1582 | { |
---|
1425 | 1583 | const struct dcmi_format *sd_fmts[ARRAY_SIZE(dcmi_formats)]; |
---|
1426 | 1584 | unsigned int num_fmts = 0, i, j; |
---|
1427 | | - struct v4l2_subdev *subdev = dcmi->entity.subdev; |
---|
| 1585 | + struct v4l2_subdev *subdev = dcmi->entity.source; |
---|
1428 | 1586 | struct v4l2_subdev_mbus_code_enum mbus_code = { |
---|
1429 | 1587 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
---|
1430 | 1588 | }; |
---|
.. | .. |
---|
1438 | 1596 | /* Code supported, have we got this fourcc yet? */ |
---|
1439 | 1597 | for (j = 0; j < num_fmts; j++) |
---|
1440 | 1598 | if (sd_fmts[j]->fourcc == |
---|
1441 | | - dcmi_formats[i].fourcc) |
---|
| 1599 | + dcmi_formats[i].fourcc) { |
---|
1442 | 1600 | /* Already available */ |
---|
| 1601 | + dev_dbg(dcmi->dev, "Skipping fourcc/code: %4.4s/0x%x\n", |
---|
| 1602 | + (char *)&sd_fmts[j]->fourcc, |
---|
| 1603 | + mbus_code.code); |
---|
1443 | 1604 | break; |
---|
1444 | | - if (j == num_fmts) |
---|
| 1605 | + } |
---|
| 1606 | + if (j == num_fmts) { |
---|
1445 | 1607 | /* New */ |
---|
1446 | 1608 | sd_fmts[num_fmts++] = dcmi_formats + i; |
---|
| 1609 | + dev_dbg(dcmi->dev, "Supported fourcc/code: %4.4s/0x%x\n", |
---|
| 1610 | + (char *)&sd_fmts[num_fmts - 1]->fourcc, |
---|
| 1611 | + sd_fmts[num_fmts - 1]->mbus_code); |
---|
| 1612 | + } |
---|
1447 | 1613 | } |
---|
1448 | 1614 | mbus_code.index++; |
---|
1449 | 1615 | } |
---|
.. | .. |
---|
1470 | 1636 | static int dcmi_framesizes_init(struct stm32_dcmi *dcmi) |
---|
1471 | 1637 | { |
---|
1472 | 1638 | unsigned int num_fsize = 0; |
---|
1473 | | - struct v4l2_subdev *subdev = dcmi->entity.subdev; |
---|
| 1639 | + struct v4l2_subdev *subdev = dcmi->entity.source; |
---|
1474 | 1640 | struct v4l2_subdev_frame_size_enum fse = { |
---|
1475 | 1641 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
---|
1476 | 1642 | .code = dcmi->sd_format->mbus_code, |
---|
.. | .. |
---|
1517 | 1683 | struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); |
---|
1518 | 1684 | int ret; |
---|
1519 | 1685 | |
---|
1520 | | - dcmi->vdev->ctrl_handler = dcmi->entity.subdev->ctrl_handler; |
---|
| 1686 | + /* |
---|
| 1687 | + * Now that the graph is complete, |
---|
| 1688 | + * we search for the source subdevice |
---|
| 1689 | + * in order to expose it through V4L2 interface |
---|
| 1690 | + */ |
---|
| 1691 | + dcmi->entity.source = |
---|
| 1692 | + media_entity_to_v4l2_subdev(dcmi_find_source(dcmi)); |
---|
| 1693 | + if (!dcmi->entity.source) { |
---|
| 1694 | + dev_err(dcmi->dev, "Source subdevice not found\n"); |
---|
| 1695 | + return -ENODEV; |
---|
| 1696 | + } |
---|
| 1697 | + |
---|
| 1698 | + dcmi->vdev->ctrl_handler = dcmi->entity.source->ctrl_handler; |
---|
| 1699 | + |
---|
1521 | 1700 | ret = dcmi_formats_init(dcmi); |
---|
1522 | 1701 | if (ret) { |
---|
1523 | 1702 | dev_err(dcmi->dev, "No supported mediabus format found\n"); |
---|
.. | .. |
---|
1542 | 1721 | return ret; |
---|
1543 | 1722 | } |
---|
1544 | 1723 | |
---|
1545 | | - ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1); |
---|
| 1724 | + ret = devm_request_threaded_irq(dcmi->dev, dcmi->irq, dcmi_irq_callback, |
---|
| 1725 | + dcmi_irq_thread, IRQF_ONESHOT, |
---|
| 1726 | + dev_name(dcmi->dev), dcmi); |
---|
1546 | 1727 | if (ret) { |
---|
1547 | | - dev_err(dcmi->dev, "Failed to register video device\n"); |
---|
| 1728 | + dev_err(dcmi->dev, "Unable to request irq %d\n", dcmi->irq); |
---|
1548 | 1729 | return ret; |
---|
1549 | 1730 | } |
---|
1550 | 1731 | |
---|
1551 | | - dev_dbg(dcmi->dev, "Device registered as %s\n", |
---|
1552 | | - video_device_node_name(dcmi->vdev)); |
---|
1553 | 1732 | return 0; |
---|
1554 | 1733 | } |
---|
1555 | 1734 | |
---|
.. | .. |
---|
1561 | 1740 | |
---|
1562 | 1741 | dev_dbg(dcmi->dev, "Removing %s\n", video_device_node_name(dcmi->vdev)); |
---|
1563 | 1742 | |
---|
1564 | | - /* Checks internaly if vdev has been init or not */ |
---|
| 1743 | + /* Checks internally if vdev has been init or not */ |
---|
1565 | 1744 | video_unregister_device(dcmi->vdev); |
---|
1566 | 1745 | } |
---|
1567 | 1746 | |
---|
.. | .. |
---|
1570 | 1749 | struct v4l2_async_subdev *asd) |
---|
1571 | 1750 | { |
---|
1572 | 1751 | struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); |
---|
| 1752 | + unsigned int ret; |
---|
| 1753 | + int src_pad; |
---|
1573 | 1754 | |
---|
1574 | | - dev_dbg(dcmi->dev, "Subdev %s bound\n", subdev->name); |
---|
| 1755 | + dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); |
---|
1575 | 1756 | |
---|
1576 | | - dcmi->entity.subdev = subdev; |
---|
| 1757 | + /* |
---|
| 1758 | + * Link this sub-device to DCMI, it could be |
---|
| 1759 | + * a parallel camera sensor or a bridge |
---|
| 1760 | + */ |
---|
| 1761 | + src_pad = media_entity_get_fwnode_pad(&subdev->entity, |
---|
| 1762 | + subdev->fwnode, |
---|
| 1763 | + MEDIA_PAD_FL_SOURCE); |
---|
1577 | 1764 | |
---|
1578 | | - return 0; |
---|
| 1765 | + ret = media_create_pad_link(&subdev->entity, src_pad, |
---|
| 1766 | + &dcmi->vdev->entity, 0, |
---|
| 1767 | + MEDIA_LNK_FL_IMMUTABLE | |
---|
| 1768 | + MEDIA_LNK_FL_ENABLED); |
---|
| 1769 | + if (ret) |
---|
| 1770 | + dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n", |
---|
| 1771 | + subdev->name); |
---|
| 1772 | + else |
---|
| 1773 | + dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n", |
---|
| 1774 | + subdev->name); |
---|
| 1775 | + |
---|
| 1776 | + return ret; |
---|
1579 | 1777 | } |
---|
1580 | 1778 | |
---|
1581 | 1779 | static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = { |
---|
.. | .. |
---|
1599 | 1797 | return -EINVAL; |
---|
1600 | 1798 | |
---|
1601 | 1799 | /* Remote node to connect */ |
---|
1602 | | - dcmi->entity.node = remote; |
---|
| 1800 | + dcmi->entity.remote_node = remote; |
---|
1603 | 1801 | dcmi->entity.asd.match_type = V4L2_ASYNC_MATCH_FWNODE; |
---|
1604 | 1802 | dcmi->entity.asd.match.fwnode = of_fwnode_handle(remote); |
---|
1605 | 1803 | return 0; |
---|
.. | .. |
---|
1607 | 1805 | |
---|
1608 | 1806 | static int dcmi_graph_init(struct stm32_dcmi *dcmi) |
---|
1609 | 1807 | { |
---|
1610 | | - struct v4l2_async_subdev **subdevs = NULL; |
---|
1611 | 1808 | int ret; |
---|
1612 | 1809 | |
---|
1613 | 1810 | /* Parse the graph to extract a list of subdevice DT nodes. */ |
---|
1614 | 1811 | ret = dcmi_graph_parse(dcmi, dcmi->dev->of_node); |
---|
1615 | 1812 | if (ret < 0) { |
---|
1616 | | - dev_err(dcmi->dev, "Graph parsing failed\n"); |
---|
| 1813 | + dev_err(dcmi->dev, "Failed to parse graph\n"); |
---|
1617 | 1814 | return ret; |
---|
1618 | 1815 | } |
---|
1619 | 1816 | |
---|
1620 | | - /* Register the subdevices notifier. */ |
---|
1621 | | - subdevs = devm_kzalloc(dcmi->dev, sizeof(*subdevs), GFP_KERNEL); |
---|
1622 | | - if (!subdevs) { |
---|
1623 | | - of_node_put(dcmi->entity.node); |
---|
1624 | | - return -ENOMEM; |
---|
| 1817 | + v4l2_async_notifier_init(&dcmi->notifier); |
---|
| 1818 | + |
---|
| 1819 | + ret = v4l2_async_notifier_add_subdev(&dcmi->notifier, |
---|
| 1820 | + &dcmi->entity.asd); |
---|
| 1821 | + if (ret) { |
---|
| 1822 | + dev_err(dcmi->dev, "Failed to add subdev notifier\n"); |
---|
| 1823 | + of_node_put(dcmi->entity.remote_node); |
---|
| 1824 | + return ret; |
---|
1625 | 1825 | } |
---|
1626 | 1826 | |
---|
1627 | | - subdevs[0] = &dcmi->entity.asd; |
---|
1628 | | - |
---|
1629 | | - dcmi->notifier.subdevs = subdevs; |
---|
1630 | | - dcmi->notifier.num_subdevs = 1; |
---|
1631 | 1827 | dcmi->notifier.ops = &dcmi_graph_notify_ops; |
---|
1632 | 1828 | |
---|
1633 | 1829 | ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier); |
---|
1634 | 1830 | if (ret < 0) { |
---|
1635 | | - dev_err(dcmi->dev, "Notifier registration failed\n"); |
---|
1636 | | - of_node_put(dcmi->entity.node); |
---|
| 1831 | + dev_err(dcmi->dev, "Failed to register notifier\n"); |
---|
| 1832 | + v4l2_async_notifier_cleanup(&dcmi->notifier); |
---|
1637 | 1833 | return ret; |
---|
1638 | 1834 | } |
---|
1639 | 1835 | |
---|
.. | .. |
---|
1644 | 1840 | { |
---|
1645 | 1841 | struct device_node *np = pdev->dev.of_node; |
---|
1646 | 1842 | const struct of_device_id *match = NULL; |
---|
1647 | | - struct v4l2_fwnode_endpoint ep; |
---|
| 1843 | + struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; |
---|
1648 | 1844 | struct stm32_dcmi *dcmi; |
---|
1649 | 1845 | struct vb2_queue *q; |
---|
1650 | 1846 | struct dma_chan *chan; |
---|
.. | .. |
---|
1672 | 1868 | np = of_graph_get_next_endpoint(np, NULL); |
---|
1673 | 1869 | if (!np) { |
---|
1674 | 1870 | dev_err(&pdev->dev, "Could not find the endpoint\n"); |
---|
1675 | | - of_node_put(np); |
---|
1676 | 1871 | return -ENODEV; |
---|
1677 | 1872 | } |
---|
1678 | 1873 | |
---|
.. | .. |
---|
1683 | 1878 | return ret; |
---|
1684 | 1879 | } |
---|
1685 | 1880 | |
---|
1686 | | - if (ep.bus_type == V4L2_MBUS_CSI2) { |
---|
| 1881 | + if (ep.bus_type == V4L2_MBUS_CSI2_DPHY) { |
---|
1687 | 1882 | dev_err(&pdev->dev, "CSI bus not supported\n"); |
---|
1688 | 1883 | return -ENODEV; |
---|
1689 | 1884 | } |
---|
.. | .. |
---|
1692 | 1887 | dcmi->bus.data_shift = ep.bus.parallel.data_shift; |
---|
1693 | 1888 | |
---|
1694 | 1889 | irq = platform_get_irq(pdev, 0); |
---|
1695 | | - if (irq <= 0) { |
---|
1696 | | - if (irq != -EPROBE_DEFER) |
---|
1697 | | - dev_err(&pdev->dev, "Could not get irq\n"); |
---|
| 1890 | + if (irq <= 0) |
---|
1698 | 1891 | return irq ? irq : -ENXIO; |
---|
1699 | | - } |
---|
| 1892 | + |
---|
| 1893 | + dcmi->irq = irq; |
---|
1700 | 1894 | |
---|
1701 | 1895 | dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
1702 | 1896 | if (!dcmi->res) { |
---|
.. | .. |
---|
1710 | 1904 | return PTR_ERR(dcmi->regs); |
---|
1711 | 1905 | } |
---|
1712 | 1906 | |
---|
1713 | | - ret = devm_request_threaded_irq(&pdev->dev, irq, dcmi_irq_callback, |
---|
1714 | | - dcmi_irq_thread, IRQF_ONESHOT, |
---|
1715 | | - dev_name(&pdev->dev), dcmi); |
---|
1716 | | - if (ret) { |
---|
1717 | | - dev_err(&pdev->dev, "Unable to request irq %d\n", irq); |
---|
1718 | | - return ret; |
---|
1719 | | - } |
---|
1720 | | - |
---|
1721 | 1907 | mclk = devm_clk_get(&pdev->dev, "mclk"); |
---|
1722 | 1908 | if (IS_ERR(mclk)) { |
---|
1723 | 1909 | if (PTR_ERR(mclk) != -EPROBE_DEFER) |
---|
.. | .. |
---|
1725 | 1911 | return PTR_ERR(mclk); |
---|
1726 | 1912 | } |
---|
1727 | 1913 | |
---|
1728 | | - chan = dma_request_slave_channel(&pdev->dev, "tx"); |
---|
1729 | | - if (!chan) { |
---|
1730 | | - dev_info(&pdev->dev, "Unable to request DMA channel, defer probing\n"); |
---|
1731 | | - return -EPROBE_DEFER; |
---|
| 1914 | + chan = dma_request_chan(&pdev->dev, "tx"); |
---|
| 1915 | + if (IS_ERR(chan)) { |
---|
| 1916 | + ret = PTR_ERR(chan); |
---|
| 1917 | + if (ret != -EPROBE_DEFER) |
---|
| 1918 | + dev_err(&pdev->dev, |
---|
| 1919 | + "Failed to request DMA channel: %d\n", ret); |
---|
| 1920 | + return ret; |
---|
1732 | 1921 | } |
---|
1733 | 1922 | |
---|
1734 | 1923 | spin_lock_init(&dcmi->irqlock); |
---|
.. | .. |
---|
1744 | 1933 | |
---|
1745 | 1934 | q = &dcmi->queue; |
---|
1746 | 1935 | |
---|
| 1936 | + dcmi->v4l2_dev.mdev = &dcmi->mdev; |
---|
| 1937 | + |
---|
| 1938 | + /* Initialize media device */ |
---|
| 1939 | + strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model)); |
---|
| 1940 | + snprintf(dcmi->mdev.bus_info, sizeof(dcmi->mdev.bus_info), |
---|
| 1941 | + "platform:%s", DRV_NAME); |
---|
| 1942 | + dcmi->mdev.dev = &pdev->dev; |
---|
| 1943 | + media_device_init(&dcmi->mdev); |
---|
| 1944 | + |
---|
1747 | 1945 | /* Initialize the top-level structure */ |
---|
1748 | 1946 | ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev); |
---|
1749 | 1947 | if (ret) |
---|
1750 | | - goto err_dma_release; |
---|
| 1948 | + goto err_media_device_cleanup; |
---|
1751 | 1949 | |
---|
1752 | 1950 | dcmi->vdev = video_device_alloc(); |
---|
1753 | 1951 | if (!dcmi->vdev) { |
---|
.. | .. |
---|
1759 | 1957 | dcmi->vdev->fops = &dcmi_fops; |
---|
1760 | 1958 | dcmi->vdev->v4l2_dev = &dcmi->v4l2_dev; |
---|
1761 | 1959 | dcmi->vdev->queue = &dcmi->queue; |
---|
1762 | | - strlcpy(dcmi->vdev->name, KBUILD_MODNAME, sizeof(dcmi->vdev->name)); |
---|
| 1960 | + strscpy(dcmi->vdev->name, KBUILD_MODNAME, sizeof(dcmi->vdev->name)); |
---|
1763 | 1961 | dcmi->vdev->release = video_device_release; |
---|
1764 | 1962 | dcmi->vdev->ioctl_ops = &dcmi_ioctl_ops; |
---|
1765 | 1963 | dcmi->vdev->lock = &dcmi->lock; |
---|
1766 | 1964 | dcmi->vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | |
---|
1767 | 1965 | V4L2_CAP_READWRITE; |
---|
1768 | 1966 | video_set_drvdata(dcmi->vdev, dcmi); |
---|
| 1967 | + |
---|
| 1968 | + /* Media entity pads */ |
---|
| 1969 | + dcmi->vid_cap_pad.flags = MEDIA_PAD_FL_SINK; |
---|
| 1970 | + ret = media_entity_pads_init(&dcmi->vdev->entity, |
---|
| 1971 | + 1, &dcmi->vid_cap_pad); |
---|
| 1972 | + if (ret) { |
---|
| 1973 | + dev_err(dcmi->dev, "Failed to init media entity pad\n"); |
---|
| 1974 | + goto err_device_release; |
---|
| 1975 | + } |
---|
| 1976 | + dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; |
---|
| 1977 | + |
---|
| 1978 | + ret = video_register_device(dcmi->vdev, VFL_TYPE_VIDEO, -1); |
---|
| 1979 | + if (ret) { |
---|
| 1980 | + dev_err(dcmi->dev, "Failed to register video device\n"); |
---|
| 1981 | + goto err_media_entity_cleanup; |
---|
| 1982 | + } |
---|
| 1983 | + |
---|
| 1984 | + dev_dbg(dcmi->dev, "Device registered as %s\n", |
---|
| 1985 | + video_device_node_name(dcmi->vdev)); |
---|
1769 | 1986 | |
---|
1770 | 1987 | /* Buffer queue */ |
---|
1771 | 1988 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
---|
.. | .. |
---|
1782 | 1999 | ret = vb2_queue_init(q); |
---|
1783 | 2000 | if (ret < 0) { |
---|
1784 | 2001 | dev_err(&pdev->dev, "Failed to initialize vb2 queue\n"); |
---|
1785 | | - goto err_device_release; |
---|
| 2002 | + goto err_media_entity_cleanup; |
---|
1786 | 2003 | } |
---|
1787 | 2004 | |
---|
1788 | 2005 | ret = dcmi_graph_init(dcmi); |
---|
1789 | 2006 | if (ret < 0) |
---|
1790 | | - goto err_device_release; |
---|
| 2007 | + goto err_media_entity_cleanup; |
---|
1791 | 2008 | |
---|
1792 | 2009 | /* Reset device */ |
---|
1793 | 2010 | ret = reset_control_assert(dcmi->rstc); |
---|
1794 | 2011 | if (ret) { |
---|
1795 | 2012 | dev_err(&pdev->dev, "Failed to assert the reset line\n"); |
---|
1796 | | - goto err_device_release; |
---|
| 2013 | + goto err_cleanup; |
---|
1797 | 2014 | } |
---|
1798 | 2015 | |
---|
1799 | 2016 | usleep_range(3000, 5000); |
---|
.. | .. |
---|
1801 | 2018 | ret = reset_control_deassert(dcmi->rstc); |
---|
1802 | 2019 | if (ret) { |
---|
1803 | 2020 | dev_err(&pdev->dev, "Failed to deassert the reset line\n"); |
---|
1804 | | - goto err_device_release; |
---|
| 2021 | + goto err_cleanup; |
---|
1805 | 2022 | } |
---|
1806 | 2023 | |
---|
1807 | 2024 | dev_info(&pdev->dev, "Probe done\n"); |
---|
.. | .. |
---|
1812 | 2029 | |
---|
1813 | 2030 | return 0; |
---|
1814 | 2031 | |
---|
| 2032 | +err_cleanup: |
---|
| 2033 | + v4l2_async_notifier_cleanup(&dcmi->notifier); |
---|
| 2034 | +err_media_entity_cleanup: |
---|
| 2035 | + media_entity_cleanup(&dcmi->vdev->entity); |
---|
1815 | 2036 | err_device_release: |
---|
1816 | 2037 | video_device_release(dcmi->vdev); |
---|
1817 | 2038 | err_device_unregister: |
---|
1818 | 2039 | v4l2_device_unregister(&dcmi->v4l2_dev); |
---|
1819 | | -err_dma_release: |
---|
| 2040 | +err_media_device_cleanup: |
---|
| 2041 | + media_device_cleanup(&dcmi->mdev); |
---|
1820 | 2042 | dma_release_channel(dcmi->dma_chan); |
---|
1821 | 2043 | |
---|
1822 | 2044 | return ret; |
---|
.. | .. |
---|
1829 | 2051 | pm_runtime_disable(&pdev->dev); |
---|
1830 | 2052 | |
---|
1831 | 2053 | v4l2_async_notifier_unregister(&dcmi->notifier); |
---|
| 2054 | + v4l2_async_notifier_cleanup(&dcmi->notifier); |
---|
| 2055 | + media_entity_cleanup(&dcmi->vdev->entity); |
---|
1832 | 2056 | v4l2_device_unregister(&dcmi->v4l2_dev); |
---|
| 2057 | + media_device_cleanup(&dcmi->mdev); |
---|
1833 | 2058 | |
---|
1834 | 2059 | dma_release_channel(dcmi->dma_chan); |
---|
1835 | 2060 | |
---|