1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Driver for Analog Devices ADV748X 8 channel analog front end (AFE) receiver |
4 | * with standard definition processor (SDP) |
5 | * |
6 | * Copyright (C) 2017 Renesas Electronics Corp. |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/module.h> |
11 | #include <linux/mutex.h> |
12 | #include <linux/v4l2-dv-timings.h> |
13 | |
14 | #include <media/v4l2-ctrls.h> |
15 | #include <media/v4l2-device.h> |
16 | #include <media/v4l2-dv-timings.h> |
17 | #include <media/v4l2-ioctl.h> |
18 | |
19 | #include "adv748x.h" |
20 | |
21 | /* ----------------------------------------------------------------------------- |
22 | * SDP |
23 | */ |
24 | |
25 | #define ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 |
26 | #define ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 |
27 | #define ADV748X_AFE_STD_AD_PAL_N_NTSC_J_SECAM 0x2 |
28 | #define ADV748X_AFE_STD_AD_PAL_N_NTSC_M_SECAM 0x3 |
29 | #define ADV748X_AFE_STD_NTSC_J 0x4 |
30 | #define ADV748X_AFE_STD_NTSC_M 0x5 |
31 | #define ADV748X_AFE_STD_PAL60 0x6 |
32 | #define ADV748X_AFE_STD_NTSC_443 0x7 |
33 | #define ADV748X_AFE_STD_PAL_BG 0x8 |
34 | #define ADV748X_AFE_STD_PAL_N 0x9 |
35 | #define ADV748X_AFE_STD_PAL_M 0xa |
36 | #define ADV748X_AFE_STD_PAL_M_PED 0xb |
37 | #define ADV748X_AFE_STD_PAL_COMB_N 0xc |
38 | #define ADV748X_AFE_STD_PAL_COMB_N_PED 0xd |
39 | #define ADV748X_AFE_STD_PAL_SECAM 0xe |
40 | #define ADV748X_AFE_STD_PAL_SECAM_PED 0xf |
41 | |
42 | static int adv748x_afe_read_ro_map(struct adv748x_state *state, u8 reg) |
43 | { |
44 | int ret; |
45 | |
46 | /* Select SDP Read-Only Main Map */ |
47 | ret = sdp_write(state, ADV748X_SDP_MAP_SEL, |
48 | ADV748X_SDP_MAP_SEL_RO_MAIN); |
49 | if (ret < 0) |
50 | return ret; |
51 | |
52 | return sdp_read(state, reg); |
53 | } |
54 | |
55 | static int adv748x_afe_status(struct adv748x_afe *afe, u32 *signal, |
56 | v4l2_std_id *std) |
57 | { |
58 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
59 | int info; |
60 | |
61 | /* Read status from reg 0x10 of SDP RO Map */ |
62 | info = adv748x_afe_read_ro_map(state, ADV748X_SDP_RO_10); |
63 | if (info < 0) |
64 | return info; |
65 | |
66 | if (signal) |
67 | *signal = info & ADV748X_SDP_RO_10_IN_LOCK ? |
68 | 0 : V4L2_IN_ST_NO_SIGNAL; |
69 | |
70 | if (!std) |
71 | return 0; |
72 | |
73 | /* Standard not valid if there is no signal */ |
74 | if (!(info & ADV748X_SDP_RO_10_IN_LOCK)) { |
75 | *std = V4L2_STD_UNKNOWN; |
76 | return 0; |
77 | } |
78 | |
79 | switch (info & 0x70) { |
80 | case 0x00: |
81 | *std = V4L2_STD_NTSC; |
82 | break; |
83 | case 0x10: |
84 | *std = V4L2_STD_NTSC_443; |
85 | break; |
86 | case 0x20: |
87 | *std = V4L2_STD_PAL_M; |
88 | break; |
89 | case 0x30: |
90 | *std = V4L2_STD_PAL_60; |
91 | break; |
92 | case 0x40: |
93 | *std = V4L2_STD_PAL; |
94 | break; |
95 | case 0x50: |
96 | *std = V4L2_STD_SECAM; |
97 | break; |
98 | case 0x60: |
99 | *std = V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; |
100 | break; |
101 | case 0x70: |
102 | *std = V4L2_STD_SECAM; |
103 | break; |
104 | default: |
105 | *std = V4L2_STD_UNKNOWN; |
106 | break; |
107 | } |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static void adv748x_afe_fill_format(struct adv748x_afe *afe, |
113 | struct v4l2_mbus_framefmt *fmt) |
114 | { |
115 | memset(fmt, 0, sizeof(*fmt)); |
116 | |
117 | fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; |
118 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; |
119 | fmt->field = V4L2_FIELD_ALTERNATE; |
120 | |
121 | fmt->width = 720; |
122 | fmt->height = afe->curr_norm & V4L2_STD_525_60 ? 480 : 576; |
123 | |
124 | /* Field height */ |
125 | fmt->height /= 2; |
126 | } |
127 | |
128 | static int adv748x_afe_std(v4l2_std_id std) |
129 | { |
130 | if (std == V4L2_STD_PAL_60) |
131 | return ADV748X_AFE_STD_PAL60; |
132 | if (std == V4L2_STD_NTSC_443) |
133 | return ADV748X_AFE_STD_NTSC_443; |
134 | if (std == V4L2_STD_PAL_N) |
135 | return ADV748X_AFE_STD_PAL_N; |
136 | if (std == V4L2_STD_PAL_M) |
137 | return ADV748X_AFE_STD_PAL_M; |
138 | if (std == V4L2_STD_PAL_Nc) |
139 | return ADV748X_AFE_STD_PAL_COMB_N; |
140 | if (std & V4L2_STD_NTSC) |
141 | return ADV748X_AFE_STD_NTSC_M; |
142 | if (std & V4L2_STD_PAL) |
143 | return ADV748X_AFE_STD_PAL_BG; |
144 | if (std & V4L2_STD_SECAM) |
145 | return ADV748X_AFE_STD_PAL_SECAM; |
146 | |
147 | return -EINVAL; |
148 | } |
149 | |
150 | static void adv748x_afe_set_video_standard(struct adv748x_state *state, |
151 | int sdpstd) |
152 | { |
153 | sdp_clrset(state, ADV748X_SDP_VID_SEL, ADV748X_SDP_VID_SEL_MASK, |
154 | (sdpstd & 0xf) << ADV748X_SDP_VID_SEL_SHIFT); |
155 | } |
156 | |
157 | int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input) |
158 | { |
159 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
160 | |
161 | return sdp_write(state, ADV748X_SDP_INSEL, input); |
162 | } |
163 | |
164 | static int adv748x_afe_g_pixelaspect(struct v4l2_subdev *sd, |
165 | struct v4l2_fract *aspect) |
166 | { |
167 | struct adv748x_afe *afe = adv748x_sd_to_afe(sd); |
168 | |
169 | if (afe->curr_norm & V4L2_STD_525_60) { |
170 | aspect->numerator = 11; |
171 | aspect->denominator = 10; |
172 | } else { |
173 | aspect->numerator = 54; |
174 | aspect->denominator = 59; |
175 | } |
176 | |
177 | return 0; |
178 | } |
179 | |
180 | /* ----------------------------------------------------------------------------- |
181 | * v4l2_subdev_video_ops |
182 | */ |
183 | |
184 | static int adv748x_afe_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) |
185 | { |
186 | struct adv748x_afe *afe = adv748x_sd_to_afe(sd); |
187 | |
188 | *norm = afe->curr_norm; |
189 | |
190 | return 0; |
191 | } |
192 | |
193 | static int adv748x_afe_s_std(struct v4l2_subdev *sd, v4l2_std_id std) |
194 | { |
195 | struct adv748x_afe *afe = adv748x_sd_to_afe(sd); |
196 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
197 | int afe_std = adv748x_afe_std(std); |
198 | |
199 | if (afe_std < 0) |
200 | return afe_std; |
201 | |
202 | mutex_lock(&state->mutex); |
203 | |
204 | adv748x_afe_set_video_standard(state, sdpstd: afe_std); |
205 | afe->curr_norm = std; |
206 | |
207 | mutex_unlock(lock: &state->mutex); |
208 | |
209 | return 0; |
210 | } |
211 | |
212 | static int adv748x_afe_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) |
213 | { |
214 | struct adv748x_afe *afe = adv748x_sd_to_afe(sd); |
215 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
216 | int afe_std; |
217 | int ret; |
218 | |
219 | mutex_lock(&state->mutex); |
220 | |
221 | if (afe->streaming) { |
222 | ret = -EBUSY; |
223 | goto unlock; |
224 | } |
225 | |
226 | /* Set auto detect mode */ |
227 | adv748x_afe_set_video_standard(state, |
228 | ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM); |
229 | |
230 | msleep(msecs: 100); |
231 | |
232 | /* Read detected standard */ |
233 | ret = adv748x_afe_status(afe, NULL, std); |
234 | |
235 | afe_std = adv748x_afe_std(std: afe->curr_norm); |
236 | if (afe_std < 0) |
237 | goto unlock; |
238 | |
239 | /* Restore original state */ |
240 | adv748x_afe_set_video_standard(state, sdpstd: afe_std); |
241 | |
242 | unlock: |
243 | mutex_unlock(lock: &state->mutex); |
244 | |
245 | return ret; |
246 | } |
247 | |
248 | static int adv748x_afe_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) |
249 | { |
250 | *norm = V4L2_STD_ALL; |
251 | |
252 | return 0; |
253 | } |
254 | |
255 | static int adv748x_afe_g_input_status(struct v4l2_subdev *sd, u32 *status) |
256 | { |
257 | struct adv748x_afe *afe = adv748x_sd_to_afe(sd); |
258 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
259 | int ret; |
260 | |
261 | mutex_lock(&state->mutex); |
262 | |
263 | ret = adv748x_afe_status(afe, signal: status, NULL); |
264 | |
265 | mutex_unlock(lock: &state->mutex); |
266 | |
267 | return ret; |
268 | } |
269 | |
270 | static int adv748x_afe_s_stream(struct v4l2_subdev *sd, int enable) |
271 | { |
272 | struct adv748x_afe *afe = adv748x_sd_to_afe(sd); |
273 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
274 | u32 signal = V4L2_IN_ST_NO_SIGNAL; |
275 | int ret; |
276 | |
277 | mutex_lock(&state->mutex); |
278 | |
279 | if (enable) { |
280 | ret = adv748x_afe_s_input(afe, input: afe->input); |
281 | if (ret) |
282 | goto unlock; |
283 | } |
284 | |
285 | ret = adv748x_tx_power(tx: afe->tx, on: enable); |
286 | if (ret) |
287 | goto unlock; |
288 | |
289 | afe->streaming = enable; |
290 | |
291 | adv748x_afe_status(afe, signal: &signal, NULL); |
292 | if (signal != V4L2_IN_ST_NO_SIGNAL) |
293 | adv_dbg(state, "Detected SDP signal\n" ); |
294 | else |
295 | adv_dbg(state, "Couldn't detect SDP video signal\n" ); |
296 | |
297 | unlock: |
298 | mutex_unlock(lock: &state->mutex); |
299 | |
300 | return ret; |
301 | } |
302 | |
303 | static const struct v4l2_subdev_video_ops adv748x_afe_video_ops = { |
304 | .g_std = adv748x_afe_g_std, |
305 | .s_std = adv748x_afe_s_std, |
306 | .querystd = adv748x_afe_querystd, |
307 | .g_tvnorms = adv748x_afe_g_tvnorms, |
308 | .g_input_status = adv748x_afe_g_input_status, |
309 | .s_stream = adv748x_afe_s_stream, |
310 | .g_pixelaspect = adv748x_afe_g_pixelaspect, |
311 | }; |
312 | |
313 | /* ----------------------------------------------------------------------------- |
314 | * v4l2_subdev_pad_ops |
315 | */ |
316 | |
317 | static int adv748x_afe_propagate_pixelrate(struct adv748x_afe *afe) |
318 | { |
319 | struct v4l2_subdev *tx; |
320 | |
321 | tx = adv748x_get_remote_sd(pad: &afe->pads[ADV748X_AFE_SOURCE]); |
322 | if (!tx) |
323 | return -ENOLINK; |
324 | |
325 | /* |
326 | * The ADV748x ADC sampling frequency is twice the externally supplied |
327 | * clock whose frequency is required to be 28.63636 MHz. It oversamples |
328 | * with a factor of 4 resulting in a pixel rate of 14.3180180 MHz. |
329 | */ |
330 | return adv748x_csi2_set_pixelrate(sd: tx, rate: 14318180); |
331 | } |
332 | |
333 | static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd, |
334 | struct v4l2_subdev_state *sd_state, |
335 | struct v4l2_subdev_mbus_code_enum *code) |
336 | { |
337 | if (code->index != 0) |
338 | return -EINVAL; |
339 | |
340 | code->code = MEDIA_BUS_FMT_UYVY8_2X8; |
341 | |
342 | return 0; |
343 | } |
344 | |
345 | static int adv748x_afe_get_format(struct v4l2_subdev *sd, |
346 | struct v4l2_subdev_state *sd_state, |
347 | struct v4l2_subdev_format *sdformat) |
348 | { |
349 | struct adv748x_afe *afe = adv748x_sd_to_afe(sd); |
350 | struct v4l2_mbus_framefmt *mbusformat; |
351 | |
352 | /* It makes no sense to get the format of the analog sink pads */ |
353 | if (sdformat->pad != ADV748X_AFE_SOURCE) |
354 | return -EINVAL; |
355 | |
356 | if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) { |
357 | mbusformat = v4l2_subdev_state_get_format(sd_state, |
358 | sdformat->pad); |
359 | sdformat->format = *mbusformat; |
360 | } else { |
361 | adv748x_afe_fill_format(afe, fmt: &sdformat->format); |
362 | adv748x_afe_propagate_pixelrate(afe); |
363 | } |
364 | |
365 | return 0; |
366 | } |
367 | |
368 | static int adv748x_afe_set_format(struct v4l2_subdev *sd, |
369 | struct v4l2_subdev_state *sd_state, |
370 | struct v4l2_subdev_format *sdformat) |
371 | { |
372 | struct v4l2_mbus_framefmt *mbusformat; |
373 | |
374 | /* It makes no sense to get the format of the analog sink pads */ |
375 | if (sdformat->pad != ADV748X_AFE_SOURCE) |
376 | return -EINVAL; |
377 | |
378 | if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
379 | return adv748x_afe_get_format(sd, sd_state, sdformat); |
380 | |
381 | mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad); |
382 | *mbusformat = sdformat->format; |
383 | |
384 | return 0; |
385 | } |
386 | |
387 | static const struct v4l2_subdev_pad_ops adv748x_afe_pad_ops = { |
388 | .enum_mbus_code = adv748x_afe_enum_mbus_code, |
389 | .set_fmt = adv748x_afe_set_format, |
390 | .get_fmt = adv748x_afe_get_format, |
391 | }; |
392 | |
393 | /* ----------------------------------------------------------------------------- |
394 | * v4l2_subdev_ops |
395 | */ |
396 | |
397 | static const struct v4l2_subdev_ops adv748x_afe_ops = { |
398 | .video = &adv748x_afe_video_ops, |
399 | .pad = &adv748x_afe_pad_ops, |
400 | }; |
401 | |
402 | /* ----------------------------------------------------------------------------- |
403 | * Controls |
404 | */ |
405 | |
406 | static const char * const [] = { |
407 | "Disabled" , |
408 | "Solid Blue" , |
409 | "Color Bars" , |
410 | "Grey Ramp" , |
411 | "Cb Ramp" , |
412 | "Cr Ramp" , |
413 | "Boundary" |
414 | }; |
415 | |
416 | static int adv748x_afe_s_ctrl(struct v4l2_ctrl *ctrl) |
417 | { |
418 | struct adv748x_afe *afe = adv748x_ctrl_to_afe(ctrl); |
419 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
420 | bool enable; |
421 | int ret; |
422 | |
423 | ret = sdp_write(state, 0x0e, 0x00); |
424 | if (ret < 0) |
425 | return ret; |
426 | |
427 | switch (ctrl->id) { |
428 | case V4L2_CID_BRIGHTNESS: |
429 | ret = sdp_write(state, ADV748X_SDP_BRI, ctrl->val); |
430 | break; |
431 | case V4L2_CID_HUE: |
432 | /* Hue is inverted according to HSL chart */ |
433 | ret = sdp_write(state, ADV748X_SDP_HUE, -ctrl->val); |
434 | break; |
435 | case V4L2_CID_CONTRAST: |
436 | ret = sdp_write(state, ADV748X_SDP_CON, ctrl->val); |
437 | break; |
438 | case V4L2_CID_SATURATION: |
439 | ret = sdp_write(state, ADV748X_SDP_SD_SAT_U, ctrl->val); |
440 | if (ret) |
441 | break; |
442 | ret = sdp_write(state, ADV748X_SDP_SD_SAT_V, ctrl->val); |
443 | break; |
444 | case V4L2_CID_TEST_PATTERN: |
445 | enable = !!ctrl->val; |
446 | |
447 | /* Enable/Disable Color bar test patterns */ |
448 | ret = sdp_clrset(state, ADV748X_SDP_DEF, ADV748X_SDP_DEF_VAL_EN, |
449 | enable); |
450 | if (ret) |
451 | break; |
452 | ret = sdp_clrset(state, ADV748X_SDP_FRP, ADV748X_SDP_FRP_MASK, |
453 | enable ? ctrl->val - 1 : 0); |
454 | break; |
455 | default: |
456 | return -EINVAL; |
457 | } |
458 | |
459 | return ret; |
460 | } |
461 | |
462 | static const struct v4l2_ctrl_ops adv748x_afe_ctrl_ops = { |
463 | .s_ctrl = adv748x_afe_s_ctrl, |
464 | }; |
465 | |
466 | static int adv748x_afe_init_controls(struct adv748x_afe *afe) |
467 | { |
468 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
469 | |
470 | v4l2_ctrl_handler_init(&afe->ctrl_hdl, 5); |
471 | |
472 | /* Use our mutex for the controls */ |
473 | afe->ctrl_hdl.lock = &state->mutex; |
474 | |
475 | v4l2_ctrl_new_std(hdl: &afe->ctrl_hdl, ops: &adv748x_afe_ctrl_ops, |
476 | V4L2_CID_BRIGHTNESS, ADV748X_SDP_BRI_MIN, |
477 | ADV748X_SDP_BRI_MAX, step: 1, ADV748X_SDP_BRI_DEF); |
478 | v4l2_ctrl_new_std(hdl: &afe->ctrl_hdl, ops: &adv748x_afe_ctrl_ops, |
479 | V4L2_CID_CONTRAST, ADV748X_SDP_CON_MIN, |
480 | ADV748X_SDP_CON_MAX, step: 1, ADV748X_SDP_CON_DEF); |
481 | v4l2_ctrl_new_std(hdl: &afe->ctrl_hdl, ops: &adv748x_afe_ctrl_ops, |
482 | V4L2_CID_SATURATION, ADV748X_SDP_SAT_MIN, |
483 | ADV748X_SDP_SAT_MAX, step: 1, ADV748X_SDP_SAT_DEF); |
484 | v4l2_ctrl_new_std(hdl: &afe->ctrl_hdl, ops: &adv748x_afe_ctrl_ops, |
485 | V4L2_CID_HUE, ADV748X_SDP_HUE_MIN, |
486 | ADV748X_SDP_HUE_MAX, step: 1, ADV748X_SDP_HUE_DEF); |
487 | |
488 | v4l2_ctrl_new_std_menu_items(hdl: &afe->ctrl_hdl, ops: &adv748x_afe_ctrl_ops, |
489 | V4L2_CID_TEST_PATTERN, |
490 | ARRAY_SIZE(afe_ctrl_frp_menu) - 1, |
491 | mask: 0, def: 0, qmenu: afe_ctrl_frp_menu); |
492 | |
493 | afe->sd.ctrl_handler = &afe->ctrl_hdl; |
494 | if (afe->ctrl_hdl.error) { |
495 | v4l2_ctrl_handler_free(hdl: &afe->ctrl_hdl); |
496 | return afe->ctrl_hdl.error; |
497 | } |
498 | |
499 | return v4l2_ctrl_handler_setup(hdl: &afe->ctrl_hdl); |
500 | } |
501 | |
502 | int adv748x_afe_init(struct adv748x_afe *afe) |
503 | { |
504 | struct adv748x_state *state = adv748x_afe_to_state(afe); |
505 | int ret; |
506 | unsigned int i; |
507 | |
508 | afe->input = 0; |
509 | afe->streaming = false; |
510 | afe->curr_norm = V4L2_STD_NTSC_M; |
511 | |
512 | adv748x_subdev_init(sd: &afe->sd, state, ops: &adv748x_afe_ops, |
513 | MEDIA_ENT_F_ATV_DECODER, ident: "afe" ); |
514 | |
515 | /* Identify the first connector found as a default input if set */ |
516 | for (i = ADV748X_PORT_AIN0; i <= ADV748X_PORT_AIN7; i++) { |
517 | /* Inputs and ports are 1-indexed to match the data sheet */ |
518 | if (state->endpoints[i]) { |
519 | afe->input = i; |
520 | break; |
521 | } |
522 | } |
523 | |
524 | adv748x_afe_s_input(afe, input: afe->input); |
525 | |
526 | adv_dbg(state, "AFE Default input set to %d\n" , afe->input); |
527 | |
528 | /* Entity pads and sinks are 0-indexed to match the pads */ |
529 | for (i = ADV748X_AFE_SINK_AIN0; i <= ADV748X_AFE_SINK_AIN7; i++) |
530 | afe->pads[i].flags = MEDIA_PAD_FL_SINK; |
531 | |
532 | afe->pads[ADV748X_AFE_SOURCE].flags = MEDIA_PAD_FL_SOURCE; |
533 | |
534 | ret = media_entity_pads_init(entity: &afe->sd.entity, num_pads: ADV748X_AFE_NR_PADS, |
535 | pads: afe->pads); |
536 | if (ret) |
537 | return ret; |
538 | |
539 | ret = adv748x_afe_init_controls(afe); |
540 | if (ret) |
541 | goto error; |
542 | |
543 | return 0; |
544 | |
545 | error: |
546 | media_entity_cleanup(entity: &afe->sd.entity); |
547 | |
548 | return ret; |
549 | } |
550 | |
551 | void adv748x_afe_cleanup(struct adv748x_afe *afe) |
552 | { |
553 | v4l2_device_unregister_subdev(sd: &afe->sd); |
554 | media_entity_cleanup(entity: &afe->sd.entity); |
555 | v4l2_ctrl_handler_free(hdl: &afe->ctrl_hdl); |
556 | } |
557 | |