rcar-fcp.c (4284B)
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 22struct rcar_fcp_device { 23 struct list_head list; 24 struct device *dev; 25}; 26 27static LIST_HEAD(fcp_devices); 28static 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 */ 44struct 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 60done: 61 mutex_unlock(&fcp_lock); 62 return fcp; 63} 64EXPORT_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 */ 72void rcar_fcp_put(struct rcar_fcp_device *fcp) 73{ 74 if (fcp) 75 put_device(fcp->dev); 76} 77EXPORT_SYMBOL_GPL(rcar_fcp_put); 78 79struct device *rcar_fcp_get_device(struct rcar_fcp_device *fcp) 80{ 81 return fcp->dev; 82} 83EXPORT_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 */ 97int 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} 104EXPORT_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 */ 113void rcar_fcp_disable(struct rcar_fcp_device *fcp) 114{ 115 if (fcp) 116 pm_runtime_put(fcp->dev); 117} 118EXPORT_SYMBOL_GPL(rcar_fcp_disable); 119 120/* ----------------------------------------------------------------------------- 121 * Platform Driver 122 */ 123 124static 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 147static 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 160static const struct of_device_id rcar_fcp_of_match[] = { 161 { .compatible = "renesas,fcpf" }, 162 { .compatible = "renesas,fcpv" }, 163 { }, 164}; 165MODULE_DEVICE_TABLE(of, rcar_fcp_of_match); 166 167static 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 177module_platform_driver(rcar_fcp_platform_driver); 178 179MODULE_ALIAS("rcar-fcp"); 180MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 181MODULE_DESCRIPTION("Renesas FCP Driver"); 182MODULE_LICENSE("GPL");