Files
linux-nv-oot/drivers/video/tegra/host/isp/isp5.c
Jon Hunter f01227d4ea drivers: Drop inline from driver remove wrapper
The driver remove function is a function pointer and therefore, it does
not make sense to define the function as an 'inline'. Update the
coccinelle script and drivers to remove the inline statement.

Bug 4749580

Change-Id: Ia03691b75c4edffe609f27468b911a92a5ddbd68
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3233980
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
2025-07-24 10:19:08 +00:00

416 lines
9.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
#include <asm/ioctls.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <linux/nvhost.h>
#include <media/fusa-capture/capture-isp-channel.h>
#include <media/tegra_camera_platform.h>
#include <soc/tegra/camrtc-capture.h>
#include <soc/tegra/fuse-helper.h>
#include "isp5.h"
#include <uapi/linux/nvhost_isp_ioctl.h>
#include <uapi/linux/nvhost_ioctl.h>
#define ISP_PPC 2
/* 20% overhead */
#define ISP_OVERHEAD 20
#define ISP_CLASS_ID 0x32
struct host_isp5 {
struct platform_device *pdev;
struct clk *clk;
};
static int isp5_alloc_syncpt(struct platform_device *pdev,
const char *name,
uint32_t *syncpt_id)
{
uint32_t id;
if (syncpt_id == NULL) {
dev_err(&pdev->dev, "%s: null argument\n", __func__);
return -EINVAL;
}
id = nvhost_get_syncpt_client_managed(pdev, name);
if (id == 0) {
dev_err(&pdev->dev, "%s: syncpt allocation failed\n", __func__);
return -ENODEV;
}
*syncpt_id = id;
return 0;
}
static void isp5_release_syncpt(struct platform_device *pdev, uint32_t id)
{
dev_dbg(&pdev->dev, "%s: id=%u\n", __func__, id);
nvhost_syncpt_put_ref_ext(pdev, id);
}
static int isp5_get_syncpt_gos_backing(struct platform_device *pdev,
uint32_t id,
dma_addr_t *syncpt_addr,
uint32_t *gos_index,
uint32_t *gos_offset)
{
uint32_t index = GOS_INDEX_INVALID;
uint32_t offset = 0;
dma_addr_t addr;
if (id == 0) {
dev_err(&pdev->dev, "%s: syncpt id is invalid\n", __func__);
return -EINVAL;
}
if (syncpt_addr == NULL || gos_index == NULL || gos_offset == NULL) {
dev_err(&pdev->dev, "%s: null arguments\n", __func__);
return -EINVAL;
}
addr = nvhost_syncpt_address(pdev, id);
*syncpt_addr = addr;
*gos_index = index;
*gos_offset = offset;
dev_dbg(&pdev->dev, "%s: id=%u addr=0x%llx gos_idx=%u gos_offset=%u\n",
__func__, id, addr, index, offset);
return 0;
}
static uint32_t isp5_get_gos_table(struct platform_device *pdev,
const dma_addr_t **table)
{
uint32_t count = 0;
*table = NULL;
return count;
}
static struct isp_channel_drv_ops isp5_channel_drv_ops = {
.alloc_syncpt = isp5_alloc_syncpt,
.release_syncpt = isp5_release_syncpt,
.get_gos_table = isp5_get_gos_table,
.get_syncpt_gos_backing = isp5_get_syncpt_gos_backing,
};
int isp5_priv_early_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct nvhost_device_data *info;
struct host_isp5 *isp5;
int err = 0;
info = (void *)of_device_get_match_data(dev);
if (unlikely(info == NULL)) {
dev_WARN(dev, "no platform data\n");
return -ENODATA;
}
err = isp_channel_drv_fops_register(&isp5_channel_drv_ops);
if (err) {
goto error;
}
isp5 = devm_kzalloc(dev, sizeof(*isp5), GFP_KERNEL);
if (!isp5)
return -ENOMEM;
isp5->pdev = pdev;
info->pdev = pdev;
mutex_init(&info->lock);
platform_set_drvdata(pdev, info);
info->private_data = isp5;
/* A bit was stolen */
(void) dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(39));
#ifdef CONFIG_DMABUF_DEFERRED_UNMAPPING
if (dma_buf_defer_unmapping(dev, true) < 0)
dev_warn(dev, "Failed to set deferred dma buffer unmapping\n");
#endif
return 0;
error:
info->private_data = NULL;
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev, "probe failed: %d\n", err);
return err;
}
static int isp5_set_rate(struct tegra_camera_dev_info *cdev_info, unsigned long rate)
{
struct nvhost_device_data *info = platform_get_drvdata(cdev_info->pdev);
struct host_isp5 *isp5 = info->private_data;
return clk_set_rate(isp5->clk, rate);
}
static struct tegra_camera_dev_ops isp5_cdev_ops = {
.set_rate = isp5_set_rate,
};
int isp5_priv_late_probe(struct platform_device *pdev)
{
struct tegra_camera_dev_info isp_info;
struct nvhost_device_data *info = platform_get_drvdata(pdev);
struct host_isp5 *isp5 = info->private_data;
int err;
memset(&isp_info, 0, sizeof(isp_info));
isp_info.overhead = ISP_OVERHEAD;
isp_info.ppc = ISP_PPC;
isp_info.hw_type = HWTYPE_ISPA;
isp_info.pdev = pdev;
isp_info.ops = &isp5_cdev_ops;
err = tegra_camera_device_register(&isp_info, isp5);
if (err)
goto device_release;
return 0;
device_release:
nvhost_client_device_release(pdev);
return err;
}
static int isp5_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct nvhost_device_data *pdata;
struct host_isp5 *isp5;
int err = 0;
err = isp5_priv_early_probe(pdev);
if (err)
goto error;
pdata = platform_get_drvdata(pdev);
isp5 = pdata->private_data;
isp5->clk = devm_clk_get(dev, NULL);
if (IS_ERR(isp5->clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
return PTR_ERR(isp5->clk);
}
err = nvhost_client_device_get_resources(pdev);
if (err)
goto error;
err = nvhost_module_init(pdev);
if (err)
goto error;
err = nvhost_client_device_init(pdev);
if (err) {
nvhost_module_deinit(pdev);
goto error;
}
err = nvhost_syncpt_unit_interface_init(pdev);
if (err)
goto error;
err = isp5_priv_late_probe(pdev);
if (err)
goto error;
return 0;
error:
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev, "probe failed: %d\n", err);
return err;
}
static long isp_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct t194_isp5_file_private *filepriv = file->private_data;
struct platform_device *pdev = filepriv->pdev;
if (_IOC_TYPE(cmd) != NVHOST_ISP_IOCTL_MAGIC)
return -EFAULT;
switch (_IOC_NR(cmd)) {
case _IOC_NR(NVHOST_ISP_IOCTL_SET_ISP_LA_BW): {
/* No BW control needed. Return without error. */
return 0;
}
default:
dev_err(&pdev->dev,
"%s: Unknown ISP ioctl.\n", __func__);
return -EINVAL;
}
return 0;
}
static int isp_open(struct inode *inode, struct file *file)
{
struct nvhost_device_data *pdata = container_of(inode->i_cdev,
struct nvhost_device_data, ctrl_cdev);
struct platform_device *pdev = pdata->pdev;
struct t194_isp5_file_private *filepriv;
filepriv = kzalloc(sizeof(*filepriv), GFP_KERNEL);
if (unlikely(filepriv == NULL))
return -ENOMEM;
filepriv->pdev = pdev;
file->private_data = filepriv;
return nonseekable_open(inode, file);
}
static int isp_release(struct inode *inode, struct file *file)
{
struct t194_isp5_file_private *filepriv = file->private_data;
kfree(filepriv);
return 0;
}
const struct file_operations isp_ctrl_ops = {
.owner = THIS_MODULE,
.open = isp_open,
.unlocked_ioctl = isp_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = isp_ioctl,
#endif
.release = isp_release,
};
static int isp5_remove(struct platform_device *pdev)
{
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct host_isp5 *isp5 = (struct host_isp5 *)pdata->private_data;
tegra_camera_device_unregister(isp5);
isp_channel_drv_unregister(&pdev->dev);
return 0;
}
struct nvhost_device_data t19_isp5_info = {
.devfs_name = "isp",
.moduleid = 4, //NVHOST_MODULE_ISP,
.clocks = {
{"isp", UINT_MAX},
},
.ctrl_ops = &isp_ctrl_ops,
.pre_virt_init = isp5_priv_early_probe,
.post_virt_init = isp5_priv_late_probe,
.autosuspend_delay = 500,
.can_powergate = true,
.class = ISP_CLASS_ID,
};
struct nvhost_device_data t264_isp_info = {
.devfs_name = "isp",
.moduleid = NVHOST_MODULE_ISP,
.clocks = {
{"isp", UINT_MAX},
},
.ctrl_ops = &isp_ctrl_ops,
.pre_virt_init = isp5_priv_early_probe,
.post_virt_init = isp5_priv_late_probe,
.can_powergate = false,
.class = ISP_CLASS_ID,
};
struct nvhost_device_data t264_isp1_info = {
.devfs_name = "isp1",
.moduleid = NVHOST_MODULE_ISPB,
.clocks = {
{"isp1", UINT_MAX},
},
.ctrl_ops = &isp_ctrl_ops,
.pre_virt_init = isp5_priv_early_probe,
.post_virt_init = isp5_priv_late_probe,
.can_powergate = false,
.class = ISP_CLASS_ID,
};
static const struct of_device_id tegra_isp5_of_match[] = {
{
.name = "isp",
.compatible = "nvidia,tegra264-isp",
.data = &t264_isp_info,
},
{
.name = "isp1",
.compatible = "nvidia,tegra264-isp",
.data = &t264_isp1_info,
},
{
.compatible = "nvidia,tegra194-isp",
.data = &t19_isp5_info,
},
{ },
};
MODULE_DEVICE_TABLE(of, tegra_isp5_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void isp5_remove_wrapper(struct platform_device *pdev)
{
isp5_remove(pdev);
}
#else
static int isp5_remove_wrapper(struct platform_device *pdev)
{
return isp5_remove(pdev);
}
#endif
static struct platform_driver isp5_driver = {
.probe = isp5_probe,
.remove = isp5_remove_wrapper,
.driver = {
.owner = THIS_MODULE,
.name = "tegra194-isp5",
#ifdef CONFIG_OF
.of_match_table = tegra_isp5_of_match,
#endif
#ifdef CONFIG_PM
.pm = &nvhost_module_pm_ops,
#endif
},
};
module_platform_driver(isp5_driver);
MODULE_LICENSE("GPL");