xref: /linux/drivers/media/platform/amd/isp4/isp4.c (revision 9a54c285630c0072daef5d526c3f0b697e901065)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2025 Advanced Micro Devices, Inc.
4  */
5 
6 #include <linux/pm_runtime.h>
7 #include <linux/vmalloc.h>
8 #include <media/v4l2-ioctl.h>
9 
10 #include "isp4.h"
11 
12 #define ISP4_DRV_NAME "amd_isp_capture"
13 
14 static const struct {
15 	const char *name;
16 	u32 status_mask;
17 	u32 en_mask;
18 	u32 ack_mask;
19 	u32 rb_int_num;
20 } isp4_irq[] = {
21 	/* The IRQ order is aligned with the isp4_subdev.fw_resp_thread order */
22 	{
23 		.name = "isp_irq_global",
24 		.rb_int_num = 4, /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT12 */
25 	},
26 	{
27 		.name = "isp_irq_stream1",
28 		.rb_int_num = 0, /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT9 */
29 	},
30 };
31 
32 static irqreturn_t isp4_irq_handler(int irq, void *arg)
33 {
34 	return IRQ_HANDLED;
35 }
36 
37 static int isp4_capture_probe(struct platform_device *pdev)
38 {
39 	struct device *dev = &pdev->dev;
40 	int irq[ARRAY_SIZE(isp4_irq)];
41 	struct isp4_device *isp_dev;
42 	int ret;
43 
44 	isp_dev = devm_kzalloc(dev, sizeof(*isp_dev), GFP_KERNEL);
45 	if (!isp_dev)
46 		return -ENOMEM;
47 
48 	dev->init_name = ISP4_DRV_NAME;
49 
50 	for (size_t i = 0; i < ARRAY_SIZE(isp4_irq); i++) {
51 		irq[i] = platform_get_irq(pdev, isp4_irq[i].rb_int_num);
52 		if (irq[i] < 0)
53 			return dev_err_probe(dev, irq[i],
54 					     "fail to get irq %d\n",
55 					     isp4_irq[i].rb_int_num);
56 
57 		ret = devm_request_irq(dev, irq[i], isp4_irq_handler,
58 				       IRQF_NO_AUTOEN, isp4_irq[i].name, dev);
59 		if (ret)
60 			return dev_err_probe(dev, ret, "fail to req irq %d\n",
61 					     irq[i]);
62 	}
63 
64 	isp_dev->v4l2_dev.mdev = &isp_dev->mdev;
65 
66 	strscpy(isp_dev->mdev.model, "amd_isp41_mdev",
67 		sizeof(isp_dev->mdev.model));
68 	isp_dev->mdev.dev = dev;
69 	media_device_init(&isp_dev->mdev);
70 
71 	snprintf(isp_dev->v4l2_dev.name, sizeof(isp_dev->v4l2_dev.name),
72 		 "AMD-V4L2-ROOT");
73 	ret = v4l2_device_register(dev, &isp_dev->v4l2_dev);
74 	if (ret) {
75 		dev_err_probe(dev, ret, "fail register v4l2 device\n");
76 		goto err_clean_media;
77 	}
78 
79 	pm_runtime_set_suspended(dev);
80 	pm_runtime_enable(dev);
81 	ret = media_device_register(&isp_dev->mdev);
82 	if (ret) {
83 		dev_err_probe(dev, ret, "fail to register media device\n");
84 		goto err_isp4_deinit;
85 	}
86 
87 	platform_set_drvdata(pdev, isp_dev);
88 
89 	return 0;
90 
91 err_isp4_deinit:
92 	pm_runtime_disable(dev);
93 	v4l2_device_unregister(&isp_dev->v4l2_dev);
94 err_clean_media:
95 	media_device_cleanup(&isp_dev->mdev);
96 
97 	return ret;
98 }
99 
100 static void isp4_capture_remove(struct platform_device *pdev)
101 {
102 	struct isp4_device *isp_dev = platform_get_drvdata(pdev);
103 	struct device *dev = &pdev->dev;
104 
105 	media_device_unregister(&isp_dev->mdev);
106 	pm_runtime_disable(dev);
107 	v4l2_device_unregister(&isp_dev->v4l2_dev);
108 	media_device_cleanup(&isp_dev->mdev);
109 }
110 
111 static struct platform_driver isp4_capture_drv = {
112 	.probe = isp4_capture_probe,
113 	.remove = isp4_capture_remove,
114 	.driver = {
115 		.name = ISP4_DRV_NAME,
116 	}
117 };
118 
119 module_platform_driver(isp4_capture_drv);
120 
121 MODULE_ALIAS("platform:" ISP4_DRV_NAME);
122 MODULE_IMPORT_NS("DMA_BUF");
123 
124 MODULE_DESCRIPTION("AMD ISP4 Driver");
125 MODULE_AUTHOR("Bin Du <bin.du@amd.com>");
126 MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>");
127 MODULE_LICENSE("GPL");
128