File Index
Files and directories
Sign in
FILE

camss-csiphy.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/qcom/camss/camss-csiphy.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * camss-csiphy.c
  4 *
  5 * Qualcomm MSM Camera Subsystem - CSIPHY Module
  6 *
  7 * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
  8 * Copyright (C) 2016-2018 Linaro Ltd.
  9 */
 10#include <linux/clk.h>
 11#include <linux/delay.h>
 12#include <linux/interrupt.h>
 13#include <linux/io.h>
 14#include <linux/kernel.h>
 15#include <linux/of.h>
 16#include <linux/platform_device.h>
 17#include <linux/pm_runtime.h>
 18#include <media/media-entity.h>
 19#include <media/v4l2-device.h>
 20#include <media/v4l2-subdev.h>
 21
 22#include "camss-csiphy.h"
 23#include "camss.h"
 24
 25#define MSM_CSIPHY_NAME "msm_csiphy"
 26
 27static const struct csiphy_format_info formats_8x16[] = {
 28	{ MEDIA_BUS_FMT_UYVY8_1X16, 8 },
 29	{ MEDIA_BUS_FMT_VYUY8_1X16, 8 },
 30	{ MEDIA_BUS_FMT_YUYV8_1X16, 8 },
 31	{ MEDIA_BUS_FMT_YVYU8_1X16, 8 },
 32	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
 33	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
 34	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
 35	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
 36	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
 37	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
 38	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
 39	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
 40	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
 41	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
 42	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
 43	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
 44	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
 45};
 46
 47static const struct csiphy_format_info formats_8x96[] = {
 48	{ MEDIA_BUS_FMT_UYVY8_1X16, 8 },
 49	{ MEDIA_BUS_FMT_VYUY8_1X16, 8 },
 50	{ MEDIA_BUS_FMT_YUYV8_1X16, 8 },
 51	{ MEDIA_BUS_FMT_YVYU8_1X16, 8 },
 52	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
 53	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
 54	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
 55	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
 56	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
 57	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
 58	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
 59	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
 60	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
 61	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
 62	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
 63	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
 64	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
 65	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
 66	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
 67	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
 68	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
 69};
 70
 71static const struct csiphy_format_info formats_sdm845[] = {
 72	{ MEDIA_BUS_FMT_UYVY8_1X16, 8 },
 73	{ MEDIA_BUS_FMT_VYUY8_1X16, 8 },
 74	{ MEDIA_BUS_FMT_YUYV8_1X16, 8 },
 75	{ MEDIA_BUS_FMT_YVYU8_1X16, 8 },
 76	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
 77	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
 78	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
 79	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
 80	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
 81	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
 82	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
 83	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
 84	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
 85	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
 86	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
 87	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
 88	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
 89	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
 90	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
 91	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
 92	{ MEDIA_BUS_FMT_Y8_1X8, 8 },
 93	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
 94};
 95
 96const struct csiphy_formats csiphy_formats_8x16 = {
 97	.nformats = ARRAY_SIZE(formats_8x16),
 98	.formats = formats_8x16
 99};
100
101const struct csiphy_formats csiphy_formats_8x96 = {
102	.nformats = ARRAY_SIZE(formats_8x96),
103	.formats = formats_8x96
104};
105
106const struct csiphy_formats csiphy_formats_sdm845 = {
107	.nformats = ARRAY_SIZE(formats_sdm845),
108	.formats = formats_sdm845
109};
110
111/*
112 * csiphy_get_bpp - map media bus format to bits per pixel
113 * @formats: supported media bus formats array
114 * @nformats: size of @formats array
115 * @code: media bus format code
116 *
117 * Return number of bits per pixel
118 */
119static u8 csiphy_get_bpp(const struct csiphy_format_info *formats,
120			 unsigned int nformats, u32 code)
121{
122	unsigned int i;
123
124	for (i = 0; i < nformats; i++)
125		if (code == formats[i].code)
126			return formats[i].bpp;
127
128	WARN(1, "Unknown format\n");
129
130	return formats[0].bpp;
131}
132
133/*
134 * csiphy_set_clock_rates - Calculate and set clock rates on CSIPHY module
135 * @csiphy: CSIPHY device
136 */
137static int csiphy_set_clock_rates(struct csiphy_device *csiphy)
138{
139	struct device *dev = csiphy->camss->dev;
140	s64 link_freq;
141	int i, j;
142	int ret;
143
144	u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
145				csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
146	u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
147
148	link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
149	if (link_freq < 0)
150		link_freq  = 0;
151
152	for (i = 0; i < csiphy->nclocks; i++) {
153		struct camss_clock *clock = &csiphy->clock[i];
154
155		if (csiphy->rate_set[i]) {
156			u64 min_rate = link_freq / 4;
157			long round_rate;
158
159			camss_add_clock_margin(&min_rate);
160
161			for (j = 0; j < clock->nfreqs; j++)
162				if (min_rate < clock->freq[j])
163					break;
164
165			if (j == clock->nfreqs) {
166				dev_err(dev,
167					"Pixel clock is too high for CSIPHY\n");
168				return -EINVAL;
169			}
170
171			/* if sensor pixel clock is not available */
172			/* set highest possible CSIPHY clock rate */
173			if (min_rate == 0)
174				j = clock->nfreqs - 1;
175
176			round_rate = clk_round_rate(clock->clk, clock->freq[j]);
177			if (round_rate < 0) {
178				dev_err(dev, "clk round rate failed: %ld\n",
179					round_rate);
180				return -EINVAL;
181			}
182
183			csiphy->timer_clk_rate = round_rate;
184
185			ret = clk_set_rate(clock->clk, csiphy->timer_clk_rate);
186			if (ret < 0) {
187				dev_err(dev, "clk set rate failed: %d\n", ret);
188				return ret;
189			}
190		}
191	}
192
193	return 0;
194}
195
196/*
197 * csiphy_set_power - Power on/off CSIPHY module
198 * @sd: CSIPHY V4L2 subdevice
199 * @on: Requested power state
200 *
201 * Return 0 on success or a negative error code otherwise
202 */
203static int csiphy_set_power(struct v4l2_subdev *sd, int on)
204{
205	struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
206	struct device *dev = csiphy->camss->dev;
207
208	if (on) {
209		int ret;
210
211		ret = pm_runtime_resume_and_get(dev);
212		if (ret < 0)
213			return ret;
214
215		ret = regulator_bulk_enable(csiphy->num_supplies,
216					    csiphy->supplies);
217		if (ret < 0) {
218			pm_runtime_put_sync(dev);
219			return ret;
220		}
221
222		ret = csiphy_set_clock_rates(csiphy);
223		if (ret < 0) {
224			regulator_bulk_disable(csiphy->num_supplies,
225					       csiphy->supplies);
226			pm_runtime_put_sync(dev);
227			return ret;
228		}
229
230		ret = camss_enable_clocks(csiphy->nclocks, csiphy->clock, dev);
231		if (ret < 0) {
232			regulator_bulk_disable(csiphy->num_supplies,
233					       csiphy->supplies);
234			pm_runtime_put_sync(dev);
235			return ret;
236		}
237
238		enable_irq(csiphy->irq);
239
240		csiphy->res->hw_ops->reset(csiphy);
241
242		csiphy->res->hw_ops->hw_version_read(csiphy, dev);
243	} else {
244		disable_irq(csiphy->irq);
245
246		camss_disable_clocks(csiphy->nclocks, csiphy->clock);
247
248		regulator_bulk_disable(csiphy->num_supplies, csiphy->supplies);
249
250		pm_runtime_put_sync(dev);
251	}
252
253	return 0;
254}
255
256/*
257 * csiphy_stream_on - Enable streaming on CSIPHY module
258 * @csiphy: CSIPHY device
259 *
260 * Helper function to enable streaming on CSIPHY module.
261 * Main configuration of CSIPHY module is also done here.
262 *
263 * Return 0 on success or a negative error code otherwise
264 */
265static int csiphy_stream_on(struct csiphy_device *csiphy)
266{
267	struct csiphy_config *cfg = &csiphy->cfg;
268	s64 link_freq;
269	u8 lane_mask = csiphy->res->hw_ops->get_lane_mask(&cfg->csi2->lane_cfg);
270	u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
271				csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
272	u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
273	u8 val;
274
275	link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
276
277	if (link_freq < 0) {
278		dev_err(csiphy->camss->dev,
279			"Cannot get CSI2 transmitter's link frequency\n");
280		return -EINVAL;
281	}
282
283	if (csiphy->base_clk_mux) {
284		val = readl_relaxed(csiphy->base_clk_mux);
285		if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) {
286			val &= ~0xf0;
287			val |= cfg->csid_id << 4;
288		} else {
289			val &= ~0xf;
290			val |= cfg->csid_id;
291		}
292		writel_relaxed(val, csiphy->base_clk_mux);
293
294		/* Enforce reg write ordering between clk mux & lane enabling */
295		wmb();
296	}
297
298	csiphy->res->hw_ops->lanes_enable(csiphy, cfg, link_freq, lane_mask);
299
300	return 0;
301}
302
303/*
304 * csiphy_stream_off - Disable streaming on CSIPHY module
305 * @csiphy: CSIPHY device
306 *
307 * Helper function to disable streaming on CSIPHY module
308 */
309static void csiphy_stream_off(struct csiphy_device *csiphy)
310{
311	csiphy->res->hw_ops->lanes_disable(csiphy, &csiphy->cfg);
312}
313
314
315/*
316 * csiphy_set_stream - Enable/disable streaming on CSIPHY module
317 * @sd: CSIPHY V4L2 subdevice
318 * @enable: Requested streaming state
319 *
320 * Return 0 on success or a negative error code otherwise
321 */
322static int csiphy_set_stream(struct v4l2_subdev *sd, int enable)
323{
324	struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
325	int ret = 0;
326
327	if (enable)
328		ret = csiphy_stream_on(csiphy);
329	else
330		csiphy_stream_off(csiphy);
331
332	return ret;
333}
334
335/*
336 * __csiphy_get_format - Get pointer to format structure
337 * @csiphy: CSIPHY device
338 * @sd_state: V4L2 subdev state
339 * @pad: pad from which format is requested
340 * @which: TRY or ACTIVE format
341 *
342 * Return pointer to TRY or ACTIVE format structure
343 */
344static struct v4l2_mbus_framefmt *
345__csiphy_get_format(struct csiphy_device *csiphy,
346		    struct v4l2_subdev_state *sd_state,
347		    unsigned int pad,
348		    enum v4l2_subdev_format_whence which)
349{
350	if (which == V4L2_SUBDEV_FORMAT_TRY)
351		return v4l2_subdev_state_get_format(sd_state, pad);
352
353	return &csiphy->fmt[pad];
354}
355
356/*
357 * csiphy_try_format - Handle try format by pad subdev method
358 * @csiphy: CSIPHY device
359 * @sd_state: V4L2 subdev state
360 * @pad: pad on which format is requested
361 * @fmt: pointer to v4l2 format structure
362 * @which: wanted subdev format
363 */
364static void csiphy_try_format(struct csiphy_device *csiphy,
365			      struct v4l2_subdev_state *sd_state,
366			      unsigned int pad,
367			      struct v4l2_mbus_framefmt *fmt,
368			      enum v4l2_subdev_format_whence which)
369{
370	unsigned int i;
371
372	switch (pad) {
373	case MSM_CSIPHY_PAD_SINK:
374		/* Set format on sink pad */
375
376		for (i = 0; i < csiphy->res->formats->nformats; i++)
377			if (fmt->code == csiphy->res->formats->formats[i].code)
378				break;
379
380		/* If not found, use UYVY as default */
381		if (i >= csiphy->res->formats->nformats)
382			fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
383
384		fmt->width = clamp_t(u32, fmt->width, 1, 8191);
385		fmt->height = clamp_t(u32, fmt->height, 1, 8191);
386
387		fmt->field = V4L2_FIELD_NONE;
388		fmt->colorspace = V4L2_COLORSPACE_SRGB;
389
390		break;
391
392	case MSM_CSIPHY_PAD_SRC:
393		/* Set and return a format same as sink pad */
394
395		*fmt = *__csiphy_get_format(csiphy, sd_state,
396					    MSM_CSID_PAD_SINK,
397					    which);
398
399		break;
400	}
401}
402
403/*
404 * csiphy_enum_mbus_code - Handle pixel format enumeration
405 * @sd: CSIPHY V4L2 subdevice
406 * @sd_state: V4L2 subdev state
407 * @code: pointer to v4l2_subdev_mbus_code_enum structure
408 * return -EINVAL or zero on success
409 */
410static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
411				 struct v4l2_subdev_state *sd_state,
412				 struct v4l2_subdev_mbus_code_enum *code)
413{
414	struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
415	struct v4l2_mbus_framefmt *format;
416
417	if (code->pad == MSM_CSIPHY_PAD_SINK) {
418		if (code->index >= csiphy->res->formats->nformats)
419			return -EINVAL;
420
421		code->code = csiphy->res->formats->formats[code->index].code;
422	} else {
423		if (code->index > 0)
424			return -EINVAL;
425
426		format = __csiphy_get_format(csiphy, sd_state,
427					     MSM_CSIPHY_PAD_SINK,
428					     code->which);
429
430		code->code = format->code;
431	}
432
433	return 0;
434}
435
436/*
437 * csiphy_enum_frame_size - Handle frame size enumeration
438 * @sd: CSIPHY V4L2 subdevice
439 * @sd_state: V4L2 subdev state
440 * @fse: pointer to v4l2_subdev_frame_size_enum structure
441 * return -EINVAL or zero on success
442 */
443static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
444				  struct v4l2_subdev_state *sd_state,
445				  struct v4l2_subdev_frame_size_enum *fse)
446{
447	struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
448	struct v4l2_mbus_framefmt format;
449
450	if (fse->index != 0)
451		return -EINVAL;
452
453	format.code = fse->code;
454	format.width = 1;
455	format.height = 1;
456	csiphy_try_format(csiphy, sd_state, fse->pad, &format, fse->which);
457	fse->min_width = format.width;
458	fse->min_height = format.height;
459
460	if (format.code != fse->code)
461		return -EINVAL;
462
463	format.code = fse->code;
464	format.width = -1;
465	format.height = -1;
466	csiphy_try_format(csiphy, sd_state, fse->pad, &format, fse->which);
467	fse->max_width = format.width;
468	fse->max_height = format.height;
469
470	return 0;
471}
472
473/*
474 * csiphy_get_format - Handle get format by pads subdev method
475 * @sd: CSIPHY V4L2 subdevice
476 * @sd_state: V4L2 subdev state
477 * @fmt: pointer to v4l2 subdev format structure
478 *
479 * Return -EINVAL or zero on success
480 */
481static int csiphy_get_format(struct v4l2_subdev *sd,
482			     struct v4l2_subdev_state *sd_state,
483			     struct v4l2_subdev_format *fmt)
484{
485	struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
486	struct v4l2_mbus_framefmt *format;
487
488	format = __csiphy_get_format(csiphy, sd_state, fmt->pad, fmt->which);
489	if (format == NULL)
490		return -EINVAL;
491
492	fmt->format = *format;
493
494	return 0;
495}
496
497/*
498 * csiphy_set_format - Handle set format by pads subdev method
499 * @sd: CSIPHY V4L2 subdevice
500 * @sd_state: V4L2 subdev state
501 * @fmt: pointer to v4l2 subdev format structure
502 *
503 * Return -EINVAL or zero on success
504 */
505static int csiphy_set_format(struct v4l2_subdev *sd,
506			     struct v4l2_subdev_state *sd_state,
507			     struct v4l2_subdev_format *fmt)
508{
509	struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
510	struct v4l2_mbus_framefmt *format;
511
512	format = __csiphy_get_format(csiphy, sd_state, fmt->pad, fmt->which);
513	if (format == NULL)
514		return -EINVAL;
515
516	csiphy_try_format(csiphy, sd_state, fmt->pad, &fmt->format,
517			  fmt->which);
518	*format = fmt->format;
519
520	/* Propagate the format from sink to source */
521	if (fmt->pad == MSM_CSIPHY_PAD_SINK) {
522		format = __csiphy_get_format(csiphy, sd_state,
523					     MSM_CSIPHY_PAD_SRC,
524					     fmt->which);
525
526		*format = fmt->format;
527		csiphy_try_format(csiphy, sd_state, MSM_CSIPHY_PAD_SRC,
528				  format,
529				  fmt->which);
530	}
531
532	return 0;
533}
534
535/*
536 * csiphy_init_formats - Initialize formats on all pads
537 * @sd: CSIPHY V4L2 subdevice
538 * @fh: V4L2 subdev file handle
539 *
540 * Initialize all pad formats with default values.
541 *
542 * Return 0 on success or a negative error code otherwise
543 */
544static int csiphy_init_formats(struct v4l2_subdev *sd,
545			       struct v4l2_subdev_fh *fh)
546{
547	struct v4l2_subdev_format format = {
548		.pad = MSM_CSIPHY_PAD_SINK,
549		.which = fh ? V4L2_SUBDEV_FORMAT_TRY :
550			      V4L2_SUBDEV_FORMAT_ACTIVE,
551		.format = {
552			.code = MEDIA_BUS_FMT_UYVY8_1X16,
553			.width = 1920,
554			.height = 1080
555		}
556	};
557
558	return csiphy_set_format(sd, fh ? fh->state : NULL, &format);
559}
560
561static bool csiphy_match_clock_name(const char *clock_name, const char *format,
562				    int index)
563{
564	char name[16]; /* csiphyXXX_timer\0 */
565
566	snprintf(name, sizeof(name), format, index);
567	return !strcmp(clock_name, name);
568}
569
570/*
571 * msm_csiphy_subdev_init - Initialize CSIPHY device structure and resources
572 * @csiphy: CSIPHY device
573 * @res: CSIPHY module resources table
574 * @id: CSIPHY module id
575 *
576 * Return 0 on success or a negative error code otherwise
577 */
578int msm_csiphy_subdev_init(struct camss *camss,
579			   struct csiphy_device *csiphy,
580			   const struct camss_subdev_resources *res, u8 id)
581{
582	struct device *dev = camss->dev;
583	struct platform_device *pdev = to_platform_device(dev);
584	int i, j;
585	int ret;
586
587	csiphy->camss = camss;
588	csiphy->id = id;
589	csiphy->cfg.combo_mode = 0;
590	csiphy->res = &res->csiphy;
591
592	ret = csiphy->res->hw_ops->init(csiphy);
593	if (ret)
594		return ret;
595
596	/* Memory */
597
598	csiphy->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
599	if (IS_ERR(csiphy->base))
600		return PTR_ERR(csiphy->base);
601
602	if (camss->res->version == CAMSS_8x16 ||
603	    camss->res->version == CAMSS_8x39 ||
604	    camss->res->version == CAMSS_8x53 ||
605	    camss->res->version == CAMSS_8x96) {
606		csiphy->base_clk_mux =
607			devm_platform_ioremap_resource_byname(pdev, res->reg[1]);
608		if (IS_ERR(csiphy->base_clk_mux))
609			return PTR_ERR(csiphy->base_clk_mux);
610	} else {
611		csiphy->base_clk_mux = NULL;
612	}
613
614	/* Interrupt */
615
616	ret = platform_get_irq_byname(pdev, res->interrupt[0]);
617	if (ret < 0)
618		return ret;
619
620	csiphy->irq = ret;
621	snprintf(csiphy->irq_name, sizeof(csiphy->irq_name), "%s_%s%d",
622		 dev_name(dev), MSM_CSIPHY_NAME, csiphy->id);
623
624	ret = devm_request_irq(dev, csiphy->irq, csiphy->res->hw_ops->isr,
625			       IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
626			       csiphy->irq_name, csiphy);
627	if (ret < 0) {
628		dev_err(dev, "request_irq failed: %d\n", ret);
629		return ret;
630	}
631
632	/* Clocks */
633
634	csiphy->nclocks = 0;
635	while (res->clock[csiphy->nclocks])
636		csiphy->nclocks++;
637
638	csiphy->clock = devm_kcalloc(dev,
639				     csiphy->nclocks, sizeof(*csiphy->clock),
640				     GFP_KERNEL);
641	if (!csiphy->clock)
642		return -ENOMEM;
643
644	csiphy->rate_set = devm_kcalloc(dev,
645					csiphy->nclocks,
646					sizeof(*csiphy->rate_set),
647					GFP_KERNEL);
648	if (!csiphy->rate_set)
649		return -ENOMEM;
650
651	for (i = 0; i < csiphy->nclocks; i++) {
652		struct camss_clock *clock = &csiphy->clock[i];
653
654		clock->clk = devm_clk_get(dev, res->clock[i]);
655		if (IS_ERR(clock->clk))
656			return PTR_ERR(clock->clk);
657
658		clock->name = res->clock[i];
659
660		clock->nfreqs = 0;
661		while (res->clock_rate[i][clock->nfreqs])
662			clock->nfreqs++;
663
664		if (!clock->nfreqs) {
665			clock->freq = NULL;
666			continue;
667		}
668
669		clock->freq = devm_kcalloc(dev,
670					   clock->nfreqs,
671					   sizeof(*clock->freq),
672					   GFP_KERNEL);
673		if (!clock->freq)
674			return -ENOMEM;
675
676		for (j = 0; j < clock->nfreqs; j++)
677			clock->freq[j] = res->clock_rate[i][j];
678
679		csiphy->rate_set[i] = csiphy_match_clock_name(clock->name,
680							      "csiphy%d_timer",
681							      csiphy->id);
682		if (csiphy->rate_set[i])
683			continue;
684
685		if (camss->res->version == CAMSS_660) {
686			csiphy->rate_set[i] = csiphy_match_clock_name(clock->name,
687								      "csi%d_phy",
688								       csiphy->id);
689			if (csiphy->rate_set[i])
690				continue;
691		}
692
693		csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, "csiphy%d", csiphy->id);
694	}
695
696	/* CSIPHY supplies */
697	for (i = 0; i < ARRAY_SIZE(res->regulators); i++) {
698		if (res->regulators[i])
699			csiphy->num_supplies++;
700	}
701
702	if (csiphy->num_supplies) {
703		csiphy->supplies = devm_kmalloc_array(camss->dev,
704						      csiphy->num_supplies,
705						      sizeof(*csiphy->supplies),
706						      GFP_KERNEL);
707		if (!csiphy->supplies)
708			return -ENOMEM;
709	}
710
711	for (i = 0; i < csiphy->num_supplies; i++)
712		csiphy->supplies[i].supply = res->regulators[i];
713
714	ret = devm_regulator_bulk_get(camss->dev, csiphy->num_supplies,
715				      csiphy->supplies);
716	return ret;
717}
718
719/*
720 * csiphy_link_setup - Setup CSIPHY connections
721 * @entity: Pointer to media entity structure
722 * @local: Pointer to local pad
723 * @remote: Pointer to remote pad
724 * @flags: Link flags
725 *
726 * Rreturn 0 on success
727 */
728static int csiphy_link_setup(struct media_entity *entity,
729			     const struct media_pad *local,
730			     const struct media_pad *remote, u32 flags)
731{
732	if ((local->flags & MEDIA_PAD_FL_SOURCE) &&
733	    (flags & MEDIA_LNK_FL_ENABLED)) {
734		struct v4l2_subdev *sd;
735		struct csiphy_device *csiphy;
736		struct csid_device *csid;
737
738		if (media_pad_remote_pad_first(local))
739			return -EBUSY;
740
741		sd = media_entity_to_v4l2_subdev(entity);
742		csiphy = v4l2_get_subdevdata(sd);
743
744		sd = media_entity_to_v4l2_subdev(remote->entity);
745		csid = v4l2_get_subdevdata(sd);
746
747		csiphy->cfg.csid_id = csid->id;
748	}
749
750	return 0;
751}
752
753static const struct v4l2_subdev_core_ops csiphy_core_ops = {
754	.s_power = csiphy_set_power,
755};
756
757static const struct v4l2_subdev_video_ops csiphy_video_ops = {
758	.s_stream = csiphy_set_stream,
759};
760
761static const struct v4l2_subdev_pad_ops csiphy_pad_ops = {
762	.enum_mbus_code = csiphy_enum_mbus_code,
763	.enum_frame_size = csiphy_enum_frame_size,
764	.get_fmt = csiphy_get_format,
765	.set_fmt = csiphy_set_format,
766};
767
768static const struct v4l2_subdev_ops csiphy_v4l2_ops = {
769	.core = &csiphy_core_ops,
770	.video = &csiphy_video_ops,
771	.pad = &csiphy_pad_ops,
772};
773
774static const struct v4l2_subdev_internal_ops csiphy_v4l2_internal_ops = {
775	.open = csiphy_init_formats,
776};
777
778static const struct media_entity_operations csiphy_media_ops = {
779	.link_setup = csiphy_link_setup,
780	.link_validate = v4l2_subdev_link_validate,
781};
782
783/*
784 * msm_csiphy_register_entity - Register subdev node for CSIPHY module
785 * @csiphy: CSIPHY device
786 * @v4l2_dev: V4L2 device
787 *
788 * Return 0 on success or a negative error code otherwise
789 */
790int msm_csiphy_register_entity(struct csiphy_device *csiphy,
791			       struct v4l2_device *v4l2_dev)
792{
793	struct v4l2_subdev *sd = &csiphy->subdev;
794	struct media_pad *pads = csiphy->pads;
795	struct device *dev = csiphy->camss->dev;
796	int ret;
797
798	v4l2_subdev_init(sd, &csiphy_v4l2_ops);
799	sd->internal_ops = &csiphy_v4l2_internal_ops;
800	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
801	snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
802		 MSM_CSIPHY_NAME, csiphy->id);
803	v4l2_set_subdevdata(sd, csiphy);
804
805	ret = csiphy_init_formats(sd, NULL);
806	if (ret < 0) {
807		dev_err(dev, "Failed to init format: %d\n", ret);
808		return ret;
809	}
810
811	pads[MSM_CSIPHY_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
812	pads[MSM_CSIPHY_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
813
814	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
815	sd->entity.ops = &csiphy_media_ops;
816	ret = media_entity_pads_init(&sd->entity, MSM_CSIPHY_PADS_NUM, pads);
817	if (ret < 0) {
818		dev_err(dev, "Failed to init media entity: %d\n", ret);
819		return ret;
820	}
821
822	ret = v4l2_device_register_subdev(v4l2_dev, sd);
823	if (ret < 0) {
824		dev_err(dev, "Failed to register subdev: %d\n", ret);
825		media_entity_cleanup(&sd->entity);
826	}
827
828	return ret;
829}
830
831/*
832 * msm_csiphy_unregister_entity - Unregister CSIPHY module subdev node
833 * @csiphy: CSIPHY device
834 */
835void msm_csiphy_unregister_entity(struct csiphy_device *csiphy)
836{
837	v4l2_device_unregister_subdev(&csiphy->subdev);
838	media_entity_cleanup(&csiphy->subdev.entity);
839}
~/ Read-only file preview.