1e58f3082SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0+ 23e89586aSKieran Bingham /* 33e89586aSKieran Bingham * Driver for Analog Devices ADV748X 8 channel analog front end (AFE) receiver 43e89586aSKieran Bingham * with standard definition processor (SDP) 53e89586aSKieran Bingham * 63e89586aSKieran Bingham * Copyright (C) 2017 Renesas Electronics Corp. 73e89586aSKieran Bingham */ 83e89586aSKieran Bingham 93e89586aSKieran Bingham #include <linux/delay.h> 103e89586aSKieran Bingham #include <linux/module.h> 113e89586aSKieran Bingham #include <linux/mutex.h> 123e89586aSKieran Bingham #include <linux/v4l2-dv-timings.h> 133e89586aSKieran Bingham 143e89586aSKieran Bingham #include <media/v4l2-ctrls.h> 153e89586aSKieran Bingham #include <media/v4l2-device.h> 163e89586aSKieran Bingham #include <media/v4l2-dv-timings.h> 173e89586aSKieran Bingham #include <media/v4l2-ioctl.h> 183e89586aSKieran Bingham 193e89586aSKieran Bingham #include "adv748x.h" 203e89586aSKieran Bingham 213e89586aSKieran Bingham /* ----------------------------------------------------------------------------- 223e89586aSKieran Bingham * SDP 233e89586aSKieran Bingham */ 243e89586aSKieran Bingham 253e89586aSKieran Bingham #define ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 263e89586aSKieran Bingham #define ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 273e89586aSKieran Bingham #define ADV748X_AFE_STD_AD_PAL_N_NTSC_J_SECAM 0x2 283e89586aSKieran Bingham #define ADV748X_AFE_STD_AD_PAL_N_NTSC_M_SECAM 0x3 293e89586aSKieran Bingham #define ADV748X_AFE_STD_NTSC_J 0x4 303e89586aSKieran Bingham #define ADV748X_AFE_STD_NTSC_M 0x5 313e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL60 0x6 323e89586aSKieran Bingham #define ADV748X_AFE_STD_NTSC_443 0x7 333e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_BG 0x8 343e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_N 0x9 353e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_M 0xa 363e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_M_PED 0xb 373e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_COMB_N 0xc 383e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_COMB_N_PED 0xd 393e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_SECAM 0xe 403e89586aSKieran Bingham #define ADV748X_AFE_STD_PAL_SECAM_PED 0xf 413e89586aSKieran Bingham 423e89586aSKieran Bingham static int adv748x_afe_read_ro_map(struct adv748x_state *state, u8 reg) 433e89586aSKieran Bingham { 443e89586aSKieran Bingham int ret; 453e89586aSKieran Bingham 463e89586aSKieran Bingham /* Select SDP Read-Only Main Map */ 473e89586aSKieran Bingham ret = sdp_write(state, ADV748X_SDP_MAP_SEL, 483e89586aSKieran Bingham ADV748X_SDP_MAP_SEL_RO_MAIN); 493e89586aSKieran Bingham if (ret < 0) 503e89586aSKieran Bingham return ret; 513e89586aSKieran Bingham 523e89586aSKieran Bingham return sdp_read(state, reg); 533e89586aSKieran Bingham } 543e89586aSKieran Bingham 553e89586aSKieran Bingham static int adv748x_afe_status(struct adv748x_afe *afe, u32 *signal, 563e89586aSKieran Bingham v4l2_std_id *std) 573e89586aSKieran Bingham { 583e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 593e89586aSKieran Bingham int info; 603e89586aSKieran Bingham 613e89586aSKieran Bingham /* Read status from reg 0x10 of SDP RO Map */ 623e89586aSKieran Bingham info = adv748x_afe_read_ro_map(state, ADV748X_SDP_RO_10); 633e89586aSKieran Bingham if (info < 0) 643e89586aSKieran Bingham return info; 653e89586aSKieran Bingham 663e89586aSKieran Bingham if (signal) 673e89586aSKieran Bingham *signal = info & ADV748X_SDP_RO_10_IN_LOCK ? 683e89586aSKieran Bingham 0 : V4L2_IN_ST_NO_SIGNAL; 693e89586aSKieran Bingham 703e89586aSKieran Bingham if (!std) 713e89586aSKieran Bingham return 0; 723e89586aSKieran Bingham 733e89586aSKieran Bingham /* Standard not valid if there is no signal */ 743e89586aSKieran Bingham if (!(info & ADV748X_SDP_RO_10_IN_LOCK)) { 753e89586aSKieran Bingham *std = V4L2_STD_UNKNOWN; 763e89586aSKieran Bingham return 0; 773e89586aSKieran Bingham } 783e89586aSKieran Bingham 793e89586aSKieran Bingham switch (info & 0x70) { 803e89586aSKieran Bingham case 0x00: 813e89586aSKieran Bingham *std = V4L2_STD_NTSC; 823e89586aSKieran Bingham break; 833e89586aSKieran Bingham case 0x10: 843e89586aSKieran Bingham *std = V4L2_STD_NTSC_443; 853e89586aSKieran Bingham break; 863e89586aSKieran Bingham case 0x20: 873e89586aSKieran Bingham *std = V4L2_STD_PAL_M; 883e89586aSKieran Bingham break; 893e89586aSKieran Bingham case 0x30: 903e89586aSKieran Bingham *std = V4L2_STD_PAL_60; 913e89586aSKieran Bingham break; 923e89586aSKieran Bingham case 0x40: 933e89586aSKieran Bingham *std = V4L2_STD_PAL; 943e89586aSKieran Bingham break; 953e89586aSKieran Bingham case 0x50: 963e89586aSKieran Bingham *std = V4L2_STD_SECAM; 973e89586aSKieran Bingham break; 983e89586aSKieran Bingham case 0x60: 993e89586aSKieran Bingham *std = V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; 1003e89586aSKieran Bingham break; 1013e89586aSKieran Bingham case 0x70: 1023e89586aSKieran Bingham *std = V4L2_STD_SECAM; 1033e89586aSKieran Bingham break; 1043e89586aSKieran Bingham default: 1053e89586aSKieran Bingham *std = V4L2_STD_UNKNOWN; 1063e89586aSKieran Bingham break; 1073e89586aSKieran Bingham } 1083e89586aSKieran Bingham 1093e89586aSKieran Bingham return 0; 1103e89586aSKieran Bingham } 1113e89586aSKieran Bingham 1123e89586aSKieran Bingham static void adv748x_afe_fill_format(struct adv748x_afe *afe, 1133e89586aSKieran Bingham struct v4l2_mbus_framefmt *fmt) 1143e89586aSKieran Bingham { 1153e89586aSKieran Bingham memset(fmt, 0, sizeof(*fmt)); 1163e89586aSKieran Bingham 1173e89586aSKieran Bingham fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 1183e89586aSKieran Bingham fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 1193e89586aSKieran Bingham fmt->field = V4L2_FIELD_ALTERNATE; 1203e89586aSKieran Bingham 1213e89586aSKieran Bingham fmt->width = 720; 1223e89586aSKieran Bingham fmt->height = afe->curr_norm & V4L2_STD_525_60 ? 480 : 576; 1233e89586aSKieran Bingham 1243e89586aSKieran Bingham /* Field height */ 1253e89586aSKieran Bingham fmt->height /= 2; 1263e89586aSKieran Bingham } 1273e89586aSKieran Bingham 1283e89586aSKieran Bingham static int adv748x_afe_std(v4l2_std_id std) 1293e89586aSKieran Bingham { 1303e89586aSKieran Bingham if (std == V4L2_STD_PAL_60) 1313e89586aSKieran Bingham return ADV748X_AFE_STD_PAL60; 1323e89586aSKieran Bingham if (std == V4L2_STD_NTSC_443) 1333e89586aSKieran Bingham return ADV748X_AFE_STD_NTSC_443; 1343e89586aSKieran Bingham if (std == V4L2_STD_PAL_N) 1353e89586aSKieran Bingham return ADV748X_AFE_STD_PAL_N; 1363e89586aSKieran Bingham if (std == V4L2_STD_PAL_M) 1373e89586aSKieran Bingham return ADV748X_AFE_STD_PAL_M; 1383e89586aSKieran Bingham if (std == V4L2_STD_PAL_Nc) 1393e89586aSKieran Bingham return ADV748X_AFE_STD_PAL_COMB_N; 1403e89586aSKieran Bingham if (std & V4L2_STD_NTSC) 1413e89586aSKieran Bingham return ADV748X_AFE_STD_NTSC_M; 1423e89586aSKieran Bingham if (std & V4L2_STD_PAL) 1433e89586aSKieran Bingham return ADV748X_AFE_STD_PAL_BG; 1443e89586aSKieran Bingham if (std & V4L2_STD_SECAM) 1453e89586aSKieran Bingham return ADV748X_AFE_STD_PAL_SECAM; 1463e89586aSKieran Bingham 1473e89586aSKieran Bingham return -EINVAL; 1483e89586aSKieran Bingham } 1493e89586aSKieran Bingham 1503e89586aSKieran Bingham static void adv748x_afe_set_video_standard(struct adv748x_state *state, 1513e89586aSKieran Bingham int sdpstd) 1523e89586aSKieran Bingham { 1533e89586aSKieran Bingham sdp_clrset(state, ADV748X_SDP_VID_SEL, ADV748X_SDP_VID_SEL_MASK, 1543e89586aSKieran Bingham (sdpstd & 0xf) << ADV748X_SDP_VID_SEL_SHIFT); 1553e89586aSKieran Bingham } 1563e89586aSKieran Bingham 157c30ed81aSNiklas Söderlund int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input) 1583e89586aSKieran Bingham { 1593e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 1603e89586aSKieran Bingham 1613e89586aSKieran Bingham return sdp_write(state, ADV748X_SDP_INSEL, input); 1623e89586aSKieran Bingham } 1633e89586aSKieran Bingham 1643e89586aSKieran Bingham static int adv748x_afe_g_pixelaspect(struct v4l2_subdev *sd, 1653e89586aSKieran Bingham struct v4l2_fract *aspect) 1663e89586aSKieran Bingham { 1673e89586aSKieran Bingham struct adv748x_afe *afe = adv748x_sd_to_afe(sd); 1683e89586aSKieran Bingham 1693e89586aSKieran Bingham if (afe->curr_norm & V4L2_STD_525_60) { 1703e89586aSKieran Bingham aspect->numerator = 11; 1713e89586aSKieran Bingham aspect->denominator = 10; 1723e89586aSKieran Bingham } else { 1733e89586aSKieran Bingham aspect->numerator = 54; 1743e89586aSKieran Bingham aspect->denominator = 59; 1753e89586aSKieran Bingham } 1763e89586aSKieran Bingham 1773e89586aSKieran Bingham return 0; 1783e89586aSKieran Bingham } 1793e89586aSKieran Bingham 1803e89586aSKieran Bingham /* ----------------------------------------------------------------------------- 1813e89586aSKieran Bingham * v4l2_subdev_video_ops 1823e89586aSKieran Bingham */ 1833e89586aSKieran Bingham 1843e89586aSKieran Bingham static int adv748x_afe_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) 1853e89586aSKieran Bingham { 1863e89586aSKieran Bingham struct adv748x_afe *afe = adv748x_sd_to_afe(sd); 1873e89586aSKieran Bingham 1883e89586aSKieran Bingham *norm = afe->curr_norm; 1893e89586aSKieran Bingham 1903e89586aSKieran Bingham return 0; 1913e89586aSKieran Bingham } 1923e89586aSKieran Bingham 1933e89586aSKieran Bingham static int adv748x_afe_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 1943e89586aSKieran Bingham { 1953e89586aSKieran Bingham struct adv748x_afe *afe = adv748x_sd_to_afe(sd); 1963e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 1973e89586aSKieran Bingham int afe_std = adv748x_afe_std(std); 1983e89586aSKieran Bingham 1993e89586aSKieran Bingham if (afe_std < 0) 2003e89586aSKieran Bingham return afe_std; 2013e89586aSKieran Bingham 2023e89586aSKieran Bingham mutex_lock(&state->mutex); 2033e89586aSKieran Bingham 2043e89586aSKieran Bingham adv748x_afe_set_video_standard(state, afe_std); 2053e89586aSKieran Bingham afe->curr_norm = std; 2063e89586aSKieran Bingham 2073e89586aSKieran Bingham mutex_unlock(&state->mutex); 2083e89586aSKieran Bingham 2093e89586aSKieran Bingham return 0; 2103e89586aSKieran Bingham } 2113e89586aSKieran Bingham 2123e89586aSKieran Bingham static int adv748x_afe_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 2133e89586aSKieran Bingham { 2143e89586aSKieran Bingham struct adv748x_afe *afe = adv748x_sd_to_afe(sd); 2153e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 216bc66c99aSSimon Yuan int afe_std; 2173e89586aSKieran Bingham int ret; 2183e89586aSKieran Bingham 2193e89586aSKieran Bingham mutex_lock(&state->mutex); 2203e89586aSKieran Bingham 2213e89586aSKieran Bingham if (afe->streaming) { 2223e89586aSKieran Bingham ret = -EBUSY; 2233e89586aSKieran Bingham goto unlock; 2243e89586aSKieran Bingham } 2253e89586aSKieran Bingham 2263e89586aSKieran Bingham /* Set auto detect mode */ 2273e89586aSKieran Bingham adv748x_afe_set_video_standard(state, 2283e89586aSKieran Bingham ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM); 2293e89586aSKieran Bingham 2303e89586aSKieran Bingham msleep(100); 2313e89586aSKieran Bingham 2323e89586aSKieran Bingham /* Read detected standard */ 2333e89586aSKieran Bingham ret = adv748x_afe_status(afe, NULL, std); 2343e89586aSKieran Bingham 235bc66c99aSSimon Yuan afe_std = adv748x_afe_std(afe->curr_norm); 236bc66c99aSSimon Yuan if (afe_std < 0) 237bc66c99aSSimon Yuan goto unlock; 238bc66c99aSSimon Yuan 2393e89586aSKieran Bingham /* Restore original state */ 240bc66c99aSSimon Yuan adv748x_afe_set_video_standard(state, afe_std); 2413e89586aSKieran Bingham 2423e89586aSKieran Bingham unlock: 2433e89586aSKieran Bingham mutex_unlock(&state->mutex); 2443e89586aSKieran Bingham 2453e89586aSKieran Bingham return ret; 2463e89586aSKieran Bingham } 2473e89586aSKieran Bingham 2483e89586aSKieran Bingham static int adv748x_afe_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) 2493e89586aSKieran Bingham { 2503e89586aSKieran Bingham *norm = V4L2_STD_ALL; 2513e89586aSKieran Bingham 2523e89586aSKieran Bingham return 0; 2533e89586aSKieran Bingham } 2543e89586aSKieran Bingham 2553e89586aSKieran Bingham static int adv748x_afe_g_input_status(struct v4l2_subdev *sd, u32 *status) 2563e89586aSKieran Bingham { 2573e89586aSKieran Bingham struct adv748x_afe *afe = adv748x_sd_to_afe(sd); 2583e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 2593e89586aSKieran Bingham int ret; 2603e89586aSKieran Bingham 2613e89586aSKieran Bingham mutex_lock(&state->mutex); 2623e89586aSKieran Bingham 2633e89586aSKieran Bingham ret = adv748x_afe_status(afe, status, NULL); 2643e89586aSKieran Bingham 2653e89586aSKieran Bingham mutex_unlock(&state->mutex); 266b0fe7778SKieran Bingham 2673e89586aSKieran Bingham return ret; 2683e89586aSKieran Bingham } 2693e89586aSKieran Bingham 2703e89586aSKieran Bingham static int adv748x_afe_s_stream(struct v4l2_subdev *sd, int enable) 2713e89586aSKieran Bingham { 2723e89586aSKieran Bingham struct adv748x_afe *afe = adv748x_sd_to_afe(sd); 2733e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 2742b8677ecSNiklas Söderlund u32 signal = V4L2_IN_ST_NO_SIGNAL; 2752b8677ecSNiklas Söderlund int ret; 2763e89586aSKieran Bingham 2773e89586aSKieran Bingham mutex_lock(&state->mutex); 2783e89586aSKieran Bingham 2793e89586aSKieran Bingham if (enable) { 2803e89586aSKieran Bingham ret = adv748x_afe_s_input(afe, afe->input); 2813e89586aSKieran Bingham if (ret) 2823e89586aSKieran Bingham goto unlock; 2833e89586aSKieran Bingham } 2843e89586aSKieran Bingham 285a33df6acSJacopo Mondi ret = adv748x_tx_power(afe->tx, enable); 2863e89586aSKieran Bingham if (ret) 2873e89586aSKieran Bingham goto unlock; 2883e89586aSKieran Bingham 2893e89586aSKieran Bingham afe->streaming = enable; 2903e89586aSKieran Bingham 2913e89586aSKieran Bingham adv748x_afe_status(afe, &signal, NULL); 2923e89586aSKieran Bingham if (signal != V4L2_IN_ST_NO_SIGNAL) 2933e89586aSKieran Bingham adv_dbg(state, "Detected SDP signal\n"); 2943e89586aSKieran Bingham else 2953e89586aSKieran Bingham adv_dbg(state, "Couldn't detect SDP video signal\n"); 2963e89586aSKieran Bingham 2973e89586aSKieran Bingham unlock: 2983e89586aSKieran Bingham mutex_unlock(&state->mutex); 2993e89586aSKieran Bingham 3003e89586aSKieran Bingham return ret; 3013e89586aSKieran Bingham } 3023e89586aSKieran Bingham 3033e89586aSKieran Bingham static const struct v4l2_subdev_video_ops adv748x_afe_video_ops = { 3043e89586aSKieran Bingham .g_std = adv748x_afe_g_std, 3053e89586aSKieran Bingham .s_std = adv748x_afe_s_std, 3063e89586aSKieran Bingham .querystd = adv748x_afe_querystd, 3073e89586aSKieran Bingham .g_tvnorms = adv748x_afe_g_tvnorms, 3083e89586aSKieran Bingham .g_input_status = adv748x_afe_g_input_status, 3093e89586aSKieran Bingham .s_stream = adv748x_afe_s_stream, 3103e89586aSKieran Bingham .g_pixelaspect = adv748x_afe_g_pixelaspect, 3113e89586aSKieran Bingham }; 3123e89586aSKieran Bingham 3133e89586aSKieran Bingham /* ----------------------------------------------------------------------------- 3143e89586aSKieran Bingham * v4l2_subdev_pad_ops 3153e89586aSKieran Bingham */ 3163e89586aSKieran Bingham 3173e89586aSKieran Bingham static int adv748x_afe_propagate_pixelrate(struct adv748x_afe *afe) 3183e89586aSKieran Bingham { 3193e89586aSKieran Bingham struct v4l2_subdev *tx; 3203e89586aSKieran Bingham 3213e89586aSKieran Bingham tx = adv748x_get_remote_sd(&afe->pads[ADV748X_AFE_SOURCE]); 3223e89586aSKieran Bingham if (!tx) 3233e89586aSKieran Bingham return -ENOLINK; 3243e89586aSKieran Bingham 32550eea4abSLaurent Pinchart /* 32650eea4abSLaurent Pinchart * The ADV748x ADC sampling frequency is twice the externally supplied 32750eea4abSLaurent Pinchart * clock whose frequency is required to be 28.63636 MHz. It oversamples 32850eea4abSLaurent Pinchart * with a factor of 4 resulting in a pixel rate of 14.3180180 MHz. 32950eea4abSLaurent Pinchart */ 33050eea4abSLaurent Pinchart return adv748x_csi2_set_pixelrate(tx, 14318180); 3313e89586aSKieran Bingham } 3323e89586aSKieran Bingham 3333e89586aSKieran Bingham static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd, 334*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 3353e89586aSKieran Bingham struct v4l2_subdev_mbus_code_enum *code) 3363e89586aSKieran Bingham { 3373e89586aSKieran Bingham if (code->index != 0) 3383e89586aSKieran Bingham return -EINVAL; 3393e89586aSKieran Bingham 3403e89586aSKieran Bingham code->code = MEDIA_BUS_FMT_UYVY8_2X8; 3413e89586aSKieran Bingham 3423e89586aSKieran Bingham return 0; 3433e89586aSKieran Bingham } 3443e89586aSKieran Bingham 3453e89586aSKieran Bingham static int adv748x_afe_get_format(struct v4l2_subdev *sd, 346*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 3473e89586aSKieran Bingham struct v4l2_subdev_format *sdformat) 3483e89586aSKieran Bingham { 3493e89586aSKieran Bingham struct adv748x_afe *afe = adv748x_sd_to_afe(sd); 3503e89586aSKieran Bingham struct v4l2_mbus_framefmt *mbusformat; 3513e89586aSKieran Bingham 3523e89586aSKieran Bingham /* It makes no sense to get the format of the analog sink pads */ 3533e89586aSKieran Bingham if (sdformat->pad != ADV748X_AFE_SOURCE) 3543e89586aSKieran Bingham return -EINVAL; 3553e89586aSKieran Bingham 3563e89586aSKieran Bingham if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) { 357*0d346d2aSTomi Valkeinen mbusformat = v4l2_subdev_get_try_format(sd, sd_state, 358*0d346d2aSTomi Valkeinen sdformat->pad); 3593e89586aSKieran Bingham sdformat->format = *mbusformat; 3603e89586aSKieran Bingham } else { 3613e89586aSKieran Bingham adv748x_afe_fill_format(afe, &sdformat->format); 3623e89586aSKieran Bingham adv748x_afe_propagate_pixelrate(afe); 3633e89586aSKieran Bingham } 3643e89586aSKieran Bingham 3653e89586aSKieran Bingham return 0; 3663e89586aSKieran Bingham } 3673e89586aSKieran Bingham 3683e89586aSKieran Bingham static int adv748x_afe_set_format(struct v4l2_subdev *sd, 369*0d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 3703e89586aSKieran Bingham struct v4l2_subdev_format *sdformat) 3713e89586aSKieran Bingham { 3723e89586aSKieran Bingham struct v4l2_mbus_framefmt *mbusformat; 3733e89586aSKieran Bingham 3743e89586aSKieran Bingham /* It makes no sense to get the format of the analog sink pads */ 3753e89586aSKieran Bingham if (sdformat->pad != ADV748X_AFE_SOURCE) 3763e89586aSKieran Bingham return -EINVAL; 3773e89586aSKieran Bingham 3783e89586aSKieran Bingham if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) 379*0d346d2aSTomi Valkeinen return adv748x_afe_get_format(sd, sd_state, sdformat); 3803e89586aSKieran Bingham 381*0d346d2aSTomi Valkeinen mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad); 3823e89586aSKieran Bingham *mbusformat = sdformat->format; 3833e89586aSKieran Bingham 3843e89586aSKieran Bingham return 0; 3853e89586aSKieran Bingham } 3863e89586aSKieran Bingham 3873e89586aSKieran Bingham static const struct v4l2_subdev_pad_ops adv748x_afe_pad_ops = { 3883e89586aSKieran Bingham .enum_mbus_code = adv748x_afe_enum_mbus_code, 3893e89586aSKieran Bingham .set_fmt = adv748x_afe_set_format, 3903e89586aSKieran Bingham .get_fmt = adv748x_afe_get_format, 3913e89586aSKieran Bingham }; 3923e89586aSKieran Bingham 3933e89586aSKieran Bingham /* ----------------------------------------------------------------------------- 3943e89586aSKieran Bingham * v4l2_subdev_ops 3953e89586aSKieran Bingham */ 3963e89586aSKieran Bingham 3973e89586aSKieran Bingham static const struct v4l2_subdev_ops adv748x_afe_ops = { 3983e89586aSKieran Bingham .video = &adv748x_afe_video_ops, 3993e89586aSKieran Bingham .pad = &adv748x_afe_pad_ops, 4003e89586aSKieran Bingham }; 4013e89586aSKieran Bingham 4023e89586aSKieran Bingham /* ----------------------------------------------------------------------------- 4033e89586aSKieran Bingham * Controls 4043e89586aSKieran Bingham */ 4053e89586aSKieran Bingham 4063e89586aSKieran Bingham static const char * const afe_ctrl_frp_menu[] = { 4073e89586aSKieran Bingham "Disabled", 4083e89586aSKieran Bingham "Solid Blue", 4093e89586aSKieran Bingham "Color Bars", 4103e89586aSKieran Bingham "Grey Ramp", 4113e89586aSKieran Bingham "Cb Ramp", 4123e89586aSKieran Bingham "Cr Ramp", 4133e89586aSKieran Bingham "Boundary" 4143e89586aSKieran Bingham }; 4153e89586aSKieran Bingham 4163e89586aSKieran Bingham static int adv748x_afe_s_ctrl(struct v4l2_ctrl *ctrl) 4173e89586aSKieran Bingham { 4183e89586aSKieran Bingham struct adv748x_afe *afe = adv748x_ctrl_to_afe(ctrl); 4193e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 4203e89586aSKieran Bingham bool enable; 4213e89586aSKieran Bingham int ret; 4223e89586aSKieran Bingham 4233e89586aSKieran Bingham ret = sdp_write(state, 0x0e, 0x00); 4243e89586aSKieran Bingham if (ret < 0) 4253e89586aSKieran Bingham return ret; 4263e89586aSKieran Bingham 4273e89586aSKieran Bingham switch (ctrl->id) { 4283e89586aSKieran Bingham case V4L2_CID_BRIGHTNESS: 4293e89586aSKieran Bingham ret = sdp_write(state, ADV748X_SDP_BRI, ctrl->val); 4303e89586aSKieran Bingham break; 4313e89586aSKieran Bingham case V4L2_CID_HUE: 4323e89586aSKieran Bingham /* Hue is inverted according to HSL chart */ 4333e89586aSKieran Bingham ret = sdp_write(state, ADV748X_SDP_HUE, -ctrl->val); 4343e89586aSKieran Bingham break; 4353e89586aSKieran Bingham case V4L2_CID_CONTRAST: 4363e89586aSKieran Bingham ret = sdp_write(state, ADV748X_SDP_CON, ctrl->val); 4373e89586aSKieran Bingham break; 4383e89586aSKieran Bingham case V4L2_CID_SATURATION: 4393e89586aSKieran Bingham ret = sdp_write(state, ADV748X_SDP_SD_SAT_U, ctrl->val); 4403e89586aSKieran Bingham if (ret) 4413e89586aSKieran Bingham break; 4423e89586aSKieran Bingham ret = sdp_write(state, ADV748X_SDP_SD_SAT_V, ctrl->val); 4433e89586aSKieran Bingham break; 4443e89586aSKieran Bingham case V4L2_CID_TEST_PATTERN: 4453e89586aSKieran Bingham enable = !!ctrl->val; 4463e89586aSKieran Bingham 4473e89586aSKieran Bingham /* Enable/Disable Color bar test patterns */ 4483e89586aSKieran Bingham ret = sdp_clrset(state, ADV748X_SDP_DEF, ADV748X_SDP_DEF_VAL_EN, 4493e89586aSKieran Bingham enable); 4503e89586aSKieran Bingham if (ret) 4513e89586aSKieran Bingham break; 4523e89586aSKieran Bingham ret = sdp_clrset(state, ADV748X_SDP_FRP, ADV748X_SDP_FRP_MASK, 4533e89586aSKieran Bingham enable ? ctrl->val - 1 : 0); 4543e89586aSKieran Bingham break; 4553e89586aSKieran Bingham default: 4563e89586aSKieran Bingham return -EINVAL; 4573e89586aSKieran Bingham } 4583e89586aSKieran Bingham 4593e89586aSKieran Bingham return ret; 4603e89586aSKieran Bingham } 4613e89586aSKieran Bingham 4623e89586aSKieran Bingham static const struct v4l2_ctrl_ops adv748x_afe_ctrl_ops = { 4633e89586aSKieran Bingham .s_ctrl = adv748x_afe_s_ctrl, 4643e89586aSKieran Bingham }; 4653e89586aSKieran Bingham 4663e89586aSKieran Bingham static int adv748x_afe_init_controls(struct adv748x_afe *afe) 4673e89586aSKieran Bingham { 4683e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 4693e89586aSKieran Bingham 4703e89586aSKieran Bingham v4l2_ctrl_handler_init(&afe->ctrl_hdl, 5); 4713e89586aSKieran Bingham 4723e89586aSKieran Bingham /* Use our mutex for the controls */ 4733e89586aSKieran Bingham afe->ctrl_hdl.lock = &state->mutex; 4743e89586aSKieran Bingham 4753e89586aSKieran Bingham v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, 4763e89586aSKieran Bingham V4L2_CID_BRIGHTNESS, ADV748X_SDP_BRI_MIN, 4773e89586aSKieran Bingham ADV748X_SDP_BRI_MAX, 1, ADV748X_SDP_BRI_DEF); 4783e89586aSKieran Bingham v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, 4793e89586aSKieran Bingham V4L2_CID_CONTRAST, ADV748X_SDP_CON_MIN, 4803e89586aSKieran Bingham ADV748X_SDP_CON_MAX, 1, ADV748X_SDP_CON_DEF); 4813e89586aSKieran Bingham v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, 4823e89586aSKieran Bingham V4L2_CID_SATURATION, ADV748X_SDP_SAT_MIN, 4833e89586aSKieran Bingham ADV748X_SDP_SAT_MAX, 1, ADV748X_SDP_SAT_DEF); 4843e89586aSKieran Bingham v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, 4853e89586aSKieran Bingham V4L2_CID_HUE, ADV748X_SDP_HUE_MIN, 4863e89586aSKieran Bingham ADV748X_SDP_HUE_MAX, 1, ADV748X_SDP_HUE_DEF); 4873e89586aSKieran Bingham 4883e89586aSKieran Bingham v4l2_ctrl_new_std_menu_items(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, 4893e89586aSKieran Bingham V4L2_CID_TEST_PATTERN, 4903e89586aSKieran Bingham ARRAY_SIZE(afe_ctrl_frp_menu) - 1, 4913e89586aSKieran Bingham 0, 0, afe_ctrl_frp_menu); 4923e89586aSKieran Bingham 4933e89586aSKieran Bingham afe->sd.ctrl_handler = &afe->ctrl_hdl; 4943e89586aSKieran Bingham if (afe->ctrl_hdl.error) { 4953e89586aSKieran Bingham v4l2_ctrl_handler_free(&afe->ctrl_hdl); 4963e89586aSKieran Bingham return afe->ctrl_hdl.error; 4973e89586aSKieran Bingham } 4983e89586aSKieran Bingham 4993e89586aSKieran Bingham return v4l2_ctrl_handler_setup(&afe->ctrl_hdl); 5003e89586aSKieran Bingham } 5013e89586aSKieran Bingham 5023e89586aSKieran Bingham int adv748x_afe_init(struct adv748x_afe *afe) 5033e89586aSKieran Bingham { 5043e89586aSKieran Bingham struct adv748x_state *state = adv748x_afe_to_state(afe); 5053e89586aSKieran Bingham int ret; 5063e89586aSKieran Bingham unsigned int i; 5073e89586aSKieran Bingham 5083e89586aSKieran Bingham afe->input = 0; 5093e89586aSKieran Bingham afe->streaming = false; 5103e89586aSKieran Bingham afe->curr_norm = V4L2_STD_NTSC_M; 5113e89586aSKieran Bingham 5123e89586aSKieran Bingham adv748x_subdev_init(&afe->sd, state, &adv748x_afe_ops, 5133e89586aSKieran Bingham MEDIA_ENT_F_ATV_DECODER, "afe"); 5143e89586aSKieran Bingham 5153e89586aSKieran Bingham /* Identify the first connector found as a default input if set */ 5163e89586aSKieran Bingham for (i = ADV748X_PORT_AIN0; i <= ADV748X_PORT_AIN7; i++) { 5173e89586aSKieran Bingham /* Inputs and ports are 1-indexed to match the data sheet */ 5183e89586aSKieran Bingham if (state->endpoints[i]) { 5193e89586aSKieran Bingham afe->input = i; 5203e89586aSKieran Bingham break; 5213e89586aSKieran Bingham } 5223e89586aSKieran Bingham } 5233e89586aSKieran Bingham 5243e89586aSKieran Bingham /* Entity pads and sinks are 0-indexed to match the pads */ 5253e89586aSKieran Bingham for (i = ADV748X_AFE_SINK_AIN0; i <= ADV748X_AFE_SINK_AIN7; i++) 5263e89586aSKieran Bingham afe->pads[i].flags = MEDIA_PAD_FL_SINK; 5273e89586aSKieran Bingham 5283e89586aSKieran Bingham afe->pads[ADV748X_AFE_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 5293e89586aSKieran Bingham 5303e89586aSKieran Bingham ret = media_entity_pads_init(&afe->sd.entity, ADV748X_AFE_NR_PADS, 5313e89586aSKieran Bingham afe->pads); 5323e89586aSKieran Bingham if (ret) 5333e89586aSKieran Bingham return ret; 5343e89586aSKieran Bingham 5353e89586aSKieran Bingham ret = adv748x_afe_init_controls(afe); 5363e89586aSKieran Bingham if (ret) 5373e89586aSKieran Bingham goto error; 5383e89586aSKieran Bingham 5393e89586aSKieran Bingham return 0; 5403e89586aSKieran Bingham 5413e89586aSKieran Bingham error: 5423e89586aSKieran Bingham media_entity_cleanup(&afe->sd.entity); 5433e89586aSKieran Bingham 5443e89586aSKieran Bingham return ret; 5453e89586aSKieran Bingham } 5463e89586aSKieran Bingham 5473e89586aSKieran Bingham void adv748x_afe_cleanup(struct adv748x_afe *afe) 5483e89586aSKieran Bingham { 5493e89586aSKieran Bingham v4l2_device_unregister_subdev(&afe->sd); 5503e89586aSKieran Bingham media_entity_cleanup(&afe->sd.entity); 5513e89586aSKieran Bingham v4l2_ctrl_handler_free(&afe->ctrl_hdl); 5523e89586aSKieran Bingham } 553