brintos

brintos / linux-shallow public Read only

0
0
Text · 16.9 KiB · e97abe3 Raw
637 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Microchip eXtended Image Sensor Controller (XISC) driver4 *5 * Copyright (C) 2019-2021 Microchip Technology, Inc. and its subsidiaries6 *7 * Author: Eugen Hristev <eugen.hristev@microchip.com>8 *9 * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS10 *11 * ISC video pipeline integrates the following submodules:12 * PFE: Parallel Front End to sample the camera sensor input stream13 * DPC: Defective Pixel Correction with black offset correction, green disparity14 *      correction and defective pixel correction (3 modules total)15 *  WB: Programmable white balance in the Bayer domain16 * CFA: Color filter array interpolation module17 *  CC: Programmable color correction18 * GAM: Gamma correction19 *VHXS: Vertical and Horizontal Scaler20 * CSC: Programmable color space conversion21 *CBHS: Contrast Brightness Hue and Saturation control22 * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling23 * RLP: This module performs rounding, range limiting24 *      and packing of the incoming data25 * DMA: This module performs DMA master accesses to write frames to external RAM26 * HIS: Histogram module performs statistic counters on the frames27 */28 29#include <linux/clk.h>30#include <linux/clkdev.h>31#include <linux/clk-provider.h>32#include <linux/delay.h>33#include <linux/interrupt.h>34#include <linux/math64.h>35#include <linux/module.h>36#include <linux/of.h>37#include <linux/of_graph.h>38#include <linux/platform_device.h>39#include <linux/pm_runtime.h>40#include <linux/regmap.h>41#include <linux/videodev2.h>42 43#include <media/v4l2-ctrls.h>44#include <media/v4l2-device.h>45#include <media/v4l2-event.h>46#include <media/v4l2-image-sizes.h>47#include <media/v4l2-ioctl.h>48#include <media/v4l2-fwnode.h>49#include <media/v4l2-subdev.h>50#include <media/videobuf2-dma-contig.h>51 52#include "microchip-isc-regs.h"53#include "microchip-isc.h"54 55#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH   326456#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT  246457 58#define ISC_SAMA7G5_PIPELINE \59	(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \60	CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)61 62/* This is a list of the formats that the ISC can *output* */63static const struct isc_format sama7g5_controller_formats[] = {64	{65		.fourcc		= V4L2_PIX_FMT_ARGB444,66	}, {67		.fourcc		= V4L2_PIX_FMT_ARGB555,68	}, {69		.fourcc		= V4L2_PIX_FMT_RGB565,70	}, {71		.fourcc		= V4L2_PIX_FMT_ABGR32,72	}, {73		.fourcc		= V4L2_PIX_FMT_XBGR32,74	}, {75		.fourcc		= V4L2_PIX_FMT_YUV420,76	}, {77		.fourcc		= V4L2_PIX_FMT_UYVY,78	}, {79		.fourcc		= V4L2_PIX_FMT_VYUY,80	}, {81		.fourcc		= V4L2_PIX_FMT_YUYV,82	}, {83		.fourcc		= V4L2_PIX_FMT_YUV422P,84	}, {85		.fourcc		= V4L2_PIX_FMT_GREY,86	}, {87		.fourcc		= V4L2_PIX_FMT_Y10,88	}, {89		.fourcc		= V4L2_PIX_FMT_Y16,90	}, {91		.fourcc		= V4L2_PIX_FMT_SBGGR8,92		.raw		= true,93	}, {94		.fourcc		= V4L2_PIX_FMT_SGBRG8,95		.raw		= true,96	}, {97		.fourcc		= V4L2_PIX_FMT_SGRBG8,98		.raw		= true,99	}, {100		.fourcc		= V4L2_PIX_FMT_SRGGB8,101		.raw		= true,102	}, {103		.fourcc		= V4L2_PIX_FMT_SBGGR10,104		.raw		= true,105	}, {106		.fourcc		= V4L2_PIX_FMT_SGBRG10,107		.raw		= true,108	}, {109		.fourcc		= V4L2_PIX_FMT_SGRBG10,110		.raw		= true,111	}, {112		.fourcc		= V4L2_PIX_FMT_SRGGB10,113		.raw		= true,114	}, {115		.fourcc		= V4L2_PIX_FMT_SBGGR12,116		.raw		= true,117	}, {118		.fourcc		= V4L2_PIX_FMT_SGBRG12,119		.raw		= true,120	}, {121		.fourcc		= V4L2_PIX_FMT_SGRBG12,122		.raw		= true,123	}, {124		.fourcc		= V4L2_PIX_FMT_SRGGB12,125		.raw		= true,126	},127};128 129/* This is a list of formats that the ISC can receive as *input* */130static struct isc_format sama7g5_formats_list[] = {131	{132		.fourcc		= V4L2_PIX_FMT_SBGGR8,133		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,134		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,135		.cfa_baycfg	= ISC_BAY_CFG_BGBG,136	},137	{138		.fourcc		= V4L2_PIX_FMT_SGBRG8,139		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,140		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,141		.cfa_baycfg	= ISC_BAY_CFG_GBGB,142	},143	{144		.fourcc		= V4L2_PIX_FMT_SGRBG8,145		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,146		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,147		.cfa_baycfg	= ISC_BAY_CFG_GRGR,148	},149	{150		.fourcc		= V4L2_PIX_FMT_SRGGB8,151		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,152		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,153		.cfa_baycfg	= ISC_BAY_CFG_RGRG,154	},155	{156		.fourcc		= V4L2_PIX_FMT_SBGGR10,157		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,158		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,159		.cfa_baycfg	= ISC_BAY_CFG_RGRG,160	},161	{162		.fourcc		= V4L2_PIX_FMT_SGBRG10,163		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,164		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,165		.cfa_baycfg	= ISC_BAY_CFG_GBGB,166	},167	{168		.fourcc		= V4L2_PIX_FMT_SGRBG10,169		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,170		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,171		.cfa_baycfg	= ISC_BAY_CFG_GRGR,172	},173	{174		.fourcc		= V4L2_PIX_FMT_SRGGB10,175		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,176		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,177		.cfa_baycfg	= ISC_BAY_CFG_RGRG,178	},179	{180		.fourcc		= V4L2_PIX_FMT_SBGGR12,181		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,182		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,183		.cfa_baycfg	= ISC_BAY_CFG_BGBG,184	},185	{186		.fourcc		= V4L2_PIX_FMT_SGBRG12,187		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,188		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,189		.cfa_baycfg	= ISC_BAY_CFG_GBGB,190	},191	{192		.fourcc		= V4L2_PIX_FMT_SGRBG12,193		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,194		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,195		.cfa_baycfg	= ISC_BAY_CFG_GRGR,196	},197	{198		.fourcc		= V4L2_PIX_FMT_SRGGB12,199		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,200		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,201		.cfa_baycfg	= ISC_BAY_CFG_RGRG,202	},203	{204		.fourcc		= V4L2_PIX_FMT_GREY,205		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,206		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,207	},208	{209		.fourcc		= V4L2_PIX_FMT_YUYV,210		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,211		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,212	},213	{214		.fourcc		= V4L2_PIX_FMT_UYVY,215		.mbus_code	= MEDIA_BUS_FMT_UYVY8_2X8,216		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,217	},218	{219		.fourcc		= V4L2_PIX_FMT_RGB565,220		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_LE,221		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,222	},223	{224		.fourcc		= V4L2_PIX_FMT_Y10,225		.mbus_code	= MEDIA_BUS_FMT_Y10_1X10,226		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,227	},228};229 230static void isc_sama7g5_config_csc(struct isc_device *isc)231{232	struct regmap *regmap = isc->regmap;233 234	/* Convert RGB to YUV */235	regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,236		     0x42 | (0x81 << 16));237	regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,238		     0x19 | (0x10 << 16));239	regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,240		     0xFDA | (0xFB6 << 16));241	regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,242		     0x70 | (0x80 << 16));243	regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,244		     0x70 | (0xFA2 << 16));245	regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,246		     0xFEE | (0x80 << 16));247}248 249static void isc_sama7g5_config_cbc(struct isc_device *isc)250{251	struct regmap *regmap = isc->regmap;252 253	/* Configure what is set via v4l2 ctrls */254	regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);255	regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);256	/* Configure Hue and Saturation as neutral midpoint */257	regmap_write(regmap, ISC_CBCHS_HUE, 0);258	regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));259}260 261static void isc_sama7g5_config_cc(struct isc_device *isc)262{263	struct regmap *regmap = isc->regmap;264 265	/* Configure each register at the neutral fixed point 1.0 or 0.0 */266	regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));267	regmap_write(regmap, ISC_CC_RB_OR, 0);268	regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);269	regmap_write(regmap, ISC_CC_GB_OG, 0);270	regmap_write(regmap, ISC_CC_BR_BG, 0);271	regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));272}273 274static void isc_sama7g5_config_ctrls(struct isc_device *isc,275				     const struct v4l2_ctrl_ops *ops)276{277	struct isc_ctrls *ctrls = &isc->ctrls;278	struct v4l2_ctrl_handler *hdl = &ctrls->handler;279 280	ctrls->contrast = 16;281 282	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);283}284 285static void isc_sama7g5_config_dpc(struct isc_device *isc)286{287	u32 bay_cfg = isc->config.sd_format->cfa_baycfg;288	struct regmap *regmap = isc->regmap;289 290	regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,291			   (64 << ISC_DPC_CFG_BLOFF_SHIFT));292	regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,293			   (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));294}295 296static void isc_sama7g5_config_gam(struct isc_device *isc)297{298	struct regmap *regmap = isc->regmap;299 300	regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,301			   ISC_GAM_CTRL_BIPART);302}303 304static void isc_sama7g5_config_rlp(struct isc_device *isc)305{306	struct regmap *regmap = isc->regmap;307	u32 rlp_mode = isc->config.rlp_cfg_mode;308 309	regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,310			   ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |311			   ISC_RLP_CFG_YMODE_MASK, rlp_mode);312}313 314static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)315{316	isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;317}318 319/* Gamma table with gamma 1/2.2 */320static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {321	/* index 0 --> gamma bipartite */322	{323	      0x980,  0x4c0320,  0x650260,  0x7801e0,  0x8701a0,  0x940180,324	   0xa00160,  0xab0120,  0xb40120,  0xbd0120,  0xc60100,  0xce0100,325	   0xd600e0,  0xdd00e0,  0xe400e0,  0xeb00c0,  0xf100c0,  0xf700c0,326	   0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,327	  0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,328	  0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,329	  0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,330	  0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,331	  0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,332	  0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,333	  0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },334};335 336static int xisc_parse_dt(struct device *dev, struct isc_device *isc)337{338	struct device_node *np = dev->of_node;339	struct device_node *epn;340	struct isc_subdev_entity *subdev_entity;341	unsigned int flags;342	bool mipi_mode;343 344	INIT_LIST_HEAD(&isc->subdev_entities);345 346	mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");347 348	for_each_endpoint_of_node(np, epn) {349		struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };350		int ret;351 352		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),353						 &v4l2_epn);354		if (ret) {355			of_node_put(epn);356			dev_err(dev, "Could not parse the endpoint\n");357			return -EINVAL;358		}359 360		subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),361					     GFP_KERNEL);362		if (!subdev_entity) {363			of_node_put(epn);364			return -ENOMEM;365		}366		subdev_entity->epn = epn;367 368		flags = v4l2_epn.bus.parallel.flags;369 370		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)371			subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;372 373		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)374			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;375 376		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)377			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;378 379		if (v4l2_epn.bus_type == V4L2_MBUS_BT656)380			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |381					ISC_PFE_CFG0_CCIR656;382 383		if (mipi_mode)384			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;385 386		list_add_tail(&subdev_entity->list, &isc->subdev_entities);387	}388 389	return 0;390}391 392static int microchip_xisc_probe(struct platform_device *pdev)393{394	struct device *dev = &pdev->dev;395	struct isc_device *isc;396	void __iomem *io_base;397	struct isc_subdev_entity *subdev_entity;398	int irq;399	int ret;400	u32 ver;401 402	isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);403	if (!isc)404		return -ENOMEM;405 406	platform_set_drvdata(pdev, isc);407	isc->dev = dev;408 409	io_base = devm_platform_ioremap_resource(pdev, 0);410	if (IS_ERR(io_base))411		return PTR_ERR(io_base);412 413	isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);414	if (IS_ERR(isc->regmap)) {415		ret = PTR_ERR(isc->regmap);416		dev_err(dev, "failed to init register map: %d\n", ret);417		return ret;418	}419 420	irq = platform_get_irq(pdev, 0);421	if (irq < 0)422		return irq;423 424	ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,425			       "microchip-sama7g5-xisc", isc);426	if (ret < 0) {427		dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",428			irq, ret);429		return ret;430	}431 432	isc->gamma_table = isc_sama7g5_gamma_table;433	isc->gamma_max = 0;434 435	isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;436	isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;437 438	isc->config_dpc = isc_sama7g5_config_dpc;439	isc->config_csc = isc_sama7g5_config_csc;440	isc->config_cbc = isc_sama7g5_config_cbc;441	isc->config_cc = isc_sama7g5_config_cc;442	isc->config_gam = isc_sama7g5_config_gam;443	isc->config_rlp = isc_sama7g5_config_rlp;444	isc->config_ctrls = isc_sama7g5_config_ctrls;445 446	isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;447 448	isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;449	isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;450	isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;451	isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;452	isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;453	isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;454	isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;455	isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;456	isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;457 458	isc->controller_formats = sama7g5_controller_formats;459	isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);460	isc->formats_list = sama7g5_formats_list;461	isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);462 463	/* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */464	isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;465 466	/* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */467	isc->ispck_required = false;468 469	ret = microchip_isc_pipeline_init(isc);470	if (ret)471		return ret;472 473	isc->hclock = devm_clk_get(dev, "hclock");474	if (IS_ERR(isc->hclock)) {475		ret = PTR_ERR(isc->hclock);476		dev_err(dev, "failed to get hclock: %d\n", ret);477		return ret;478	}479 480	ret = clk_prepare_enable(isc->hclock);481	if (ret) {482		dev_err(dev, "failed to enable hclock: %d\n", ret);483		return ret;484	}485 486	ret = microchip_isc_clk_init(isc);487	if (ret) {488		dev_err(dev, "failed to init isc clock: %d\n", ret);489		goto unprepare_hclk;490	}491 492	ret = v4l2_device_register(dev, &isc->v4l2_dev);493	if (ret) {494		dev_err(dev, "unable to register v4l2 device.\n");495		goto unprepare_hclk;496	}497 498	ret = xisc_parse_dt(dev, isc);499	if (ret) {500		dev_err(dev, "fail to parse device tree\n");501		goto unregister_v4l2_device;502	}503 504	if (list_empty(&isc->subdev_entities)) {505		dev_err(dev, "no subdev found\n");506		ret = -ENODEV;507		goto unregister_v4l2_device;508	}509 510	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {511		struct v4l2_async_connection *asd;512		struct fwnode_handle *fwnode =513			of_fwnode_handle(subdev_entity->epn);514 515		v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);516 517		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,518						      fwnode,519						      struct v4l2_async_connection);520 521		of_node_put(subdev_entity->epn);522		subdev_entity->epn = NULL;523 524		if (IS_ERR(asd)) {525			ret = PTR_ERR(asd);526			goto cleanup_subdev;527		}528 529		subdev_entity->notifier.ops = &microchip_isc_async_ops;530 531		ret = v4l2_async_nf_register(&subdev_entity->notifier);532		if (ret) {533			dev_err(dev, "fail to register async notifier\n");534			goto cleanup_subdev;535		}536 537		if (video_is_registered(&isc->video_dev))538			break;539	}540 541	regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);542 543	ret = isc_mc_init(isc, ver);544	if (ret < 0)545		goto isc_probe_mc_init_err;546 547	pm_runtime_set_active(dev);548	pm_runtime_enable(dev);549	pm_request_idle(dev);550 551	dev_info(dev, "Microchip XISC version %x\n", ver);552 553	return 0;554 555isc_probe_mc_init_err:556	isc_mc_cleanup(isc);557 558cleanup_subdev:559	microchip_isc_subdev_cleanup(isc);560 561unregister_v4l2_device:562	v4l2_device_unregister(&isc->v4l2_dev);563 564unprepare_hclk:565	clk_disable_unprepare(isc->hclock);566 567	microchip_isc_clk_cleanup(isc);568 569	return ret;570}571 572static void microchip_xisc_remove(struct platform_device *pdev)573{574	struct isc_device *isc = platform_get_drvdata(pdev);575 576	pm_runtime_disable(&pdev->dev);577 578	isc_mc_cleanup(isc);579 580	microchip_isc_subdev_cleanup(isc);581 582	v4l2_device_unregister(&isc->v4l2_dev);583 584	clk_disable_unprepare(isc->hclock);585 586	microchip_isc_clk_cleanup(isc);587}588 589static int __maybe_unused xisc_runtime_suspend(struct device *dev)590{591	struct isc_device *isc = dev_get_drvdata(dev);592 593	clk_disable_unprepare(isc->hclock);594 595	return 0;596}597 598static int __maybe_unused xisc_runtime_resume(struct device *dev)599{600	struct isc_device *isc = dev_get_drvdata(dev);601	int ret;602 603	ret = clk_prepare_enable(isc->hclock);604	if (ret)605		return ret;606 607	return ret;608}609 610static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {611	SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)612};613 614#if IS_ENABLED(CONFIG_OF)615static const struct of_device_id microchip_xisc_of_match[] = {616	{ .compatible = "microchip,sama7g5-isc" },617	{ }618};619MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);620#endif621 622static struct platform_driver microchip_xisc_driver = {623	.probe	= microchip_xisc_probe,624	.remove_new = microchip_xisc_remove,625	.driver	= {626		.name		= "microchip-sama7g5-xisc",627		.pm		= &microchip_xisc_dev_pm_ops,628		.of_match_table = of_match_ptr(microchip_xisc_of_match),629	},630};631 632module_platform_driver(microchip_xisc_driver);633 634MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");635MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");636MODULE_LICENSE("GPL v2");637