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