File Index
Files and directories
Sign in
FILE

microchip-sama5d2-isc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/microchip/microchip-sama5d2-isc.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Microchip Image Sensor Controller (ISC) driver
  4 *
  5 * Copyright (C) 2016-2019 Microchip Technology, Inc.
  6 *
  7 * Author: Songjun Wu
  8 * Author: Eugen Hristev <eugen.hristev@microchip.com>
  9 *
 10 *
 11 * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
 12 *
 13 * ISC video pipeline integrates the following submodules:
 14 * PFE: Parallel Front End to sample the camera sensor input stream
 15 *  WB: Programmable white balance in the Bayer domain
 16 * CFA: Color filter array interpolation module
 17 *  CC: Programmable color correction
 18 * GAM: Gamma correction
 19 * CSC: Programmable color space conversion
 20 * CBC: Contrast and Brightness control
 21 * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
 22 * RLP: This module performs rounding, range limiting
 23 *      and packing of the incoming data
 24 */
 25
 26#include <linux/clk.h>
 27#include <linux/clkdev.h>
 28#include <linux/clk-provider.h>
 29#include <linux/delay.h>
 30#include <linux/interrupt.h>
 31#include <linux/math64.h>
 32#include <linux/module.h>
 33#include <linux/of.h>
 34#include <linux/of_graph.h>
 35#include <linux/platform_device.h>
 36#include <linux/pm_runtime.h>
 37#include <linux/regmap.h>
 38#include <linux/videodev2.h>
 39
 40#include <media/v4l2-ctrls.h>
 41#include <media/v4l2-device.h>
 42#include <media/v4l2-event.h>
 43#include <media/v4l2-image-sizes.h>
 44#include <media/v4l2-ioctl.h>
 45#include <media/v4l2-fwnode.h>
 46#include <media/v4l2-subdev.h>
 47#include <media/videobuf2-dma-contig.h>
 48
 49#include "microchip-isc-regs.h"
 50#include "microchip-isc.h"
 51
 52#define ISC_SAMA5D2_MAX_SUPPORT_WIDTH   2592
 53#define ISC_SAMA5D2_MAX_SUPPORT_HEIGHT  1944
 54
 55#define ISC_SAMA5D2_PIPELINE \
 56	(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
 57	CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
 58
 59/* This is a list of the formats that the ISC can *output* */
 60static const struct isc_format sama5d2_controller_formats[] = {
 61	{
 62		.fourcc		= V4L2_PIX_FMT_ARGB444,
 63	}, {
 64		.fourcc		= V4L2_PIX_FMT_ARGB555,
 65	}, {
 66		.fourcc		= V4L2_PIX_FMT_RGB565,
 67	}, {
 68		.fourcc		= V4L2_PIX_FMT_ABGR32,
 69	}, {
 70		.fourcc		= V4L2_PIX_FMT_XBGR32,
 71	}, {
 72		.fourcc		= V4L2_PIX_FMT_YUV420,
 73	}, {
 74		.fourcc		= V4L2_PIX_FMT_YUYV,
 75	}, {
 76		.fourcc		= V4L2_PIX_FMT_YUV422P,
 77	}, {
 78		.fourcc		= V4L2_PIX_FMT_GREY,
 79	}, {
 80		.fourcc		= V4L2_PIX_FMT_Y10,
 81	}, {
 82		.fourcc		= V4L2_PIX_FMT_SBGGR8,
 83		.raw		= true,
 84	}, {
 85		.fourcc		= V4L2_PIX_FMT_SGBRG8,
 86		.raw		= true,
 87	}, {
 88		.fourcc		= V4L2_PIX_FMT_SGRBG8,
 89		.raw		= true,
 90	}, {
 91		.fourcc		= V4L2_PIX_FMT_SRGGB8,
 92		.raw		= true,
 93	}, {
 94		.fourcc		= V4L2_PIX_FMT_SBGGR10,
 95		.raw		= true,
 96	}, {
 97		.fourcc		= V4L2_PIX_FMT_SGBRG10,
 98		.raw		= true,
 99	}, {
100		.fourcc		= V4L2_PIX_FMT_SGRBG10,
101		.raw		= true,
102	}, {
103		.fourcc		= V4L2_PIX_FMT_SRGGB10,
104		.raw		= true,
105	}, {
106		.fourcc		= V4L2_PIX_FMT_SBGGR12,
107		.raw		= true,
108	}, {
109		.fourcc		= V4L2_PIX_FMT_SGBRG12,
110		.raw		= true,
111	}, {
112		.fourcc		= V4L2_PIX_FMT_SGRBG12,
113		.raw		= true,
114	}, {
115		.fourcc		= V4L2_PIX_FMT_SRGGB12,
116		.raw		= true,
117	},
118};
119
120/* This is a list of formats that the ISC can receive as *input* */
121static struct isc_format sama5d2_formats_list[] = {
122	{
123		.fourcc		= V4L2_PIX_FMT_SBGGR8,
124		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
125		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
126		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
127	},
128	{
129		.fourcc		= V4L2_PIX_FMT_SGBRG8,
130		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,
131		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
132		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
133	},
134	{
135		.fourcc		= V4L2_PIX_FMT_SGRBG8,
136		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,
137		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
138		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
139	},
140	{
141		.fourcc		= V4L2_PIX_FMT_SRGGB8,
142		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,
143		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
144		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
145	},
146	{
147		.fourcc		= V4L2_PIX_FMT_SBGGR10,
148		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
149		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
150		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
151	},
152	{
153		.fourcc		= V4L2_PIX_FMT_SGBRG10,
154		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,
155		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
156		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
157	},
158	{
159		.fourcc		= V4L2_PIX_FMT_SGRBG10,
160		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,
161		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
162		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
163	},
164	{
165		.fourcc		= V4L2_PIX_FMT_SRGGB10,
166		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,
167		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
168		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
169	},
170	{
171		.fourcc		= V4L2_PIX_FMT_SBGGR12,
172		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,
173		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
174		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
175	},
176	{
177		.fourcc		= V4L2_PIX_FMT_SGBRG12,
178		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,
179		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
180		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
181	},
182	{
183		.fourcc		= V4L2_PIX_FMT_SGRBG12,
184		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,
185		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
186		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
187	},
188	{
189		.fourcc		= V4L2_PIX_FMT_SRGGB12,
190		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,
191		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
192		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
193	},
194	{
195		.fourcc		= V4L2_PIX_FMT_GREY,
196		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,
197		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
198	},
199	{
200		.fourcc		= V4L2_PIX_FMT_YUYV,
201		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
202		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
203	},
204	{
205		.fourcc		= V4L2_PIX_FMT_RGB565,
206		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_LE,
207		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
208	},
209	{
210		.fourcc		= V4L2_PIX_FMT_Y10,
211		.mbus_code	= MEDIA_BUS_FMT_Y10_1X10,
212		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
213	},
214
215};
216
217static void isc_sama5d2_config_csc(struct isc_device *isc)
218{
219	struct regmap *regmap = isc->regmap;
220
221	/* Convert RGB to YUV */
222	regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
223		     0x42 | (0x81 << 16));
224	regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
225		     0x19 | (0x10 << 16));
226	regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
227		     0xFDA | (0xFB6 << 16));
228	regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
229		     0x70 | (0x80 << 16));
230	regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
231		     0x70 | (0xFA2 << 16));
232	regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
233		     0xFEE | (0x80 << 16));
234}
235
236static void isc_sama5d2_config_cbc(struct isc_device *isc)
237{
238	struct regmap *regmap = isc->regmap;
239
240	regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc,
241		     isc->ctrls.brightness);
242	regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc,
243		     isc->ctrls.contrast);
244}
245
246static void isc_sama5d2_config_cc(struct isc_device *isc)
247{
248	struct regmap *regmap = isc->regmap;
249
250	/* Configure each register at the neutral fixed point 1.0 or 0.0 */
251	regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
252	regmap_write(regmap, ISC_CC_RB_OR, 0);
253	regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
254	regmap_write(regmap, ISC_CC_GB_OG, 0);
255	regmap_write(regmap, ISC_CC_BR_BG, 0);
256	regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
257}
258
259static void isc_sama5d2_config_ctrls(struct isc_device *isc,
260				     const struct v4l2_ctrl_ops *ops)
261{
262	struct isc_ctrls *ctrls = &isc->ctrls;
263	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
264
265	ctrls->contrast = 256;
266
267	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
268}
269
270static void isc_sama5d2_config_dpc(struct isc_device *isc)
271{
272	/* This module is not present on sama5d2 pipeline */
273}
274
275static void isc_sama5d2_config_gam(struct isc_device *isc)
276{
277	/* No specific gamma configuration */
278}
279
280static void isc_sama5d2_config_rlp(struct isc_device *isc)
281{
282	struct regmap *regmap = isc->regmap;
283	u32 rlp_mode = isc->config.rlp_cfg_mode;
284
285	/*
286	 * In sama5d2, the YUV planar modes and the YUYV modes are treated
287	 * in the same way in RLP register.
288	 * Normally, YYCC mode should be Luma(n) - Color B(n) - Color R (n)
289	 * and YCYC should be Luma(n + 1) - Color B (n) - Luma (n) - Color R (n)
290	 * but in sama5d2, the YCYC mode does not exist, and YYCC must be
291	 * selected for both planar and interleaved modes, as in fact
292	 * both modes are supported.
293	 *
294	 * Thus, if the YCYC mode is selected, replace it with the
295	 * sama5d2-compliant mode which is YYCC .
296	 */
297	if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) {
298		rlp_mode &= ~ISC_RLP_CFG_MODE_MASK;
299		rlp_mode |= ISC_RLP_CFG_MODE_YYCC;
300	}
301
302	regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
303			   ISC_RLP_CFG_MODE_MASK, rlp_mode);
304}
305
306static void isc_sama5d2_adapt_pipeline(struct isc_device *isc)
307{
308	isc->try_config.bits_pipeline &= ISC_SAMA5D2_PIPELINE;
309}
310
311/* Gamma table with gamma 1/2.2 */
312static const u32 isc_sama5d2_gamma_table[][GAMMA_ENTRIES] = {
313	/* 0 --> gamma 1/1.8 */
314	{      0x65,  0x66002F,  0x950025,  0xBB0020,  0xDB001D,  0xF8001A,
315	  0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
316	  0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
317	  0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
318	  0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
319	  0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
320	  0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
321	  0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
322	  0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
323	  0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
324	  0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
325
326	/* 1 --> gamma 1/2 */
327	{      0x7F,  0x800034,  0xB50028,  0xDE0021, 0x100001E, 0x11E001B,
328	  0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
329	  0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
330	  0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
331	  0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
332	  0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
333	  0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
334	  0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
335	  0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
336	  0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
337	  0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
338
339	/* 2 --> gamma 1/2.2 */
340	{      0x99,  0x9B0038,  0xD4002A,  0xFF0023, 0x122001F, 0x141001B,
341	  0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
342	  0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
343	  0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
344	  0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
345	  0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
346	  0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
347	  0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
348	  0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
349	  0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
350	  0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
351};
352
353static int isc_parse_dt(struct device *dev, struct isc_device *isc)
354{
355	struct device_node *np = dev->of_node;
356	struct device_node *epn;
357	struct isc_subdev_entity *subdev_entity;
358	unsigned int flags;
359
360	INIT_LIST_HEAD(&isc->subdev_entities);
361
362	for_each_endpoint_of_node(np, epn) {
363		struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
364		int ret;
365
366		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
367						 &v4l2_epn);
368		if (ret) {
369			of_node_put(epn);
370			dev_err(dev, "Could not parse the endpoint\n");
371			return -EINVAL;
372		}
373
374		subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
375					     GFP_KERNEL);
376		if (!subdev_entity) {
377			of_node_put(epn);
378			return -ENOMEM;
379		}
380		subdev_entity->epn = epn;
381
382		flags = v4l2_epn.bus.parallel.flags;
383
384		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
385			subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
386
387		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
388			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
389
390		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
391			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
392
393		if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
394			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
395					ISC_PFE_CFG0_CCIR656;
396
397		list_add_tail(&subdev_entity->list, &isc->subdev_entities);
398	}
399
400	return 0;
401}
402
403static int microchip_isc_probe(struct platform_device *pdev)
404{
405	struct device *dev = &pdev->dev;
406	struct isc_device *isc;
407	void __iomem *io_base;
408	struct isc_subdev_entity *subdev_entity;
409	int irq;
410	int ret;
411	u32 ver;
412
413	isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
414	if (!isc)
415		return -ENOMEM;
416
417	platform_set_drvdata(pdev, isc);
418	isc->dev = dev;
419
420	io_base = devm_platform_ioremap_resource(pdev, 0);
421	if (IS_ERR(io_base))
422		return PTR_ERR(io_base);
423
424	isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
425	if (IS_ERR(isc->regmap)) {
426		ret = PTR_ERR(isc->regmap);
427		dev_err(dev, "failed to init register map: %d\n", ret);
428		return ret;
429	}
430
431	irq = platform_get_irq(pdev, 0);
432	if (irq < 0)
433		return irq;
434
435	ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
436			       "microchip-sama5d2-isc", isc);
437	if (ret < 0) {
438		dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
439			irq, ret);
440		return ret;
441	}
442
443	isc->gamma_table = isc_sama5d2_gamma_table;
444	isc->gamma_max = 2;
445
446	isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
447	isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
448
449	isc->config_dpc = isc_sama5d2_config_dpc;
450	isc->config_csc = isc_sama5d2_config_csc;
451	isc->config_cbc = isc_sama5d2_config_cbc;
452	isc->config_cc = isc_sama5d2_config_cc;
453	isc->config_gam = isc_sama5d2_config_gam;
454	isc->config_rlp = isc_sama5d2_config_rlp;
455	isc->config_ctrls = isc_sama5d2_config_ctrls;
456
457	isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
458
459	isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
460	isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
461	isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
462	isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
463	isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
464	isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
465	isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
466	isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
467	isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
468
469	isc->controller_formats = sama5d2_controller_formats;
470	isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
471	isc->formats_list = sama5d2_formats_list;
472	isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
473
474	/* sama5d2-isc - 8 bits per beat */
475	isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
476
477	/* sama5d2-isc : ISPCK is required and mandatory */
478	isc->ispck_required = true;
479
480	ret = microchip_isc_pipeline_init(isc);
481	if (ret)
482		return ret;
483
484	isc->hclock = devm_clk_get(dev, "hclock");
485	if (IS_ERR(isc->hclock)) {
486		ret = PTR_ERR(isc->hclock);
487		dev_err(dev, "failed to get hclock: %d\n", ret);
488		return ret;
489	}
490
491	ret = clk_prepare_enable(isc->hclock);
492	if (ret) {
493		dev_err(dev, "failed to enable hclock: %d\n", ret);
494		return ret;
495	}
496
497	ret = microchip_isc_clk_init(isc);
498	if (ret) {
499		dev_err(dev, "failed to init isc clock: %d\n", ret);
500		goto unprepare_hclk;
501	}
502	ret = v4l2_device_register(dev, &isc->v4l2_dev);
503	if (ret) {
504		dev_err(dev, "unable to register v4l2 device.\n");
505		goto unprepare_clk;
506	}
507
508	ret = isc_parse_dt(dev, isc);
509	if (ret) {
510		dev_err(dev, "fail to parse device tree\n");
511		goto unregister_v4l2_device;
512	}
513
514	if (list_empty(&isc->subdev_entities)) {
515		dev_err(dev, "no subdev found\n");
516		ret = -ENODEV;
517		goto unregister_v4l2_device;
518	}
519
520	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
521		struct v4l2_async_connection *asd;
522		struct fwnode_handle *fwnode =
523			of_fwnode_handle(subdev_entity->epn);
524
525		v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);
526
527		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
528						      fwnode,
529						      struct v4l2_async_connection);
530
531		of_node_put(subdev_entity->epn);
532		subdev_entity->epn = NULL;
533
534		if (IS_ERR(asd)) {
535			ret = PTR_ERR(asd);
536			goto cleanup_subdev;
537		}
538
539		subdev_entity->notifier.ops = &microchip_isc_async_ops;
540
541		ret = v4l2_async_nf_register(&subdev_entity->notifier);
542		if (ret) {
543			dev_err(dev, "fail to register async notifier\n");
544			goto cleanup_subdev;
545		}
546
547		if (video_is_registered(&isc->video_dev))
548			break;
549	}
550
551	regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
552
553	ret = isc_mc_init(isc, ver);
554	if (ret < 0)
555		goto isc_probe_mc_init_err;
556
557	pm_runtime_set_active(dev);
558	pm_runtime_enable(dev);
559	pm_request_idle(dev);
560
561	isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
562
563	ret = clk_prepare_enable(isc->ispck);
564	if (ret) {
565		dev_err(dev, "failed to enable ispck: %d\n", ret);
566		goto disable_pm;
567	}
568
569	/* ispck should be greater or equal to hclock */
570	ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
571	if (ret) {
572		dev_err(dev, "failed to set ispck rate: %d\n", ret);
573		goto unprepare_clk;
574	}
575
576	dev_info(dev, "Microchip ISC version %x\n", ver);
577
578	return 0;
579
580unprepare_clk:
581	clk_disable_unprepare(isc->ispck);
582
583disable_pm:
584	pm_runtime_disable(dev);
585
586isc_probe_mc_init_err:
587	isc_mc_cleanup(isc);
588
589cleanup_subdev:
590	microchip_isc_subdev_cleanup(isc);
591
592unregister_v4l2_device:
593	v4l2_device_unregister(&isc->v4l2_dev);
594
595unprepare_hclk:
596	clk_disable_unprepare(isc->hclock);
597
598	microchip_isc_clk_cleanup(isc);
599
600	return ret;
601}
602
603static void microchip_isc_remove(struct platform_device *pdev)
604{
605	struct isc_device *isc = platform_get_drvdata(pdev);
606
607	pm_runtime_disable(&pdev->dev);
608
609	isc_mc_cleanup(isc);
610
611	microchip_isc_subdev_cleanup(isc);
612
613	v4l2_device_unregister(&isc->v4l2_dev);
614
615	clk_disable_unprepare(isc->ispck);
616	clk_disable_unprepare(isc->hclock);
617
618	microchip_isc_clk_cleanup(isc);
619}
620
621static int __maybe_unused isc_runtime_suspend(struct device *dev)
622{
623	struct isc_device *isc = dev_get_drvdata(dev);
624
625	clk_disable_unprepare(isc->ispck);
626	clk_disable_unprepare(isc->hclock);
627
628	return 0;
629}
630
631static int __maybe_unused isc_runtime_resume(struct device *dev)
632{
633	struct isc_device *isc = dev_get_drvdata(dev);
634	int ret;
635
636	ret = clk_prepare_enable(isc->hclock);
637	if (ret)
638		return ret;
639
640	ret = clk_prepare_enable(isc->ispck);
641	if (ret)
642		clk_disable_unprepare(isc->hclock);
643
644	return ret;
645}
646
647static const struct dev_pm_ops microchip_isc_dev_pm_ops = {
648	SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
649};
650
651#if IS_ENABLED(CONFIG_OF)
652static const struct of_device_id microchip_isc_of_match[] = {
653	{ .compatible = "atmel,sama5d2-isc" },
654	{ }
655};
656MODULE_DEVICE_TABLE(of, microchip_isc_of_match);
657#endif
658
659static struct platform_driver microchip_isc_driver = {
660	.probe	= microchip_isc_probe,
661	.remove = microchip_isc_remove,
662	.driver	= {
663		.name		= "microchip-sama5d2-isc",
664		.pm		= &microchip_isc_dev_pm_ops,
665		.of_match_table = of_match_ptr(microchip_isc_of_match),
666	},
667};
668
669module_platform_driver(microchip_isc_driver);
670
671MODULE_AUTHOR("Songjun Wu");
672MODULE_DESCRIPTION("The V4L2 driver for Microchip-ISC");
673MODULE_LICENSE("GPL v2");
~/ Read-only file preview.