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
27 static 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
47 static 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
71 static 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
96 const struct csiphy_formats csiphy_formats_8x16 = {
97 .nformats = ARRAY_SIZE(formats_8x16),
98 .formats = formats_8x16
99 };
100
101 const struct csiphy_formats csiphy_formats_8x96 = {
102 .nformats = ARRAY_SIZE(formats_8x96),
103 .formats = formats_8x96
104 };
105
106 const 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 */
csiphy_get_bpp(const struct csiphy_format_info * formats,unsigned int nformats,u32 code)119 static 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 */
csiphy_set_clock_rates(struct csiphy_device * csiphy)137 static 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 */
csiphy_set_power(struct v4l2_subdev * sd,int on)203 static 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 = csiphy_set_clock_rates(csiphy);
216 if (ret < 0) {
217 pm_runtime_put_sync(dev);
218 return ret;
219 }
220
221 ret = camss_enable_clocks(csiphy->nclocks, csiphy->clock, dev);
222 if (ret < 0) {
223 pm_runtime_put_sync(dev);
224 return ret;
225 }
226
227 enable_irq(csiphy->irq);
228
229 csiphy->res->hw_ops->reset(csiphy);
230
231 csiphy->res->hw_ops->hw_version_read(csiphy, dev);
232 } else {
233 disable_irq(csiphy->irq);
234
235 camss_disable_clocks(csiphy->nclocks, csiphy->clock);
236
237 pm_runtime_put_sync(dev);
238 }
239
240 return 0;
241 }
242
243 /*
244 * csiphy_stream_on - Enable streaming on CSIPHY module
245 * @csiphy: CSIPHY device
246 *
247 * Helper function to enable streaming on CSIPHY module.
248 * Main configuration of CSIPHY module is also done here.
249 *
250 * Return 0 on success or a negative error code otherwise
251 */
csiphy_stream_on(struct csiphy_device * csiphy)252 static int csiphy_stream_on(struct csiphy_device *csiphy)
253 {
254 struct csiphy_config *cfg = &csiphy->cfg;
255 s64 link_freq;
256 u8 lane_mask = csiphy->res->hw_ops->get_lane_mask(&cfg->csi2->lane_cfg);
257 u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
258 csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
259 u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
260 u8 val;
261
262 link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes);
263
264 if (link_freq < 0) {
265 dev_err(csiphy->camss->dev,
266 "Cannot get CSI2 transmitter's link frequency\n");
267 return -EINVAL;
268 }
269
270 if (csiphy->base_clk_mux) {
271 val = readl_relaxed(csiphy->base_clk_mux);
272 if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) {
273 val &= ~0xf0;
274 val |= cfg->csid_id << 4;
275 } else {
276 val &= ~0xf;
277 val |= cfg->csid_id;
278 }
279 writel_relaxed(val, csiphy->base_clk_mux);
280
281 /* Enforce reg write ordering between clk mux & lane enabling */
282 wmb();
283 }
284
285 csiphy->res->hw_ops->lanes_enable(csiphy, cfg, link_freq, lane_mask);
286
287 return 0;
288 }
289
290 /*
291 * csiphy_stream_off - Disable streaming on CSIPHY module
292 * @csiphy: CSIPHY device
293 *
294 * Helper function to disable streaming on CSIPHY module
295 */
csiphy_stream_off(struct csiphy_device * csiphy)296 static void csiphy_stream_off(struct csiphy_device *csiphy)
297 {
298 csiphy->res->hw_ops->lanes_disable(csiphy, &csiphy->cfg);
299 }
300
301
302 /*
303 * csiphy_set_stream - Enable/disable streaming on CSIPHY module
304 * @sd: CSIPHY V4L2 subdevice
305 * @enable: Requested streaming state
306 *
307 * Return 0 on success or a negative error code otherwise
308 */
csiphy_set_stream(struct v4l2_subdev * sd,int enable)309 static int csiphy_set_stream(struct v4l2_subdev *sd, int enable)
310 {
311 struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
312 int ret = 0;
313
314 if (enable)
315 ret = csiphy_stream_on(csiphy);
316 else
317 csiphy_stream_off(csiphy);
318
319 return ret;
320 }
321
322 /*
323 * __csiphy_get_format - Get pointer to format structure
324 * @csiphy: CSIPHY device
325 * @sd_state: V4L2 subdev state
326 * @pad: pad from which format is requested
327 * @which: TRY or ACTIVE format
328 *
329 * Return pointer to TRY or ACTIVE format structure
330 */
331 static struct v4l2_mbus_framefmt *
__csiphy_get_format(struct csiphy_device * csiphy,struct v4l2_subdev_state * sd_state,unsigned int pad,enum v4l2_subdev_format_whence which)332 __csiphy_get_format(struct csiphy_device *csiphy,
333 struct v4l2_subdev_state *sd_state,
334 unsigned int pad,
335 enum v4l2_subdev_format_whence which)
336 {
337 if (which == V4L2_SUBDEV_FORMAT_TRY)
338 return v4l2_subdev_state_get_format(sd_state, pad);
339
340 return &csiphy->fmt[pad];
341 }
342
343 /*
344 * csiphy_try_format - Handle try format by pad subdev method
345 * @csiphy: CSIPHY device
346 * @sd_state: V4L2 subdev state
347 * @pad: pad on which format is requested
348 * @fmt: pointer to v4l2 format structure
349 * @which: wanted subdev format
350 */
csiphy_try_format(struct csiphy_device * csiphy,struct v4l2_subdev_state * sd_state,unsigned int pad,struct v4l2_mbus_framefmt * fmt,enum v4l2_subdev_format_whence which)351 static void csiphy_try_format(struct csiphy_device *csiphy,
352 struct v4l2_subdev_state *sd_state,
353 unsigned int pad,
354 struct v4l2_mbus_framefmt *fmt,
355 enum v4l2_subdev_format_whence which)
356 {
357 unsigned int i;
358
359 switch (pad) {
360 case MSM_CSIPHY_PAD_SINK:
361 /* Set format on sink pad */
362
363 for (i = 0; i < csiphy->res->formats->nformats; i++)
364 if (fmt->code == csiphy->res->formats->formats[i].code)
365 break;
366
367 /* If not found, use UYVY as default */
368 if (i >= csiphy->res->formats->nformats)
369 fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
370
371 fmt->width = clamp_t(u32, fmt->width, 1, 8191);
372 fmt->height = clamp_t(u32, fmt->height, 1, 8191);
373
374 fmt->field = V4L2_FIELD_NONE;
375 fmt->colorspace = V4L2_COLORSPACE_SRGB;
376
377 break;
378
379 case MSM_CSIPHY_PAD_SRC:
380 /* Set and return a format same as sink pad */
381
382 *fmt = *__csiphy_get_format(csiphy, sd_state,
383 MSM_CSID_PAD_SINK,
384 which);
385
386 break;
387 }
388 }
389
390 /*
391 * csiphy_enum_mbus_code - Handle pixel format enumeration
392 * @sd: CSIPHY V4L2 subdevice
393 * @sd_state: V4L2 subdev state
394 * @code: pointer to v4l2_subdev_mbus_code_enum structure
395 * return -EINVAL or zero on success
396 */
csiphy_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)397 static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
398 struct v4l2_subdev_state *sd_state,
399 struct v4l2_subdev_mbus_code_enum *code)
400 {
401 struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
402 struct v4l2_mbus_framefmt *format;
403
404 if (code->pad == MSM_CSIPHY_PAD_SINK) {
405 if (code->index >= csiphy->res->formats->nformats)
406 return -EINVAL;
407
408 code->code = csiphy->res->formats->formats[code->index].code;
409 } else {
410 if (code->index > 0)
411 return -EINVAL;
412
413 format = __csiphy_get_format(csiphy, sd_state,
414 MSM_CSIPHY_PAD_SINK,
415 code->which);
416
417 code->code = format->code;
418 }
419
420 return 0;
421 }
422
423 /*
424 * csiphy_enum_frame_size - Handle frame size enumeration
425 * @sd: CSIPHY V4L2 subdevice
426 * @sd_state: V4L2 subdev state
427 * @fse: pointer to v4l2_subdev_frame_size_enum structure
428 * return -EINVAL or zero on success
429 */
csiphy_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)430 static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
431 struct v4l2_subdev_state *sd_state,
432 struct v4l2_subdev_frame_size_enum *fse)
433 {
434 struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
435 struct v4l2_mbus_framefmt format;
436
437 if (fse->index != 0)
438 return -EINVAL;
439
440 format.code = fse->code;
441 format.width = 1;
442 format.height = 1;
443 csiphy_try_format(csiphy, sd_state, fse->pad, &format, fse->which);
444 fse->min_width = format.width;
445 fse->min_height = format.height;
446
447 if (format.code != fse->code)
448 return -EINVAL;
449
450 format.code = fse->code;
451 format.width = -1;
452 format.height = -1;
453 csiphy_try_format(csiphy, sd_state, fse->pad, &format, fse->which);
454 fse->max_width = format.width;
455 fse->max_height = format.height;
456
457 return 0;
458 }
459
460 /*
461 * csiphy_get_format - Handle get format by pads subdev method
462 * @sd: CSIPHY V4L2 subdevice
463 * @sd_state: V4L2 subdev state
464 * @fmt: pointer to v4l2 subdev format structure
465 *
466 * Return -EINVAL or zero on success
467 */
csiphy_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)468 static int csiphy_get_format(struct v4l2_subdev *sd,
469 struct v4l2_subdev_state *sd_state,
470 struct v4l2_subdev_format *fmt)
471 {
472 struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
473 struct v4l2_mbus_framefmt *format;
474
475 format = __csiphy_get_format(csiphy, sd_state, fmt->pad, fmt->which);
476 if (format == NULL)
477 return -EINVAL;
478
479 fmt->format = *format;
480
481 return 0;
482 }
483
484 /*
485 * csiphy_set_format - Handle set format by pads subdev method
486 * @sd: CSIPHY V4L2 subdevice
487 * @sd_state: V4L2 subdev state
488 * @fmt: pointer to v4l2 subdev format structure
489 *
490 * Return -EINVAL or zero on success
491 */
csiphy_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)492 static int csiphy_set_format(struct v4l2_subdev *sd,
493 struct v4l2_subdev_state *sd_state,
494 struct v4l2_subdev_format *fmt)
495 {
496 struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
497 struct v4l2_mbus_framefmt *format;
498
499 format = __csiphy_get_format(csiphy, sd_state, fmt->pad, fmt->which);
500 if (format == NULL)
501 return -EINVAL;
502
503 csiphy_try_format(csiphy, sd_state, fmt->pad, &fmt->format,
504 fmt->which);
505 *format = fmt->format;
506
507 /* Propagate the format from sink to source */
508 if (fmt->pad == MSM_CSIPHY_PAD_SINK) {
509 format = __csiphy_get_format(csiphy, sd_state,
510 MSM_CSIPHY_PAD_SRC,
511 fmt->which);
512
513 *format = fmt->format;
514 csiphy_try_format(csiphy, sd_state, MSM_CSIPHY_PAD_SRC,
515 format,
516 fmt->which);
517 }
518
519 return 0;
520 }
521
522 /*
523 * csiphy_init_formats - Initialize formats on all pads
524 * @sd: CSIPHY V4L2 subdevice
525 * @fh: V4L2 subdev file handle
526 *
527 * Initialize all pad formats with default values.
528 *
529 * Return 0 on success or a negative error code otherwise
530 */
csiphy_init_formats(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)531 static int csiphy_init_formats(struct v4l2_subdev *sd,
532 struct v4l2_subdev_fh *fh)
533 {
534 struct v4l2_subdev_format format = {
535 .pad = MSM_CSIPHY_PAD_SINK,
536 .which = fh ? V4L2_SUBDEV_FORMAT_TRY :
537 V4L2_SUBDEV_FORMAT_ACTIVE,
538 .format = {
539 .code = MEDIA_BUS_FMT_UYVY8_1X16,
540 .width = 1920,
541 .height = 1080
542 }
543 };
544
545 return csiphy_set_format(sd, fh ? fh->state : NULL, &format);
546 }
547
csiphy_match_clock_name(const char * clock_name,const char * format,int index)548 static bool csiphy_match_clock_name(const char *clock_name, const char *format,
549 int index)
550 {
551 char name[16]; /* csiphyXXX_timer\0 */
552
553 snprintf(name, sizeof(name), format, index);
554 return !strcmp(clock_name, name);
555 }
556
557 /*
558 * msm_csiphy_subdev_init - Initialize CSIPHY device structure and resources
559 * @csiphy: CSIPHY device
560 * @res: CSIPHY module resources table
561 * @id: CSIPHY module id
562 *
563 * Return 0 on success or a negative error code otherwise
564 */
msm_csiphy_subdev_init(struct camss * camss,struct csiphy_device * csiphy,const struct camss_subdev_resources * res,u8 id)565 int msm_csiphy_subdev_init(struct camss *camss,
566 struct csiphy_device *csiphy,
567 const struct camss_subdev_resources *res, u8 id)
568 {
569 struct device *dev = camss->dev;
570 struct platform_device *pdev = to_platform_device(dev);
571 int i, j, k;
572 int ret;
573
574 csiphy->camss = camss;
575 csiphy->id = id;
576 csiphy->cfg.combo_mode = 0;
577 csiphy->res = &res->csiphy;
578
579 /* Memory */
580
581 csiphy->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
582 if (IS_ERR(csiphy->base))
583 return PTR_ERR(csiphy->base);
584
585 if (camss->res->version == CAMSS_8x16 ||
586 camss->res->version == CAMSS_8x96) {
587 csiphy->base_clk_mux =
588 devm_platform_ioremap_resource_byname(pdev, res->reg[1]);
589 if (IS_ERR(csiphy->base_clk_mux))
590 return PTR_ERR(csiphy->base_clk_mux);
591 } else {
592 csiphy->base_clk_mux = NULL;
593 }
594
595 /* Interrupt */
596
597 ret = platform_get_irq_byname(pdev, res->interrupt[0]);
598 if (ret < 0)
599 return ret;
600
601 csiphy->irq = ret;
602 snprintf(csiphy->irq_name, sizeof(csiphy->irq_name), "%s_%s%d",
603 dev_name(dev), MSM_CSIPHY_NAME, csiphy->id);
604
605 ret = devm_request_irq(dev, csiphy->irq, csiphy->res->hw_ops->isr,
606 IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
607 csiphy->irq_name, csiphy);
608 if (ret < 0) {
609 dev_err(dev, "request_irq failed: %d\n", ret);
610 return ret;
611 }
612
613 /* Clocks */
614
615 csiphy->nclocks = 0;
616 while (res->clock[csiphy->nclocks])
617 csiphy->nclocks++;
618
619 csiphy->clock = devm_kcalloc(dev,
620 csiphy->nclocks, sizeof(*csiphy->clock),
621 GFP_KERNEL);
622 if (!csiphy->clock)
623 return -ENOMEM;
624
625 csiphy->rate_set = devm_kcalloc(dev,
626 csiphy->nclocks,
627 sizeof(*csiphy->rate_set),
628 GFP_KERNEL);
629 if (!csiphy->rate_set)
630 return -ENOMEM;
631
632 for (i = 0; i < csiphy->nclocks; i++) {
633 struct camss_clock *clock = &csiphy->clock[i];
634
635 clock->clk = devm_clk_get(dev, res->clock[i]);
636 if (IS_ERR(clock->clk))
637 return PTR_ERR(clock->clk);
638
639 clock->name = res->clock[i];
640
641 clock->nfreqs = 0;
642 while (res->clock_rate[i][clock->nfreqs])
643 clock->nfreqs++;
644
645 if (!clock->nfreqs) {
646 clock->freq = NULL;
647 continue;
648 }
649
650 clock->freq = devm_kcalloc(dev,
651 clock->nfreqs,
652 sizeof(*clock->freq),
653 GFP_KERNEL);
654 if (!clock->freq)
655 return -ENOMEM;
656
657 for (j = 0; j < clock->nfreqs; j++)
658 clock->freq[j] = res->clock_rate[i][j];
659
660 for (k = 0; k < camss->res->csiphy_num; k++) {
661 csiphy->rate_set[i] = csiphy_match_clock_name(clock->name,
662 "csiphy%d_timer", k);
663 if (csiphy->rate_set[i])
664 break;
665
666 if (camss->res->version == CAMSS_660) {
667 csiphy->rate_set[i] = csiphy_match_clock_name(clock->name,
668 "csi%d_phy", k);
669 if (csiphy->rate_set[i])
670 break;
671 }
672
673 csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, "csiphy%d", k);
674 if (csiphy->rate_set[i])
675 break;
676 }
677 }
678
679 return 0;
680 }
681
682 /*
683 * csiphy_link_setup - Setup CSIPHY connections
684 * @entity: Pointer to media entity structure
685 * @local: Pointer to local pad
686 * @remote: Pointer to remote pad
687 * @flags: Link flags
688 *
689 * Rreturn 0 on success
690 */
csiphy_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)691 static int csiphy_link_setup(struct media_entity *entity,
692 const struct media_pad *local,
693 const struct media_pad *remote, u32 flags)
694 {
695 if ((local->flags & MEDIA_PAD_FL_SOURCE) &&
696 (flags & MEDIA_LNK_FL_ENABLED)) {
697 struct v4l2_subdev *sd;
698 struct csiphy_device *csiphy;
699 struct csid_device *csid;
700
701 if (media_pad_remote_pad_first(local))
702 return -EBUSY;
703
704 sd = media_entity_to_v4l2_subdev(entity);
705 csiphy = v4l2_get_subdevdata(sd);
706
707 sd = media_entity_to_v4l2_subdev(remote->entity);
708 csid = v4l2_get_subdevdata(sd);
709
710 csiphy->cfg.csid_id = csid->id;
711 }
712
713 return 0;
714 }
715
716 static const struct v4l2_subdev_core_ops csiphy_core_ops = {
717 .s_power = csiphy_set_power,
718 };
719
720 static const struct v4l2_subdev_video_ops csiphy_video_ops = {
721 .s_stream = csiphy_set_stream,
722 };
723
724 static const struct v4l2_subdev_pad_ops csiphy_pad_ops = {
725 .enum_mbus_code = csiphy_enum_mbus_code,
726 .enum_frame_size = csiphy_enum_frame_size,
727 .get_fmt = csiphy_get_format,
728 .set_fmt = csiphy_set_format,
729 };
730
731 static const struct v4l2_subdev_ops csiphy_v4l2_ops = {
732 .core = &csiphy_core_ops,
733 .video = &csiphy_video_ops,
734 .pad = &csiphy_pad_ops,
735 };
736
737 static const struct v4l2_subdev_internal_ops csiphy_v4l2_internal_ops = {
738 .open = csiphy_init_formats,
739 };
740
741 static const struct media_entity_operations csiphy_media_ops = {
742 .link_setup = csiphy_link_setup,
743 .link_validate = v4l2_subdev_link_validate,
744 };
745
746 /*
747 * msm_csiphy_register_entity - Register subdev node for CSIPHY module
748 * @csiphy: CSIPHY device
749 * @v4l2_dev: V4L2 device
750 *
751 * Return 0 on success or a negative error code otherwise
752 */
msm_csiphy_register_entity(struct csiphy_device * csiphy,struct v4l2_device * v4l2_dev)753 int msm_csiphy_register_entity(struct csiphy_device *csiphy,
754 struct v4l2_device *v4l2_dev)
755 {
756 struct v4l2_subdev *sd = &csiphy->subdev;
757 struct media_pad *pads = csiphy->pads;
758 struct device *dev = csiphy->camss->dev;
759 int ret;
760
761 v4l2_subdev_init(sd, &csiphy_v4l2_ops);
762 sd->internal_ops = &csiphy_v4l2_internal_ops;
763 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
764 snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
765 MSM_CSIPHY_NAME, csiphy->id);
766 v4l2_set_subdevdata(sd, csiphy);
767
768 ret = csiphy_init_formats(sd, NULL);
769 if (ret < 0) {
770 dev_err(dev, "Failed to init format: %d\n", ret);
771 return ret;
772 }
773
774 pads[MSM_CSIPHY_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
775 pads[MSM_CSIPHY_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
776
777 sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
778 sd->entity.ops = &csiphy_media_ops;
779 ret = media_entity_pads_init(&sd->entity, MSM_CSIPHY_PADS_NUM, pads);
780 if (ret < 0) {
781 dev_err(dev, "Failed to init media entity: %d\n", ret);
782 return ret;
783 }
784
785 ret = v4l2_device_register_subdev(v4l2_dev, sd);
786 if (ret < 0) {
787 dev_err(dev, "Failed to register subdev: %d\n", ret);
788 media_entity_cleanup(&sd->entity);
789 }
790
791 return ret;
792 }
793
794 /*
795 * msm_csiphy_unregister_entity - Unregister CSIPHY module subdev node
796 * @csiphy: CSIPHY device
797 */
msm_csiphy_unregister_entity(struct csiphy_device * csiphy)798 void msm_csiphy_unregister_entity(struct csiphy_device *csiphy)
799 {
800 v4l2_device_unregister_subdev(&csiphy->subdev);
801 media_entity_cleanup(&csiphy->subdev.entity);
802 }
803