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