| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2009 Texas Instruments Inc |
|---|
| 3 | 4 | * Copyright (C) 2014 Lad, Prabhakar <prabhakar.csengg@gmail.com> |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 6 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 7 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 8 | | - * (at your option) any later version. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | 5 | * |
|---|
| 15 | 6 | * TODO : add support for VBI & HBI data service |
|---|
| 16 | 7 | * add static buffer allocation |
|---|
| .. | .. |
|---|
| 947 | 938 | } |
|---|
| 948 | 939 | |
|---|
| 949 | 940 | /* Fill in the information about format */ |
|---|
| 950 | | - if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { |
|---|
| 951 | | - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
|---|
| 952 | | - strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb"); |
|---|
| 941 | + if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) |
|---|
| 953 | 942 | fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; |
|---|
| 954 | | - } else { |
|---|
| 955 | | - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
|---|
| 956 | | - strcpy(fmt->description, "YCbCr4:2:2 Semi-Planar"); |
|---|
| 943 | + else |
|---|
| 957 | 944 | fmt->pixelformat = V4L2_PIX_FMT_NV16; |
|---|
| 958 | | - } |
|---|
| 959 | 945 | return 0; |
|---|
| 960 | 946 | } |
|---|
| 961 | 947 | |
|---|
| .. | .. |
|---|
| 986 | 972 | pixfmt->bytesperline = common->fmt.fmt.pix.width * 2; |
|---|
| 987 | 973 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; |
|---|
| 988 | 974 | } |
|---|
| 989 | | - pixfmt->priv = 0; |
|---|
| 990 | 975 | |
|---|
| 991 | 976 | dev_dbg(vpif_dev, "%s: %d x %d; pitch=%d pixelformat=0x%08x, field=%d, size=%d\n", __func__, |
|---|
| 992 | 977 | pixfmt->width, pixfmt->height, |
|---|
| .. | .. |
|---|
| 1092 | 1077 | { |
|---|
| 1093 | 1078 | struct vpif_capture_config *config = vpif_dev->platform_data; |
|---|
| 1094 | 1079 | |
|---|
| 1095 | | - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; |
|---|
| 1096 | | - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
|---|
| 1097 | | - strlcpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); |
|---|
| 1080 | + strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); |
|---|
| 1098 | 1081 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", |
|---|
| 1099 | 1082 | dev_name(vpif_dev)); |
|---|
| 1100 | | - strlcpy(cap->card, config->card_name, sizeof(cap->card)); |
|---|
| 1083 | + strscpy(cap->card, config->card_name, sizeof(cap->card)); |
|---|
| 1101 | 1084 | |
|---|
| 1102 | 1085 | return 0; |
|---|
| 1103 | 1086 | } |
|---|
| .. | .. |
|---|
| 1252 | 1235 | } else { |
|---|
| 1253 | 1236 | std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); |
|---|
| 1254 | 1237 | } |
|---|
| 1255 | | - strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME); |
|---|
| 1238 | + strscpy(std_info->name, "Custom timings BT656/1120", |
|---|
| 1239 | + sizeof(std_info->name)); |
|---|
| 1256 | 1240 | std_info->width = bt->width; |
|---|
| 1257 | 1241 | std_info->height = bt->height; |
|---|
| 1258 | 1242 | std_info->frm_fmt = bt->interlaced ? 0 : 1; |
|---|
| .. | .. |
|---|
| 1382 | 1366 | return err; |
|---|
| 1383 | 1367 | } |
|---|
| 1384 | 1368 | |
|---|
| 1369 | +static inline void free_vpif_objs(void) |
|---|
| 1370 | +{ |
|---|
| 1371 | + int i; |
|---|
| 1372 | + |
|---|
| 1373 | + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) |
|---|
| 1374 | + kfree(vpif_obj.dev[i]); |
|---|
| 1375 | +} |
|---|
| 1376 | + |
|---|
| 1385 | 1377 | static int vpif_async_bound(struct v4l2_async_notifier *notifier, |
|---|
| 1386 | 1378 | struct v4l2_subdev *subdev, |
|---|
| 1387 | 1379 | struct v4l2_async_subdev *asd) |
|---|
| .. | .. |
|---|
| 1463 | 1455 | |
|---|
| 1464 | 1456 | /* Initialize the video_device structure */ |
|---|
| 1465 | 1457 | vdev = &ch->video_dev; |
|---|
| 1466 | | - strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name)); |
|---|
| 1458 | + strscpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name)); |
|---|
| 1467 | 1459 | vdev->release = video_device_release_empty; |
|---|
| 1468 | 1460 | vdev->fops = &vpif_fops; |
|---|
| 1469 | 1461 | vdev->ioctl_ops = &vpif_ioctl_ops; |
|---|
| .. | .. |
|---|
| 1471 | 1463 | vdev->vfl_dir = VFL_DIR_RX; |
|---|
| 1472 | 1464 | vdev->queue = q; |
|---|
| 1473 | 1465 | vdev->lock = &common->lock; |
|---|
| 1466 | + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; |
|---|
| 1474 | 1467 | video_set_drvdata(&ch->video_dev, ch); |
|---|
| 1475 | 1468 | err = video_register_device(vdev, |
|---|
| 1476 | | - VFL_TYPE_GRABBER, (j ? 1 : 0)); |
|---|
| 1469 | + VFL_TYPE_VIDEO, (j ? 1 : 0)); |
|---|
| 1477 | 1470 | if (err) |
|---|
| 1478 | 1471 | goto probe_out; |
|---|
| 1479 | 1472 | } |
|---|
| .. | .. |
|---|
| 1489 | 1482 | /* Unregister video device */ |
|---|
| 1490 | 1483 | video_unregister_device(&ch->video_dev); |
|---|
| 1491 | 1484 | } |
|---|
| 1492 | | - kfree(vpif_obj.sd); |
|---|
| 1493 | | - v4l2_device_unregister(&vpif_obj.v4l2_dev); |
|---|
| 1494 | 1485 | |
|---|
| 1495 | 1486 | return err; |
|---|
| 1496 | 1487 | } |
|---|
| .. | .. |
|---|
| 1509 | 1500 | vpif_capture_get_pdata(struct platform_device *pdev) |
|---|
| 1510 | 1501 | { |
|---|
| 1511 | 1502 | struct device_node *endpoint = NULL; |
|---|
| 1512 | | - struct v4l2_fwnode_endpoint bus_cfg; |
|---|
| 1503 | + struct device_node *rem = NULL; |
|---|
| 1513 | 1504 | struct vpif_capture_config *pdata; |
|---|
| 1514 | 1505 | struct vpif_subdev_info *sdinfo; |
|---|
| 1515 | 1506 | struct vpif_capture_chan_config *chan; |
|---|
| 1516 | 1507 | unsigned int i; |
|---|
| 1508 | + |
|---|
| 1509 | + v4l2_async_notifier_init(&vpif_obj.notifier); |
|---|
| 1517 | 1510 | |
|---|
| 1518 | 1511 | /* |
|---|
| 1519 | 1512 | * DT boot: OF node from parent device contains |
|---|
| .. | .. |
|---|
| 1537 | 1530 | return NULL; |
|---|
| 1538 | 1531 | |
|---|
| 1539 | 1532 | for (i = 0; i < VPIF_CAPTURE_NUM_CHANNELS; i++) { |
|---|
| 1540 | | - struct device_node *rem; |
|---|
| 1533 | + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; |
|---|
| 1541 | 1534 | unsigned int flags; |
|---|
| 1542 | 1535 | int err; |
|---|
| 1543 | 1536 | |
|---|
| .. | .. |
|---|
| 1546 | 1539 | if (!endpoint) |
|---|
| 1547 | 1540 | break; |
|---|
| 1548 | 1541 | |
|---|
| 1542 | + rem = of_graph_get_remote_port_parent(endpoint); |
|---|
| 1543 | + if (!rem) { |
|---|
| 1544 | + dev_dbg(&pdev->dev, "Remote device at %pOF not found\n", |
|---|
| 1545 | + endpoint); |
|---|
| 1546 | + goto done; |
|---|
| 1547 | + } |
|---|
| 1548 | + |
|---|
| 1549 | 1549 | sdinfo = &pdata->subdev_info[i]; |
|---|
| 1550 | 1550 | chan = &pdata->chan_config[i]; |
|---|
| 1551 | 1551 | chan->inputs = devm_kcalloc(&pdev->dev, |
|---|
| .. | .. |
|---|
| 1553 | 1553 | sizeof(*chan->inputs), |
|---|
| 1554 | 1554 | GFP_KERNEL); |
|---|
| 1555 | 1555 | if (!chan->inputs) |
|---|
| 1556 | | - return NULL; |
|---|
| 1556 | + goto err_cleanup; |
|---|
| 1557 | 1557 | |
|---|
| 1558 | 1558 | chan->input_count++; |
|---|
| 1559 | 1559 | chan->inputs[i].input.type = V4L2_INPUT_TYPE_CAMERA; |
|---|
| .. | .. |
|---|
| 1564 | 1564 | &bus_cfg); |
|---|
| 1565 | 1565 | if (err) { |
|---|
| 1566 | 1566 | dev_err(&pdev->dev, "Could not parse the endpoint\n"); |
|---|
| 1567 | + of_node_put(rem); |
|---|
| 1567 | 1568 | goto done; |
|---|
| 1568 | 1569 | } |
|---|
| 1570 | + |
|---|
| 1569 | 1571 | dev_dbg(&pdev->dev, "Endpoint %pOF, bus_width = %d\n", |
|---|
| 1570 | 1572 | endpoint, bus_cfg.bus.parallel.bus_width); |
|---|
| 1573 | + |
|---|
| 1571 | 1574 | flags = bus_cfg.bus.parallel.flags; |
|---|
| 1572 | 1575 | |
|---|
| 1573 | 1576 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) |
|---|
| .. | .. |
|---|
| 1576 | 1579 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) |
|---|
| 1577 | 1580 | chan->vpif_if.vd_pol = 1; |
|---|
| 1578 | 1581 | |
|---|
| 1579 | | - rem = of_graph_get_remote_port_parent(endpoint); |
|---|
| 1580 | | - if (!rem) { |
|---|
| 1581 | | - dev_dbg(&pdev->dev, "Remote device at %pOF not found\n", |
|---|
| 1582 | | - endpoint); |
|---|
| 1583 | | - goto done; |
|---|
| 1584 | | - } |
|---|
| 1585 | | - |
|---|
| 1586 | | - dev_dbg(&pdev->dev, "Remote device %s, %pOF found\n", |
|---|
| 1587 | | - rem->name, rem); |
|---|
| 1582 | + dev_dbg(&pdev->dev, "Remote device %pOF found\n", rem); |
|---|
| 1588 | 1583 | sdinfo->name = rem->full_name; |
|---|
| 1589 | 1584 | |
|---|
| 1590 | | - pdata->asd[i] = devm_kzalloc(&pdev->dev, |
|---|
| 1591 | | - sizeof(struct v4l2_async_subdev), |
|---|
| 1592 | | - GFP_KERNEL); |
|---|
| 1593 | | - if (!pdata->asd[i]) { |
|---|
| 1594 | | - of_node_put(rem); |
|---|
| 1595 | | - pdata = NULL; |
|---|
| 1596 | | - goto done; |
|---|
| 1597 | | - } |
|---|
| 1585 | + pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev( |
|---|
| 1586 | + &vpif_obj.notifier, of_fwnode_handle(rem), |
|---|
| 1587 | + sizeof(struct v4l2_async_subdev)); |
|---|
| 1588 | + if (IS_ERR(pdata->asd[i])) |
|---|
| 1589 | + goto err_cleanup; |
|---|
| 1598 | 1590 | |
|---|
| 1599 | | - pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_FWNODE; |
|---|
| 1600 | | - pdata->asd[i]->match.fwnode = of_fwnode_handle(rem); |
|---|
| 1601 | 1591 | of_node_put(rem); |
|---|
| 1602 | 1592 | } |
|---|
| 1603 | 1593 | |
|---|
| 1604 | 1594 | done: |
|---|
| 1605 | | - if (pdata) { |
|---|
| 1606 | | - pdata->asd_sizes[0] = i; |
|---|
| 1607 | | - pdata->subdev_count = i; |
|---|
| 1608 | | - pdata->card_name = "DA850/OMAP-L138 Video Capture"; |
|---|
| 1609 | | - } |
|---|
| 1595 | + of_node_put(endpoint); |
|---|
| 1596 | + pdata->asd_sizes[0] = i; |
|---|
| 1597 | + pdata->subdev_count = i; |
|---|
| 1598 | + pdata->card_name = "DA850/OMAP-L138 Video Capture"; |
|---|
| 1610 | 1599 | |
|---|
| 1611 | 1600 | return pdata; |
|---|
| 1601 | + |
|---|
| 1602 | +err_cleanup: |
|---|
| 1603 | + of_node_put(rem); |
|---|
| 1604 | + of_node_put(endpoint); |
|---|
| 1605 | + v4l2_async_notifier_cleanup(&vpif_obj.notifier); |
|---|
| 1606 | + |
|---|
| 1607 | + return NULL; |
|---|
| 1612 | 1608 | } |
|---|
| 1613 | 1609 | |
|---|
| 1614 | 1610 | /** |
|---|
| .. | .. |
|---|
| 1633 | 1629 | return -EINVAL; |
|---|
| 1634 | 1630 | } |
|---|
| 1635 | 1631 | |
|---|
| 1636 | | - if (!pdev->dev.platform_data) { |
|---|
| 1637 | | - dev_warn(&pdev->dev, "Missing platform data. Giving up.\n"); |
|---|
| 1638 | | - return -EINVAL; |
|---|
| 1639 | | - } |
|---|
| 1640 | | - |
|---|
| 1641 | 1632 | vpif_dev = &pdev->dev; |
|---|
| 1642 | 1633 | |
|---|
| 1643 | 1634 | err = initialize_vpif(); |
|---|
| 1644 | 1635 | if (err) { |
|---|
| 1645 | 1636 | v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); |
|---|
| 1646 | | - return err; |
|---|
| 1637 | + goto cleanup; |
|---|
| 1647 | 1638 | } |
|---|
| 1648 | 1639 | |
|---|
| 1649 | 1640 | err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); |
|---|
| 1650 | 1641 | if (err) { |
|---|
| 1651 | 1642 | v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); |
|---|
| 1652 | | - return err; |
|---|
| 1643 | + goto vpif_free; |
|---|
| 1653 | 1644 | } |
|---|
| 1654 | 1645 | |
|---|
| 1655 | 1646 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { |
|---|
| .. | .. |
|---|
| 1696 | 1687 | "registered sub device %s\n", |
|---|
| 1697 | 1688 | subdevdata->name); |
|---|
| 1698 | 1689 | } |
|---|
| 1699 | | - vpif_probe_complete(); |
|---|
| 1690 | + err = vpif_probe_complete(); |
|---|
| 1691 | + if (err) |
|---|
| 1692 | + goto probe_subdev_out; |
|---|
| 1700 | 1693 | } else { |
|---|
| 1701 | | - vpif_obj.notifier.subdevs = vpif_obj.config->asd; |
|---|
| 1702 | | - vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0]; |
|---|
| 1703 | 1694 | vpif_obj.notifier.ops = &vpif_async_ops; |
|---|
| 1704 | 1695 | err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev, |
|---|
| 1705 | 1696 | &vpif_obj.notifier); |
|---|
| .. | .. |
|---|
| 1717 | 1708 | kfree(vpif_obj.sd); |
|---|
| 1718 | 1709 | vpif_unregister: |
|---|
| 1719 | 1710 | v4l2_device_unregister(&vpif_obj.v4l2_dev); |
|---|
| 1711 | +vpif_free: |
|---|
| 1712 | + free_vpif_objs(); |
|---|
| 1713 | +cleanup: |
|---|
| 1714 | + v4l2_async_notifier_cleanup(&vpif_obj.notifier); |
|---|
| 1720 | 1715 | |
|---|
| 1721 | 1716 | return err; |
|---|
| 1722 | 1717 | } |
|---|
| .. | .. |
|---|
| 1732 | 1727 | struct channel_obj *ch; |
|---|
| 1733 | 1728 | int i; |
|---|
| 1734 | 1729 | |
|---|
| 1730 | + v4l2_async_notifier_unregister(&vpif_obj.notifier); |
|---|
| 1731 | + v4l2_async_notifier_cleanup(&vpif_obj.notifier); |
|---|
| 1735 | 1732 | v4l2_device_unregister(&vpif_obj.v4l2_dev); |
|---|
| 1736 | 1733 | |
|---|
| 1737 | 1734 | kfree(vpif_obj.sd); |
|---|