FILE
rcar-fcp.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/renesas/rcar-fcp.c
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/io.h> 13#include <linux/iopoll.h> 14#include <linux/list.h> 15#include <linux/module.h> 16#include <linux/mod_devicetable.h> 17#include <linux/mutex.h> 18#include <linux/platform_device.h> 19#include <linux/pm_runtime.h> 20#include <linux/slab.h> 21 22#include <media/rcar-fcp.h> 23 24#define RCAR_FCP_REG_RST 0x0010 25#define RCAR_FCP_REG_RST_SOFTRST BIT(0) 26#define RCAR_FCP_REG_STA 0x0018 27#define RCAR_FCP_REG_STA_ACT BIT(0) 28 29struct rcar_fcp_device { 30 struct list_head list; 31 struct device *dev; 32 void __iomem *base; 33}; 34 35static LIST_HEAD(fcp_devices); 36static DEFINE_MUTEX(fcp_lock); 37 38static inline void rcar_fcp_write(struct rcar_fcp_device *fcp, u32 reg, u32 val) 39{ 40 iowrite32(val, fcp->base + reg); 41} 42 43/* ----------------------------------------------------------------------------- 44 * Public API 45 */ 46 47/** 48 * rcar_fcp_get - Find and acquire a reference to an FCP instance 49 * @np: Device node of the FCP instance 50 * 51 * Search the list of registered FCP instances for the instance corresponding to 52 * the given device node. 53 * 54 * Return a pointer to the FCP instance, or an ERR_PTR if the instance can't be 55 * found. 56 */ 57struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np) 58{ 59 struct rcar_fcp_device *fcp; 60 61 mutex_lock(&fcp_lock); 62 63 list_for_each_entry(fcp, &fcp_devices, list) { 64 if (fcp->dev->of_node != np) 65 continue; 66 67 get_device(fcp->dev); 68 goto done; 69 } 70 71 fcp = ERR_PTR(-EPROBE_DEFER); 72 73done: 74 mutex_unlock(&fcp_lock); 75 return fcp; 76} 77EXPORT_SYMBOL_GPL(rcar_fcp_get); 78 79/** 80 * rcar_fcp_put - Release a reference to an FCP instance 81 * @fcp: The FCP instance 82 * 83 * Release the FCP instance acquired by a call to rcar_fcp_get(). 84 */ 85void rcar_fcp_put(struct rcar_fcp_device *fcp) 86{ 87 if (fcp) 88 put_device(fcp->dev); 89} 90EXPORT_SYMBOL_GPL(rcar_fcp_put); 91 92struct device *rcar_fcp_get_device(struct rcar_fcp_device *fcp) 93{ 94 return fcp->dev; 95} 96EXPORT_SYMBOL_GPL(rcar_fcp_get_device); 97 98/** 99 * rcar_fcp_enable - Enable an FCP 100 * @fcp: The FCP instance 101 * 102 * Before any memory access through an FCP is performed by a module, the FCP 103 * must be enabled by a call to this function. The enable calls are reference 104 * counted, each successful call must be followed by one rcar_fcp_disable() 105 * call when no more memory transfer can occur through the FCP. 106 * 107 * Return 0 on success or a negative error code if an error occurs. The enable 108 * reference count isn't increased when this function returns an error. 109 */ 110int rcar_fcp_enable(struct rcar_fcp_device *fcp) 111{ 112 if (!fcp) 113 return 0; 114 115 return pm_runtime_resume_and_get(fcp->dev); 116} 117EXPORT_SYMBOL_GPL(rcar_fcp_enable); 118 119/** 120 * rcar_fcp_disable - Disable an FCP 121 * @fcp: The FCP instance 122 * 123 * This function is the counterpart of rcar_fcp_enable(). As enable calls are 124 * reference counted a disable call may not disable the FCP synchronously. 125 */ 126void rcar_fcp_disable(struct rcar_fcp_device *fcp) 127{ 128 if (fcp) 129 pm_runtime_put(fcp->dev); 130} 131EXPORT_SYMBOL_GPL(rcar_fcp_disable); 132 133int rcar_fcp_soft_reset(struct rcar_fcp_device *fcp) 134{ 135 u32 value; 136 int ret; 137 138 if (!fcp) 139 return 0; 140 141 rcar_fcp_write(fcp, RCAR_FCP_REG_RST, RCAR_FCP_REG_RST_SOFTRST); 142 ret = readl_poll_timeout(fcp->base + RCAR_FCP_REG_STA, 143 value, !(value & RCAR_FCP_REG_STA_ACT), 144 1, 100); 145 if (ret) 146 dev_err(fcp->dev, "Failed to soft-reset\n"); 147 148 return ret; 149} 150EXPORT_SYMBOL_GPL(rcar_fcp_soft_reset); 151 152/* ----------------------------------------------------------------------------- 153 * Platform Driver 154 */ 155 156static int rcar_fcp_probe(struct platform_device *pdev) 157{ 158 struct rcar_fcp_device *fcp; 159 160 fcp = devm_kzalloc(&pdev->dev, sizeof(*fcp), GFP_KERNEL); 161 if (fcp == NULL) 162 return -ENOMEM; 163 164 fcp->dev = &pdev->dev; 165 166 fcp->base = devm_platform_ioremap_resource(pdev, 0); 167 if (IS_ERR(fcp->base)) 168 return PTR_ERR(fcp->base); 169 170 dma_set_max_seg_size(fcp->dev, UINT_MAX); 171 172 pm_runtime_enable(&pdev->dev); 173 174 mutex_lock(&fcp_lock); 175 list_add_tail(&fcp->list, &fcp_devices); 176 mutex_unlock(&fcp_lock); 177 178 platform_set_drvdata(pdev, fcp); 179 180 return 0; 181} 182 183static void rcar_fcp_remove(struct platform_device *pdev) 184{ 185 struct rcar_fcp_device *fcp = platform_get_drvdata(pdev); 186 187 mutex_lock(&fcp_lock); 188 list_del(&fcp->list); 189 mutex_unlock(&fcp_lock); 190 191 pm_runtime_disable(&pdev->dev); 192} 193 194static const struct of_device_id rcar_fcp_of_match[] = { 195 { .compatible = "renesas,fcpf" }, 196 { .compatible = "renesas,fcpv" }, 197 { }, 198}; 199MODULE_DEVICE_TABLE(of, rcar_fcp_of_match); 200 201static struct platform_driver rcar_fcp_platform_driver = { 202 .probe = rcar_fcp_probe, 203 .remove = rcar_fcp_remove, 204 .driver = { 205 .name = "rcar-fcp", 206 .of_match_table = rcar_fcp_of_match, 207 .suppress_bind_attrs = true, 208 }, 209}; 210 211module_platform_driver(rcar_fcp_platform_driver); 212 213MODULE_ALIAS("rcar-fcp"); 214MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 215MODULE_DESCRIPTION("Renesas FCP Driver"); 216MODULE_LICENSE("GPL");
~/
Read-only file preview.