1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * rcar-fcp.c -- R-Car Frame Compression Processor Driver 4 * 5 * Copyright (C) 2016 Renesas Electronics Corporation 6 * 7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 8 */ 9 10 #include <linux/device.h> 11 #include <linux/dma-mapping.h> 12 #include <linux/list.h> 13 #include <linux/module.h> 14 #include <linux/mod_devicetable.h> 15 #include <linux/mutex.h> 16 #include <linux/platform_device.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/slab.h> 19 20 #include <media/rcar-fcp.h> 21 22 struct rcar_fcp_device { 23 struct list_head list; 24 struct device *dev; 25 }; 26 27 static LIST_HEAD(fcp_devices); 28 static DEFINE_MUTEX(fcp_lock); 29 30 /* ----------------------------------------------------------------------------- 31 * Public API 32 */ 33 34 /** 35 * rcar_fcp_get - Find and acquire a reference to an FCP instance 36 * @np: Device node of the FCP instance 37 * 38 * Search the list of registered FCP instances for the instance corresponding to 39 * the given device node. 40 * 41 * Return a pointer to the FCP instance, or an ERR_PTR if the instance can't be 42 * found. 43 */ 44 struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np) 45 { 46 struct rcar_fcp_device *fcp; 47 48 mutex_lock(&fcp_lock); 49 50 list_for_each_entry(fcp, &fcp_devices, list) { 51 if (fcp->dev->of_node != np) 52 continue; 53 54 get_device(fcp->dev); 55 goto done; 56 } 57 58 fcp = ERR_PTR(-EPROBE_DEFER); 59 60 done: 61 mutex_unlock(&fcp_lock); 62 return fcp; 63 } 64 EXPORT_SYMBOL_GPL(rcar_fcp_get); 65 66 /** 67 * rcar_fcp_put - Release a reference to an FCP instance 68 * @fcp: The FCP instance 69 * 70 * Release the FCP instance acquired by a call to rcar_fcp_get(). 71 */ 72 void rcar_fcp_put(struct rcar_fcp_device *fcp) 73 { 74 if (fcp) 75 put_device(fcp->dev); 76 } 77 EXPORT_SYMBOL_GPL(rcar_fcp_put); 78 79 struct device *rcar_fcp_get_device(struct rcar_fcp_device *fcp) 80 { 81 return fcp->dev; 82 } 83 EXPORT_SYMBOL_GPL(rcar_fcp_get_device); 84 85 /** 86 * rcar_fcp_enable - Enable an FCP 87 * @fcp: The FCP instance 88 * 89 * Before any memory access through an FCP is performed by a module, the FCP 90 * must be enabled by a call to this function. The enable calls are reference 91 * counted, each successful call must be followed by one rcar_fcp_disable() 92 * call when no more memory transfer can occur through the FCP. 93 * 94 * Return 0 on success or a negative error code if an error occurs. The enable 95 * reference count isn't increased when this function returns an error. 96 */ 97 int rcar_fcp_enable(struct rcar_fcp_device *fcp) 98 { 99 if (!fcp) 100 return 0; 101 102 return pm_runtime_resume_and_get(fcp->dev); 103 } 104 EXPORT_SYMBOL_GPL(rcar_fcp_enable); 105 106 /** 107 * rcar_fcp_disable - Disable an FCP 108 * @fcp: The FCP instance 109 * 110 * This function is the counterpart of rcar_fcp_enable(). As enable calls are 111 * reference counted a disable call may not disable the FCP synchronously. 112 */ 113 void rcar_fcp_disable(struct rcar_fcp_device *fcp) 114 { 115 if (fcp) 116 pm_runtime_put(fcp->dev); 117 } 118 EXPORT_SYMBOL_GPL(rcar_fcp_disable); 119 120 /* ----------------------------------------------------------------------------- 121 * Platform Driver 122 */ 123 124 static int rcar_fcp_probe(struct platform_device *pdev) 125 { 126 struct rcar_fcp_device *fcp; 127 128 fcp = devm_kzalloc(&pdev->dev, sizeof(*fcp), GFP_KERNEL); 129 if (fcp == NULL) 130 return -ENOMEM; 131 132 fcp->dev = &pdev->dev; 133 134 dma_set_max_seg_size(fcp->dev, UINT_MAX); 135 136 pm_runtime_enable(&pdev->dev); 137 138 mutex_lock(&fcp_lock); 139 list_add_tail(&fcp->list, &fcp_devices); 140 mutex_unlock(&fcp_lock); 141 142 platform_set_drvdata(pdev, fcp); 143 144 return 0; 145 } 146 147 static int rcar_fcp_remove(struct platform_device *pdev) 148 { 149 struct rcar_fcp_device *fcp = platform_get_drvdata(pdev); 150 151 mutex_lock(&fcp_lock); 152 list_del(&fcp->list); 153 mutex_unlock(&fcp_lock); 154 155 pm_runtime_disable(&pdev->dev); 156 157 return 0; 158 } 159 160 static const struct of_device_id rcar_fcp_of_match[] = { 161 { .compatible = "renesas,fcpf" }, 162 { .compatible = "renesas,fcpv" }, 163 { }, 164 }; 165 MODULE_DEVICE_TABLE(of, rcar_fcp_of_match); 166 167 static struct platform_driver rcar_fcp_platform_driver = { 168 .probe = rcar_fcp_probe, 169 .remove = rcar_fcp_remove, 170 .driver = { 171 .name = "rcar-fcp", 172 .of_match_table = rcar_fcp_of_match, 173 .suppress_bind_attrs = true, 174 }, 175 }; 176 177 module_platform_driver(rcar_fcp_platform_driver); 178 179 MODULE_ALIAS("rcar-fcp"); 180 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 181 MODULE_DESCRIPTION("Renesas FCP Driver"); 182 MODULE_LICENSE("GPL"); 183