1459ee17cSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0 2459ee17cSMauro Carvalho Chehab // 3459ee17cSMauro Carvalho Chehab // tvp5150 - Texas Instruments TVP5150A/AM1 and TVP5151 video decoder driver 4459ee17cSMauro Carvalho Chehab // 532590819SMauro Carvalho Chehab // Copyright (c) 2005,2006 Mauro Carvalho Chehab <mchehab@kernel.org> 6cb7a01acSMauro Carvalho Chehab 7b802fb99SJavier Martinez Canillas #include <dt-bindings/media/tvp5150.h> 8cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 9cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 10cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 11cb7a01acSMauro Carvalho Chehab #include <linux/delay.h> 1209aa2609SJavier Martinez Canillas #include <linux/gpio/consumer.h> 138e4c97e0SPhilipp Zabel #include <linux/interrupt.h> 14cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 15859969b3SSakari Ailus #include <linux/of_graph.h> 1673549a69SMarco Felsch #include <linux/pm_runtime.h> 1728b9e227SPhilipp Zabel #include <linux/regmap.h> 18c7d97499SJavier Martinez Canillas #include <media/v4l2-async.h> 19cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 20e953c103SMarco Felsch #include <media/v4l2-event.h> 21cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 22859969b3SSakari Ailus #include <media/v4l2-fwnode.h> 2355606310SMauro Carvalho Chehab #include <media/v4l2-mc.h> 2446fe6e7dSMarco Felsch #include <media/v4l2-rect.h> 25cb7a01acSMauro Carvalho Chehab 26cb7a01acSMauro Carvalho Chehab #include "tvp5150_reg.h" 27cb7a01acSMauro Carvalho Chehab 28785a3de1SPhilipp Zabel #define TVP5150_H_MAX 720U 29785a3de1SPhilipp Zabel #define TVP5150_V_MAX_525_60 480U 30785a3de1SPhilipp Zabel #define TVP5150_V_MAX_OTHERS 576U 31cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_LEFT 511 32cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_TOP 127 33cb7a01acSMauro Carvalho Chehab #define TVP5150_CROP_SHIFT 2 345cb82940SMarco Felsch #define TVP5150_MBUS_FMT MEDIA_BUS_FMT_UYVY8_2X8 355cb82940SMarco Felsch #define TVP5150_FIELD V4L2_FIELD_ALTERNATE 365cb82940SMarco Felsch #define TVP5150_COLORSPACE V4L2_COLORSPACE_SMPTE170M 37baf17821SMarco Felsch #define TVP5150_STD_MASK (V4L2_STD_NTSC | \ 38baf17821SMarco Felsch V4L2_STD_NTSC_443 | \ 39baf17821SMarco Felsch V4L2_STD_PAL | \ 40baf17821SMarco Felsch V4L2_STD_PAL_M | \ 41baf17821SMarco Felsch V4L2_STD_PAL_N | \ 42baf17821SMarco Felsch V4L2_STD_PAL_Nc | \ 43baf17821SMarco Felsch V4L2_STD_SECAM) 44cb7a01acSMauro Carvalho Chehab 450556f1d5SMarco Felsch #define TVP5150_MAX_CONNECTORS 3 /* Check dt-bindings for more information */ 460556f1d5SMarco Felsch 47c43875f6SMauro Carvalho Chehab MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver"); 48cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab"); 49459ee17cSMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 50cb7a01acSMauro Carvalho Chehab 51cb7a01acSMauro Carvalho Chehab 52cb7a01acSMauro Carvalho Chehab static int debug; 532a0489d3SPhilipp Zabel module_param(debug, int, 0644); 54cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-2)"); 55cb7a01acSMauro Carvalho Chehab 56ad0e3744SMauro Carvalho Chehab #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg) 57ad0e3744SMauro Carvalho Chehab 58bc322c0dSMauro Carvalho Chehab enum tvp5150_pads { 590556f1d5SMarco Felsch TVP5150_PAD_AIP1A, 600556f1d5SMarco Felsch TVP5150_PAD_AIP1B, 61bc322c0dSMauro Carvalho Chehab TVP5150_PAD_VID_OUT, 62bc322c0dSMauro Carvalho Chehab TVP5150_NUM_PADS 63bc322c0dSMauro Carvalho Chehab }; 64bc322c0dSMauro Carvalho Chehab 650556f1d5SMarco Felsch struct tvp5150_connector { 660556f1d5SMarco Felsch struct v4l2_fwnode_connector base; 670556f1d5SMarco Felsch struct media_entity ent; 680556f1d5SMarco Felsch struct media_pad pad; 690556f1d5SMarco Felsch }; 700556f1d5SMarco Felsch 71cb7a01acSMauro Carvalho Chehab struct tvp5150 { 72cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 730556f1d5SMarco Felsch 74bc322c0dSMauro Carvalho Chehab struct media_pad pads[TVP5150_NUM_PADS]; 750556f1d5SMarco Felsch struct tvp5150_connector connectors[TVP5150_MAX_CONNECTORS]; 76baf17821SMarco Felsch struct tvp5150_connector *cur_connector; 770556f1d5SMarco Felsch unsigned int connectors_num; 780556f1d5SMarco Felsch 79cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler hdl; 80cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect; 8128b9e227SPhilipp Zabel struct regmap *regmap; 828e4c97e0SPhilipp Zabel int irq; 83cb7a01acSMauro Carvalho Chehab 84cb7a01acSMauro Carvalho Chehab v4l2_std_id norm; /* Current set standard */ 85b440b733SPhilipp Zabel v4l2_std_id detected_norm; 86cb7a01acSMauro Carvalho Chehab u32 input; 87cb7a01acSMauro Carvalho Chehab u32 output; 8862a764e1SPhilipp Zabel u32 oe; 89cb7a01acSMauro Carvalho Chehab int enable; 908e4c97e0SPhilipp Zabel bool lock; 91a2e5f1b3SJavier Martinez Canillas 9282275133SJavier Martinez Canillas u16 dev_id; 9382275133SJavier Martinez Canillas u16 rom_ver; 9482275133SJavier Martinez Canillas 95a2e5f1b3SJavier Martinez Canillas enum v4l2_mbus_type mbus_type; 96cb7a01acSMauro Carvalho Chehab }; 97cb7a01acSMauro Carvalho Chehab 98cb7a01acSMauro Carvalho Chehab static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) 99cb7a01acSMauro Carvalho Chehab { 100cb7a01acSMauro Carvalho Chehab return container_of(sd, struct tvp5150, sd); 101cb7a01acSMauro Carvalho Chehab } 102cb7a01acSMauro Carvalho Chehab 103cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 104cb7a01acSMauro Carvalho Chehab { 105cb7a01acSMauro Carvalho Chehab return &container_of(ctrl->handler, struct tvp5150, hdl)->sd; 106cb7a01acSMauro Carvalho Chehab } 107cb7a01acSMauro Carvalho Chehab 108cb7a01acSMauro Carvalho Chehab static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) 109cb7a01acSMauro Carvalho Chehab { 11028b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 11128b9e227SPhilipp Zabel int ret, val; 112cb7a01acSMauro Carvalho Chehab 11328b9e227SPhilipp Zabel ret = regmap_read(decoder->regmap, addr, &val); 11428b9e227SPhilipp Zabel if (ret < 0) 11528b9e227SPhilipp Zabel return ret; 116cb7a01acSMauro Carvalho Chehab 11728b9e227SPhilipp Zabel return val; 118cb7a01acSMauro Carvalho Chehab } 119cb7a01acSMauro Carvalho Chehab 120cb7a01acSMauro Carvalho Chehab static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, 121cb7a01acSMauro Carvalho Chehab const u8 end, int max_line) 122cb7a01acSMauro Carvalho Chehab { 123e5134114SMauro Carvalho Chehab u8 buf[16]; 124e5134114SMauro Carvalho Chehab int i = 0, j, len; 125cb7a01acSMauro Carvalho Chehab 126e5134114SMauro Carvalho Chehab if (max_line > 16) { 127e5134114SMauro Carvalho Chehab dprintk0(sd->dev, "too much data to dump\n"); 128e5134114SMauro Carvalho Chehab return; 129cb7a01acSMauro Carvalho Chehab } 130cb7a01acSMauro Carvalho Chehab 131e5134114SMauro Carvalho Chehab for (i = init; i < end; i += max_line) { 132e5134114SMauro Carvalho Chehab len = (end - i > max_line) ? max_line : end - i; 133e5134114SMauro Carvalho Chehab 134e5134114SMauro Carvalho Chehab for (j = 0; j < len; j++) 135e5134114SMauro Carvalho Chehab buf[j] = tvp5150_read(sd, i + j); 136e5134114SMauro Carvalho Chehab 137e5134114SMauro Carvalho Chehab dprintk0(sd->dev, "%s reg %02x = %*ph\n", s, i, len, buf); 138cb7a01acSMauro Carvalho Chehab } 139cb7a01acSMauro Carvalho Chehab } 140cb7a01acSMauro Carvalho Chehab 141cb7a01acSMauro Carvalho Chehab static int tvp5150_log_status(struct v4l2_subdev *sd) 142cb7a01acSMauro Carvalho Chehab { 143ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Video input source selection #1 = 0x%02x\n", 144cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); 145ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Analog channel controls = 0x%02x\n", 146cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); 147ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Operation mode controls = 0x%02x\n", 148cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_OP_MODE_CTL)); 149ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Miscellaneous controls = 0x%02x\n", 150cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MISC_CTL)); 151ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Autoswitch mask= 0x%02x\n", 152cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_AUTOSW_MSK)); 153ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Color killer threshold control = 0x%02x\n", 154cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); 155ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", 156cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), 157cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), 158cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); 159ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Brightness control = 0x%02x\n", 160cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_BRIGHT_CTL)); 161ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Color saturation control = 0x%02x\n", 162cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_SATURATION_CTL)); 163ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Hue control = 0x%02x\n", 164cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HUE_CTL)); 165ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Contrast control = 0x%02x\n", 166cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONTRAST_CTL)); 167ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Outputs and data rates select = 0x%02x\n", 168cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); 169ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Configuration shared pins = 0x%02x\n", 170cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); 171ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Active video cropping start = 0x%02x%02x\n", 172cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), 173cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); 174ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Active video cropping stop = 0x%02x%02x\n", 175cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), 176cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); 177ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Genlock/RTC = 0x%02x\n", 178cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_GENLOCK)); 179ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Horizontal sync start = 0x%02x\n", 180cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); 181ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical blanking start = 0x%02x\n", 182cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); 183ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical blanking stop = 0x%02x\n", 184cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); 185ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", 186cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), 187cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); 188ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt reset register B = 0x%02x\n", 189cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); 190ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt enable register B = 0x%02x\n", 191cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); 192ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt configuration register B = 0x%02x\n", 193cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); 194ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Video standard = 0x%02x\n", 195cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VIDEO_STD)); 196ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", 197cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CB_GAIN_FACT), 198cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); 199ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Macrovision on counter = 0x%02x\n", 200cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); 201ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Macrovision off counter = 0x%02x\n", 202cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); 203ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", 204cb7a01acSMauro Carvalho Chehab (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); 205ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Device ID = %02x%02x\n", 206cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MSB_DEV_ID), 207cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LSB_DEV_ID)); 208ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: ROM version = (hex) %02x.%02x\n", 209cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), 210cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); 211ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical line count = 0x%02x%02x\n", 212cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), 213cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); 214ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt status register B = 0x%02x\n", 215cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); 216ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt active register B = 0x%02x\n", 217cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); 218ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", 219cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_1), 220cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_2), 221cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_3), 222cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_4), 223cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_5)); 224cb7a01acSMauro Carvalho Chehab 225cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, 226cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL1_END, 8); 227cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, 228cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL2_END, 8); 229cb7a01acSMauro Carvalho Chehab 230ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Teletext filter enable = 0x%02x\n", 231cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); 232ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt status register A = 0x%02x\n", 233cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); 234ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt enable register A = 0x%02x\n", 235cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); 236ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt configuration = 0x%02x\n", 237cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_CONF)); 238ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: VDP status register = 0x%02x\n", 239cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); 240ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO word count = 0x%02x\n", 241cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); 242ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO interrupt threshold = 0x%02x\n", 243cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); 244ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO reset = 0x%02x\n", 245cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_RESET)); 246ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Line number interrupt = 0x%02x\n", 247cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); 248ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Pixel alignment register = 0x%02x%02x\n", 249cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), 250cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); 251ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO output control = 0x%02x\n", 252cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); 253ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Full field enable = 0x%02x\n", 254cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); 255ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Full field mode register = 0x%02x\n", 256cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); 257cb7a01acSMauro Carvalho Chehab 258cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI, 259cb7a01acSMauro Carvalho Chehab TVP5150_CC_DATA_END, 8); 260cb7a01acSMauro Carvalho Chehab 261cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "WSS data", TVP5150_WSS_DATA_INI, 262cb7a01acSMauro Carvalho Chehab TVP5150_WSS_DATA_END, 8); 263cb7a01acSMauro Carvalho Chehab 264cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VPS data", TVP5150_VPS_DATA_INI, 265cb7a01acSMauro Carvalho Chehab TVP5150_VPS_DATA_END, 8); 266cb7a01acSMauro Carvalho Chehab 267cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VITC data", TVP5150_VITC_DATA_INI, 268cb7a01acSMauro Carvalho Chehab TVP5150_VITC_DATA_END, 10); 269cb7a01acSMauro Carvalho Chehab 270cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Line mode", TVP5150_LINE_MODE_INI, 271cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_END, 8); 272cb7a01acSMauro Carvalho Chehab return 0; 273cb7a01acSMauro Carvalho Chehab } 274cb7a01acSMauro Carvalho Chehab 275cb7a01acSMauro Carvalho Chehab /**************************************************************************** 276cb7a01acSMauro Carvalho Chehab Basic functions 277cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 278cb7a01acSMauro Carvalho Chehab 2796e98bee2SLaurent Pinchart static void tvp5150_selmux(struct v4l2_subdev *sd) 280cb7a01acSMauro Carvalho Chehab { 281cb7a01acSMauro Carvalho Chehab int opmode = 0; 282cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 2838a7441baSMarco Felsch unsigned int mask, val; 284cb7a01acSMauro Carvalho Chehab int input = 0; 285cb7a01acSMauro Carvalho Chehab 286c43875f6SMauro Carvalho Chehab /* Only tvp5150am1 and tvp5151 have signal generator support */ 287c43875f6SMauro Carvalho Chehab if ((decoder->dev_id == 0x5150 && decoder->rom_ver == 0x0400) || 288c43875f6SMauro Carvalho Chehab (decoder->dev_id == 0x5151 && decoder->rom_ver == 0x0100)) { 289c43875f6SMauro Carvalho Chehab if (!decoder->enable) 290cb7a01acSMauro Carvalho Chehab input = 8; 291c43875f6SMauro Carvalho Chehab } 292cb7a01acSMauro Carvalho Chehab 293cb7a01acSMauro Carvalho Chehab switch (decoder->input) { 294cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE1: 295cb7a01acSMauro Carvalho Chehab input |= 2; 296cb7a01acSMauro Carvalho Chehab /* fall through */ 297cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE0: 298cb7a01acSMauro Carvalho Chehab break; 299cb7a01acSMauro Carvalho Chehab case TVP5150_SVIDEO: 300cb7a01acSMauro Carvalho Chehab default: 301cb7a01acSMauro Carvalho Chehab input |= 1; 302cb7a01acSMauro Carvalho Chehab break; 303cb7a01acSMauro Carvalho Chehab } 304cb7a01acSMauro Carvalho Chehab 305430f35b7SMarco Felsch dev_dbg_lvl(sd->dev, 1, debug, 306430f35b7SMarco Felsch "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n", 307430f35b7SMarco Felsch decoder->input == 0 ? "aip1a" : 308430f35b7SMarco Felsch decoder->input == 2 ? "aip1b" : "svideo", 309430f35b7SMarco Felsch decoder->output == 0 ? "normal" : "black-frame-gen", 310cb7a01acSMauro Carvalho Chehab input, opmode); 311cb7a01acSMauro Carvalho Chehab 31228b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode); 31328b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input); 314cb7a01acSMauro Carvalho Chehab 315b4b2de38SLaurent Pinchart /* 316b4b2de38SLaurent Pinchart * Setup the FID/GLCO/VLK/HVLK and INTREQ/GPCL/VBLK output signals. For 317b4b2de38SLaurent Pinchart * S-Video we output the vertical lock (VLK) signal on FID/GLCO/VLK/HVLK 318b4b2de38SLaurent Pinchart * and set INTREQ/GPCL/VBLK to logic 0. For composite we output the 319b4b2de38SLaurent Pinchart * field indicator (FID) signal on FID/GLCO/VLK/HVLK and set 320b4b2de38SLaurent Pinchart * INTREQ/GPCL/VBLK to logic 1. 321cb7a01acSMauro Carvalho Chehab */ 3228a7441baSMarco Felsch mask = TVP5150_MISC_CTL_GPCL | TVP5150_MISC_CTL_HVLK; 323cb7a01acSMauro Carvalho Chehab if (decoder->input == TVP5150_SVIDEO) 3248a7441baSMarco Felsch val = TVP5150_MISC_CTL_HVLK; 325cb7a01acSMauro Carvalho Chehab else 3268a7441baSMarco Felsch val = TVP5150_MISC_CTL_GPCL; 3278a7441baSMarco Felsch regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val); 328cb7a01acSMauro Carvalho Chehab }; 329cb7a01acSMauro Carvalho Chehab 330cb7a01acSMauro Carvalho Chehab struct i2c_reg_value { 331cb7a01acSMauro Carvalho Chehab unsigned char reg; 332cb7a01acSMauro Carvalho Chehab unsigned char value; 333cb7a01acSMauro Carvalho Chehab }; 334cb7a01acSMauro Carvalho Chehab 335cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 336cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_default[] = { 337cb7a01acSMauro Carvalho Chehab { /* 0x00 */ 338cb7a01acSMauro Carvalho Chehab TVP5150_VD_IN_SRC_SEL_1, 0x00 339cb7a01acSMauro Carvalho Chehab }, 340cb7a01acSMauro Carvalho Chehab { /* 0x01 */ 341cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 342cb7a01acSMauro Carvalho Chehab }, 343cb7a01acSMauro Carvalho Chehab { /* 0x02 */ 344cb7a01acSMauro Carvalho Chehab TVP5150_OP_MODE_CTL, 0x00 345cb7a01acSMauro Carvalho Chehab }, 346cb7a01acSMauro Carvalho Chehab { /* 0x03 */ 347cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL, 0x01 348cb7a01acSMauro Carvalho Chehab }, 349cb7a01acSMauro Carvalho Chehab { /* 0x06 */ 350cb7a01acSMauro Carvalho Chehab TVP5150_COLOR_KIL_THSH_CTL, 0x10 351cb7a01acSMauro Carvalho Chehab }, 352cb7a01acSMauro Carvalho Chehab { /* 0x07 */ 353cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_1, 0x60 354cb7a01acSMauro Carvalho Chehab }, 355cb7a01acSMauro Carvalho Chehab { /* 0x08 */ 356cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_2, 0x00 357cb7a01acSMauro Carvalho Chehab }, 358cb7a01acSMauro Carvalho Chehab { /* 0x09 */ 359cb7a01acSMauro Carvalho Chehab TVP5150_BRIGHT_CTL, 0x80 360cb7a01acSMauro Carvalho Chehab }, 361cb7a01acSMauro Carvalho Chehab { /* 0x0a */ 362cb7a01acSMauro Carvalho Chehab TVP5150_SATURATION_CTL, 0x80 363cb7a01acSMauro Carvalho Chehab }, 364cb7a01acSMauro Carvalho Chehab { /* 0x0b */ 365cb7a01acSMauro Carvalho Chehab TVP5150_HUE_CTL, 0x00 366cb7a01acSMauro Carvalho Chehab }, 367cb7a01acSMauro Carvalho Chehab { /* 0x0c */ 368cb7a01acSMauro Carvalho Chehab TVP5150_CONTRAST_CTL, 0x80 369cb7a01acSMauro Carvalho Chehab }, 370cb7a01acSMauro Carvalho Chehab { /* 0x0d */ 371cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 372cb7a01acSMauro Carvalho Chehab }, 373cb7a01acSMauro Carvalho Chehab { /* 0x0e */ 374cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_3, 0x00 375cb7a01acSMauro Carvalho Chehab }, 376cb7a01acSMauro Carvalho Chehab { /* 0x0f */ 377cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN, 0x08 378cb7a01acSMauro Carvalho Chehab }, 379cb7a01acSMauro Carvalho Chehab { /* 0x11 */ 380cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_MSB, 0x00 381cb7a01acSMauro Carvalho Chehab }, 382cb7a01acSMauro Carvalho Chehab { /* 0x12 */ 383cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_LSB, 0x00 384cb7a01acSMauro Carvalho Chehab }, 385cb7a01acSMauro Carvalho Chehab { /* 0x13 */ 386cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_MSB, 0x00 387cb7a01acSMauro Carvalho Chehab }, 388cb7a01acSMauro Carvalho Chehab { /* 0x14 */ 389cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_LSB, 0x00 390cb7a01acSMauro Carvalho Chehab }, 391cb7a01acSMauro Carvalho Chehab { /* 0x15 */ 392cb7a01acSMauro Carvalho Chehab TVP5150_GENLOCK, 0x01 393cb7a01acSMauro Carvalho Chehab }, 394cb7a01acSMauro Carvalho Chehab { /* 0x16 */ 395cb7a01acSMauro Carvalho Chehab TVP5150_HORIZ_SYNC_START, 0x80 396cb7a01acSMauro Carvalho Chehab }, 397cb7a01acSMauro Carvalho Chehab { /* 0x18 */ 398cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_START, 0x00 399cb7a01acSMauro Carvalho Chehab }, 400cb7a01acSMauro Carvalho Chehab { /* 0x19 */ 401cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_STOP, 0x00 402cb7a01acSMauro Carvalho Chehab }, 403cb7a01acSMauro Carvalho Chehab { /* 0x1a */ 404cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 405cb7a01acSMauro Carvalho Chehab }, 406cb7a01acSMauro Carvalho Chehab { /* 0x1b */ 407cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x14 408cb7a01acSMauro Carvalho Chehab }, 409cb7a01acSMauro Carvalho Chehab { /* 0x1c */ 410cb7a01acSMauro Carvalho Chehab TVP5150_INT_RESET_REG_B, 0x00 411cb7a01acSMauro Carvalho Chehab }, 412cb7a01acSMauro Carvalho Chehab { /* 0x1d */ 413cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_B, 0x00 414cb7a01acSMauro Carvalho Chehab }, 415cb7a01acSMauro Carvalho Chehab { /* 0x1e */ 416cb7a01acSMauro Carvalho Chehab TVP5150_INTT_CONFIG_REG_B, 0x00 417cb7a01acSMauro Carvalho Chehab }, 418cb7a01acSMauro Carvalho Chehab { /* 0x28 */ 419cb7a01acSMauro Carvalho Chehab TVP5150_VIDEO_STD, 0x00 420cb7a01acSMauro Carvalho Chehab }, 421cb7a01acSMauro Carvalho Chehab { /* 0x2e */ 422cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_ON_CTR, 0x0f 423cb7a01acSMauro Carvalho Chehab }, 424cb7a01acSMauro Carvalho Chehab { /* 0x2f */ 425cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_OFF_CTR, 0x01 426cb7a01acSMauro Carvalho Chehab }, 427cb7a01acSMauro Carvalho Chehab { /* 0xbb */ 428cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL_ENA, 0x00 429cb7a01acSMauro Carvalho Chehab }, 430cb7a01acSMauro Carvalho Chehab { /* 0xc0 */ 431cb7a01acSMauro Carvalho Chehab TVP5150_INT_STATUS_REG_A, 0x00 432cb7a01acSMauro Carvalho Chehab }, 433cb7a01acSMauro Carvalho Chehab { /* 0xc1 */ 434cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_A, 0x00 435cb7a01acSMauro Carvalho Chehab }, 436cb7a01acSMauro Carvalho Chehab { /* 0xc2 */ 437cb7a01acSMauro Carvalho Chehab TVP5150_INT_CONF, 0x04 438cb7a01acSMauro Carvalho Chehab }, 439cb7a01acSMauro Carvalho Chehab { /* 0xc8 */ 440cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_INT_THRESHOLD, 0x80 441cb7a01acSMauro Carvalho Chehab }, 442cb7a01acSMauro Carvalho Chehab { /* 0xc9 */ 443cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_RESET, 0x00 444cb7a01acSMauro Carvalho Chehab }, 445cb7a01acSMauro Carvalho Chehab { /* 0xca */ 446cb7a01acSMauro Carvalho Chehab TVP5150_LINE_NUMBER_INT, 0x00 447cb7a01acSMauro Carvalho Chehab }, 448cb7a01acSMauro Carvalho Chehab { /* 0xcb */ 449cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_LOW, 0x4e 450cb7a01acSMauro Carvalho Chehab }, 451cb7a01acSMauro Carvalho Chehab { /* 0xcc */ 452cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_HIGH, 0x00 453cb7a01acSMauro Carvalho Chehab }, 454cb7a01acSMauro Carvalho Chehab { /* 0xcd */ 455cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_OUT_CTRL, 0x01 456cb7a01acSMauro Carvalho Chehab }, 457cb7a01acSMauro Carvalho Chehab { /* 0xcf */ 458cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_ENA, 0x00 459cb7a01acSMauro Carvalho Chehab }, 460cb7a01acSMauro Carvalho Chehab { /* 0xd0 */ 461cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_INI, 0x00 462cb7a01acSMauro Carvalho Chehab }, 463cb7a01acSMauro Carvalho Chehab { /* 0xfc */ 464cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_MODE_REG, 0x7f 465cb7a01acSMauro Carvalho Chehab }, 466cb7a01acSMauro Carvalho Chehab { /* end of data */ 467cb7a01acSMauro Carvalho Chehab 0xff, 0xff 468cb7a01acSMauro Carvalho Chehab } 469cb7a01acSMauro Carvalho Chehab }; 470cb7a01acSMauro Carvalho Chehab 471cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 472cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_enable[] = { 4738105e1bcSPhilipp Zabel { /* Automatic offset and AGC enabled */ 474cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 475cb7a01acSMauro Carvalho Chehab }, { /* Activate YCrCb output 0x9 or 0xd ? */ 476b4b2de38SLaurent Pinchart TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL | 477b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_INTREQ_OE | 478b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_YCBCR_OE | 479b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_SYNC_OE | 480b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_VBLANK | 481b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_CLOCK_OE, 482cb7a01acSMauro Carvalho Chehab }, { /* Activates video std autodetection for all standards */ 483cb7a01acSMauro Carvalho Chehab TVP5150_AUTOSW_MSK, 0x0 484cb7a01acSMauro Carvalho Chehab }, { /* Default format: 0x47. For 4:2:2: 0x40 */ 485cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 486cb7a01acSMauro Carvalho Chehab }, { 487cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 488cb7a01acSMauro Carvalho Chehab }, { 489cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x54 490cb7a01acSMauro Carvalho Chehab }, { /* Non documented, but initialized on WinTV USB2 */ 491cb7a01acSMauro Carvalho Chehab 0x27, 0x20 492cb7a01acSMauro Carvalho Chehab }, { 493cb7a01acSMauro Carvalho Chehab 0xff, 0xff 494cb7a01acSMauro Carvalho Chehab } 495cb7a01acSMauro Carvalho Chehab }; 496cb7a01acSMauro Carvalho Chehab 497cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type { 498cb7a01acSMauro Carvalho Chehab unsigned int vbi_type; 499cb7a01acSMauro Carvalho Chehab unsigned int ini_line; 500cb7a01acSMauro Carvalho Chehab unsigned int end_line; 501cb7a01acSMauro Carvalho Chehab unsigned int by_field :1; 502cb7a01acSMauro Carvalho Chehab }; 503cb7a01acSMauro Carvalho Chehab 504cb7a01acSMauro Carvalho Chehab struct i2c_vbi_ram_value { 505cb7a01acSMauro Carvalho Chehab u16 reg; 506cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type type; 507cb7a01acSMauro Carvalho Chehab unsigned char values[16]; 508cb7a01acSMauro Carvalho Chehab }; 509cb7a01acSMauro Carvalho Chehab 510cb7a01acSMauro Carvalho Chehab /* This struct have the values for each supported VBI Standard 511cb7a01acSMauro Carvalho Chehab * by 512cb7a01acSMauro Carvalho Chehab tvp5150_vbi_types should follow the same order as vbi_ram_default 513cb7a01acSMauro Carvalho Chehab * value 0 means rom position 0x10, value 1 means rom position 0x30 514cb7a01acSMauro Carvalho Chehab * and so on. There are 16 possible locations from 0 to 15. 515cb7a01acSMauro Carvalho Chehab */ 516cb7a01acSMauro Carvalho Chehab 51765dc760bSNasser Afshin static struct i2c_vbi_ram_value vbi_ram_default[] = { 51865dc760bSNasser Afshin 5199bfd8f88SNasser Afshin /* 5209bfd8f88SNasser Afshin * FIXME: Current api doesn't handle all VBI types, those not 5219bfd8f88SNasser Afshin * yet supported are placed under #if 0 5229bfd8f88SNasser Afshin */ 523cb7a01acSMauro Carvalho Chehab #if 0 5243dd6b560SMauro Carvalho Chehab [0] = {0x010, /* Teletext, SECAM, WST System A */ 525cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_SECAM, 6, 23, 1}, 526cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 527cb7a01acSMauro Carvalho Chehab 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } 528cb7a01acSMauro Carvalho Chehab }, 529cb7a01acSMauro Carvalho Chehab #endif 5303dd6b560SMauro Carvalho Chehab [1] = {0x030, /* Teletext, PAL, WST System B */ 531cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_B, 6, 22, 1}, 532cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 533cb7a01acSMauro Carvalho Chehab 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } 534cb7a01acSMauro Carvalho Chehab }, 535cb7a01acSMauro Carvalho Chehab #if 0 5363dd6b560SMauro Carvalho Chehab [2] = {0x050, /* Teletext, PAL, WST System C */ 537cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_PAL_C, 6, 22, 1}, 538cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 539cb7a01acSMauro Carvalho Chehab 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 540cb7a01acSMauro Carvalho Chehab }, 5413dd6b560SMauro Carvalho Chehab [3] = {0x070, /* Teletext, NTSC, WST System B */ 542cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_B, 10, 21, 1}, 543cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, 544cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 545cb7a01acSMauro Carvalho Chehab }, 5463dd6b560SMauro Carvalho Chehab [4] = {0x090, /* Tetetext, NTSC NABTS System C */ 547cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_C, 10, 21, 1}, 548cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 549cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } 550cb7a01acSMauro Carvalho Chehab }, 5513dd6b560SMauro Carvalho Chehab [5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */ 552cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_D, 10, 21, 1}, 553cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, 554cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 555cb7a01acSMauro Carvalho Chehab }, 5563dd6b560SMauro Carvalho Chehab [6] = {0x0d0, /* Closed Caption, PAL/SECAM */ 557cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_625, 22, 22, 1}, 558cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 559cb7a01acSMauro Carvalho Chehab 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 560cb7a01acSMauro Carvalho Chehab }, 561cb7a01acSMauro Carvalho Chehab #endif 5623dd6b560SMauro Carvalho Chehab [7] = {0x0f0, /* Closed Caption, NTSC */ 563cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_525, 21, 21, 1}, 564cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 565cb7a01acSMauro Carvalho Chehab 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 566cb7a01acSMauro Carvalho Chehab }, 5673dd6b560SMauro Carvalho Chehab [8] = {0x110, /* Wide Screen Signal, PAL/SECAM */ 568cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_625, 23, 23, 1}, 569cb7a01acSMauro Carvalho Chehab { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 570cb7a01acSMauro Carvalho Chehab 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } 571cb7a01acSMauro Carvalho Chehab }, 572cb7a01acSMauro Carvalho Chehab #if 0 5733dd6b560SMauro Carvalho Chehab [9] = {0x130, /* Wide Screen Signal, NTSC C */ 574cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_525, 20, 20, 1}, 575cb7a01acSMauro Carvalho Chehab { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, 576cb7a01acSMauro Carvalho Chehab 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } 577cb7a01acSMauro Carvalho Chehab }, 5783dd6b560SMauro Carvalho Chehab [10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ 579cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_625, 6, 22, 0}, 580cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 581cb7a01acSMauro Carvalho Chehab 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 582cb7a01acSMauro Carvalho Chehab }, 5833dd6b560SMauro Carvalho Chehab [11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */ 584cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_525, 10, 20, 0}, 585cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 586cb7a01acSMauro Carvalho Chehab 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 587cb7a01acSMauro Carvalho Chehab }, 588cb7a01acSMauro Carvalho Chehab #endif 5893dd6b560SMauro Carvalho Chehab [12] = {0x190, /* Video Program System (VPS), PAL */ 590cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_VPS, 16, 16, 0}, 591cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, 592cb7a01acSMauro Carvalho Chehab 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } 593cb7a01acSMauro Carvalho Chehab }, 594cb7a01acSMauro Carvalho Chehab /* 0x1d0 User programmable */ 595cb7a01acSMauro Carvalho Chehab }; 596cb7a01acSMauro Carvalho Chehab 597cb7a01acSMauro Carvalho Chehab static int tvp5150_write_inittab(struct v4l2_subdev *sd, 598cb7a01acSMauro Carvalho Chehab const struct i2c_reg_value *regs) 599cb7a01acSMauro Carvalho Chehab { 60028b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 60128b9e227SPhilipp Zabel 602cb7a01acSMauro Carvalho Chehab while (regs->reg != 0xff) { 60328b9e227SPhilipp Zabel regmap_write(decoder->regmap, regs->reg, regs->value); 604cb7a01acSMauro Carvalho Chehab regs++; 605cb7a01acSMauro Carvalho Chehab } 606cb7a01acSMauro Carvalho Chehab return 0; 607cb7a01acSMauro Carvalho Chehab } 608cb7a01acSMauro Carvalho Chehab 6093dd6b560SMauro Carvalho Chehab static int tvp5150_vdp_init(struct v4l2_subdev *sd) 610cb7a01acSMauro Carvalho Chehab { 61128b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 61228b9e227SPhilipp Zabel struct regmap *map = decoder->regmap; 613cb7a01acSMauro Carvalho Chehab unsigned int i; 6143dd6b560SMauro Carvalho Chehab int j; 615cb7a01acSMauro Carvalho Chehab 616cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 61728b9e227SPhilipp Zabel regmap_write(map, TVP5150_FULL_FIELD_ENA, 0); 618cb7a01acSMauro Carvalho Chehab 619cb7a01acSMauro Carvalho Chehab /* Before programming, Line mode should be at 0xff */ 620cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 62128b9e227SPhilipp Zabel regmap_write(map, i, 0xff); 622cb7a01acSMauro Carvalho Chehab 623cb7a01acSMauro Carvalho Chehab /* Load Ram Table */ 6243dd6b560SMauro Carvalho Chehab for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) { 6253dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j]; 6263dd6b560SMauro Carvalho Chehab 6273dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 6283dd6b560SMauro Carvalho Chehab continue; 6293dd6b560SMauro Carvalho Chehab 63028b9e227SPhilipp Zabel regmap_write(map, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); 63128b9e227SPhilipp Zabel regmap_write(map, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); 632cb7a01acSMauro Carvalho Chehab 633cb7a01acSMauro Carvalho Chehab for (i = 0; i < 16; i++) 63428b9e227SPhilipp Zabel regmap_write(map, TVP5150_VDP_CONF_RAM_DATA, 63528b9e227SPhilipp Zabel regs->values[i]); 636cb7a01acSMauro Carvalho Chehab } 637cb7a01acSMauro Carvalho Chehab return 0; 638cb7a01acSMauro Carvalho Chehab } 639cb7a01acSMauro Carvalho Chehab 640cb7a01acSMauro Carvalho Chehab /* Fills VBI capabilities based on i2c_vbi_ram_value struct */ 641cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, 642cb7a01acSMauro Carvalho Chehab struct v4l2_sliced_vbi_cap *cap) 643cb7a01acSMauro Carvalho Chehab { 6443dd6b560SMauro Carvalho Chehab int line, i; 645cb7a01acSMauro Carvalho Chehab 646257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n"); 647bb7a3681SNasser Afshin memset(cap, 0, sizeof(*cap)); 648cb7a01acSMauro Carvalho Chehab 6493dd6b560SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { 6503dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; 6513dd6b560SMauro Carvalho Chehab 6523dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 6533dd6b560SMauro Carvalho Chehab continue; 6543dd6b560SMauro Carvalho Chehab 6553dd6b560SMauro Carvalho Chehab for (line = regs->type.ini_line; 6563dd6b560SMauro Carvalho Chehab line <= regs->type.end_line; 6573dd6b560SMauro Carvalho Chehab line++) { 658cb7a01acSMauro Carvalho Chehab cap->service_lines[0][line] |= regs->type.vbi_type; 659cb7a01acSMauro Carvalho Chehab } 660cb7a01acSMauro Carvalho Chehab cap->service_set |= regs->type.vbi_type; 661cb7a01acSMauro Carvalho Chehab } 662cb7a01acSMauro Carvalho Chehab return 0; 663cb7a01acSMauro Carvalho Chehab } 664cb7a01acSMauro Carvalho Chehab 665cb7a01acSMauro Carvalho Chehab /* Set vbi processing 666cb7a01acSMauro Carvalho Chehab * type - one of tvp5150_vbi_types 667cb7a01acSMauro Carvalho Chehab * line - line to gather data 668cb7a01acSMauro Carvalho Chehab * fields: bit 0 field1, bit 1, field2 669cb7a01acSMauro Carvalho Chehab * flags (default=0xf0) is a bitmask, were set means: 670cb7a01acSMauro Carvalho Chehab * bit 7: enable filtering null bytes on CC 671cb7a01acSMauro Carvalho Chehab * bit 6: send data also to FIFO 672cb7a01acSMauro Carvalho Chehab * bit 5: don't allow data with errors on FIFO 673cb7a01acSMauro Carvalho Chehab * bit 4: enable ECC when possible 674cb7a01acSMauro Carvalho Chehab * pix_align = pix alignment: 675cb7a01acSMauro Carvalho Chehab * LSB = field1 676cb7a01acSMauro Carvalho Chehab * MSB = field2 677cb7a01acSMauro Carvalho Chehab */ 678cb7a01acSMauro Carvalho Chehab static int tvp5150_set_vbi(struct v4l2_subdev *sd, 679cb7a01acSMauro Carvalho Chehab unsigned int type, u8 flags, int line, 680cb7a01acSMauro Carvalho Chehab const int fields) 681cb7a01acSMauro Carvalho Chehab { 682cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 683cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 684cb7a01acSMauro Carvalho Chehab u8 reg; 6853dd6b560SMauro Carvalho Chehab int i, pos = 0; 686cb7a01acSMauro Carvalho Chehab 687cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 688257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); 689cb7a01acSMauro Carvalho Chehab return 0; 690cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 691cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 692cb7a01acSMauro Carvalho Chehab line += 3; 693cb7a01acSMauro Carvalho Chehab } 694cb7a01acSMauro Carvalho Chehab 695cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 696cb7a01acSMauro Carvalho Chehab return 0; 697cb7a01acSMauro Carvalho Chehab 6983dd6b560SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { 6993dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; 7003dd6b560SMauro Carvalho Chehab 7013dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 7023dd6b560SMauro Carvalho Chehab continue; 7033dd6b560SMauro Carvalho Chehab 704cb7a01acSMauro Carvalho Chehab if ((type & regs->type.vbi_type) && 705cb7a01acSMauro Carvalho Chehab (line >= regs->type.ini_line) && 706b3d930aaSGustavo A. R. Silva (line <= regs->type.end_line)) 707cb7a01acSMauro Carvalho Chehab break; 708cb7a01acSMauro Carvalho Chehab pos++; 709cb7a01acSMauro Carvalho Chehab } 710b3d930aaSGustavo A. R. Silva 711cb7a01acSMauro Carvalho Chehab type = pos | (flags & 0xf0); 712cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 713cb7a01acSMauro Carvalho Chehab 714b3d930aaSGustavo A. R. Silva if (fields & 1) 71528b9e227SPhilipp Zabel regmap_write(decoder->regmap, reg, type); 716cb7a01acSMauro Carvalho Chehab 717b3d930aaSGustavo A. R. Silva if (fields & 2) 71828b9e227SPhilipp Zabel regmap_write(decoder->regmap, reg + 1, type); 719cb7a01acSMauro Carvalho Chehab 720cb7a01acSMauro Carvalho Chehab return type; 721cb7a01acSMauro Carvalho Chehab } 722cb7a01acSMauro Carvalho Chehab 7233dd6b560SMauro Carvalho Chehab static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line) 724cb7a01acSMauro Carvalho Chehab { 725cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 726cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 727cb7a01acSMauro Carvalho Chehab u8 reg; 728cb7a01acSMauro Carvalho Chehab int pos, type = 0; 729cb7a01acSMauro Carvalho Chehab int i, ret = 0; 730cb7a01acSMauro Carvalho Chehab 731cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 732257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); 733cb7a01acSMauro Carvalho Chehab return 0; 734cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 735cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 736cb7a01acSMauro Carvalho Chehab line += 3; 737cb7a01acSMauro Carvalho Chehab } 738cb7a01acSMauro Carvalho Chehab 739cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 740cb7a01acSMauro Carvalho Chehab return 0; 741cb7a01acSMauro Carvalho Chehab 742cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 743cb7a01acSMauro Carvalho Chehab 744cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 1; i++) { 745cb7a01acSMauro Carvalho Chehab ret = tvp5150_read(sd, reg + i); 746cb7a01acSMauro Carvalho Chehab if (ret < 0) { 747257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "%s: failed with error = %d\n", 748cb7a01acSMauro Carvalho Chehab __func__, ret); 749cb7a01acSMauro Carvalho Chehab return 0; 750cb7a01acSMauro Carvalho Chehab } 751cb7a01acSMauro Carvalho Chehab pos = ret & 0x0f; 7523dd6b560SMauro Carvalho Chehab if (pos < ARRAY_SIZE(vbi_ram_default)) 7533dd6b560SMauro Carvalho Chehab type |= vbi_ram_default[pos].type.vbi_type; 754cb7a01acSMauro Carvalho Chehab } 755cb7a01acSMauro Carvalho Chehab 756cb7a01acSMauro Carvalho Chehab return type; 757cb7a01acSMauro Carvalho Chehab } 758cb7a01acSMauro Carvalho Chehab 759cb7a01acSMauro Carvalho Chehab static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) 760cb7a01acSMauro Carvalho Chehab { 761cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 762cb7a01acSMauro Carvalho Chehab int fmt = 0; 763cb7a01acSMauro Carvalho Chehab 764cb7a01acSMauro Carvalho Chehab /* First tests should be against specific std */ 765cb7a01acSMauro Carvalho Chehab 76626811ae0SHans Verkuil if (std == V4L2_STD_NTSC_443) { 767cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_4_43_BIT; 76826811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_M) { 769cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_M_BIT; 77026811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) { 771cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_COMBINATION_N_BIT; 772cb7a01acSMauro Carvalho Chehab } else { 773cb7a01acSMauro Carvalho Chehab /* Then, test against generic ones */ 774cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 775cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_MJ_BIT; 776cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_PAL) 777cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_BDGHIN_BIT; 778cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_SECAM) 779cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_SECAM_BIT; 780cb7a01acSMauro Carvalho Chehab } 781cb7a01acSMauro Carvalho Chehab 782257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "Set video std register to %d.\n", fmt); 78328b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VIDEO_STD, fmt); 784cb7a01acSMauro Carvalho Chehab return 0; 785cb7a01acSMauro Carvalho Chehab } 786cb7a01acSMauro Carvalho Chehab 7870db87cc7SMarco Felsch static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) 7880db87cc7SMarco Felsch { 7890db87cc7SMarco Felsch struct tvp5150 *decoder = to_tvp5150(sd); 7900db87cc7SMarco Felsch 7910db87cc7SMarco Felsch *std = decoder->norm; 7920db87cc7SMarco Felsch 7930db87cc7SMarco Felsch return 0; 7940db87cc7SMarco Felsch } 7950db87cc7SMarco Felsch 796cb7a01acSMauro Carvalho Chehab static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 797cb7a01acSMauro Carvalho Chehab { 798cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 799baf17821SMarco Felsch struct tvp5150_connector *cur_con = decoder->cur_connector; 800baf17821SMarco Felsch v4l2_std_id supported_stds; 801cb7a01acSMauro Carvalho Chehab 802cb7a01acSMauro Carvalho Chehab if (decoder->norm == std) 803cb7a01acSMauro Carvalho Chehab return 0; 804cb7a01acSMauro Carvalho Chehab 805baf17821SMarco Felsch /* In case of no of-connectors are available no limitations are made */ 806baf17821SMarco Felsch if (!decoder->connectors_num) 807baf17821SMarco Felsch supported_stds = V4L2_STD_ALL; 808baf17821SMarco Felsch else 809baf17821SMarco Felsch supported_stds = cur_con->base.connector.analog.sdtv_stds; 810baf17821SMarco Felsch 811baf17821SMarco Felsch /* 812baf17821SMarco Felsch * Check if requested std or group of std's is/are supported by the 813baf17821SMarco Felsch * connector. 814baf17821SMarco Felsch */ 815baf17821SMarco Felsch if ((supported_stds & std) == 0) 816baf17821SMarco Felsch return -EINVAL; 817baf17821SMarco Felsch 818cb7a01acSMauro Carvalho Chehab /* Change cropping height limits */ 819cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 820cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_525_60; 821cb7a01acSMauro Carvalho Chehab else 822cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_OTHERS; 823cb7a01acSMauro Carvalho Chehab 824baf17821SMarco Felsch /* Set only the specific supported std in case of group of std's. */ 825baf17821SMarco Felsch decoder->norm = supported_stds & std; 826cb7a01acSMauro Carvalho Chehab 827cb7a01acSMauro Carvalho Chehab return tvp5150_set_std(sd, std); 828cb7a01acSMauro Carvalho Chehab } 829cb7a01acSMauro Carvalho Chehab 83015695866SPhilipp Zabel static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) 83115695866SPhilipp Zabel { 83215695866SPhilipp Zabel int val = tvp5150_read(sd, TVP5150_STATUS_REG_5); 83315695866SPhilipp Zabel 83415695866SPhilipp Zabel switch (val & 0x0F) { 83515695866SPhilipp Zabel case 0x01: 83615695866SPhilipp Zabel return V4L2_STD_NTSC; 83715695866SPhilipp Zabel case 0x03: 83815695866SPhilipp Zabel return V4L2_STD_PAL; 83915695866SPhilipp Zabel case 0x05: 84015695866SPhilipp Zabel return V4L2_STD_PAL_M; 84115695866SPhilipp Zabel case 0x07: 84215695866SPhilipp Zabel return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc; 84315695866SPhilipp Zabel case 0x09: 84415695866SPhilipp Zabel return V4L2_STD_NTSC_443; 84515695866SPhilipp Zabel case 0xb: 84615695866SPhilipp Zabel return V4L2_STD_SECAM; 84715695866SPhilipp Zabel default: 84815695866SPhilipp Zabel return V4L2_STD_UNKNOWN; 84915695866SPhilipp Zabel } 85015695866SPhilipp Zabel } 85115695866SPhilipp Zabel 8525bd1d91dSMauro Carvalho Chehab static int query_lock(struct v4l2_subdev *sd) 8535bd1d91dSMauro Carvalho Chehab { 8545bd1d91dSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 8555bd1d91dSMauro Carvalho Chehab int status; 8565bd1d91dSMauro Carvalho Chehab 8575bd1d91dSMauro Carvalho Chehab if (decoder->irq) 8585bd1d91dSMauro Carvalho Chehab return decoder->lock; 8595bd1d91dSMauro Carvalho Chehab 8605bd1d91dSMauro Carvalho Chehab regmap_read(decoder->regmap, TVP5150_STATUS_REG_1, &status); 8615bd1d91dSMauro Carvalho Chehab 8625bd1d91dSMauro Carvalho Chehab /* For standard detection, we need the 3 locks */ 8635bd1d91dSMauro Carvalho Chehab return (status & 0x0e) == 0x0e; 8645bd1d91dSMauro Carvalho Chehab } 8655bd1d91dSMauro Carvalho Chehab 866ee9a6ff6SPhilipp Zabel static int tvp5150_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) 867ee9a6ff6SPhilipp Zabel { 8685bd1d91dSMauro Carvalho Chehab *std_id = query_lock(sd) ? tvp5150_read_std(sd) : V4L2_STD_UNKNOWN; 869ee9a6ff6SPhilipp Zabel 870ee9a6ff6SPhilipp Zabel return 0; 871ee9a6ff6SPhilipp Zabel } 872ee9a6ff6SPhilipp Zabel 8732f0a5c65SPhilipp Zabel static const struct v4l2_event tvp5150_ev_fmt = { 8742f0a5c65SPhilipp Zabel .type = V4L2_EVENT_SOURCE_CHANGE, 8752f0a5c65SPhilipp Zabel .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 8762f0a5c65SPhilipp Zabel }; 8772f0a5c65SPhilipp Zabel 8788e4c97e0SPhilipp Zabel static irqreturn_t tvp5150_isr(int irq, void *dev_id) 8798e4c97e0SPhilipp Zabel { 8808e4c97e0SPhilipp Zabel struct tvp5150 *decoder = dev_id; 8818e4c97e0SPhilipp Zabel struct regmap *map = decoder->regmap; 88262a764e1SPhilipp Zabel unsigned int mask, active = 0, status = 0; 88362a764e1SPhilipp Zabel 88462a764e1SPhilipp Zabel mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE | 88562a764e1SPhilipp Zabel TVP5150_MISC_CTL_CLOCK_OE; 8868e4c97e0SPhilipp Zabel 8878e4c97e0SPhilipp Zabel regmap_read(map, TVP5150_INT_STATUS_REG_A, &status); 8888e4c97e0SPhilipp Zabel if (status) { 8898e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INT_STATUS_REG_A, status); 8908e4c97e0SPhilipp Zabel 89162a764e1SPhilipp Zabel if (status & TVP5150_INT_A_LOCK) { 8928e4c97e0SPhilipp Zabel decoder->lock = !!(status & TVP5150_INT_A_LOCK_STATUS); 8937bb3c338SPhilipp Zabel dev_dbg_lvl(decoder->sd.dev, 1, debug, 8947bb3c338SPhilipp Zabel "sync lo%s signal\n", 8957bb3c338SPhilipp Zabel decoder->lock ? "ck" : "ss"); 8962f0a5c65SPhilipp Zabel v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt); 89762a764e1SPhilipp Zabel regmap_update_bits(map, TVP5150_MISC_CTL, mask, 89862a764e1SPhilipp Zabel decoder->lock ? decoder->oe : 0); 89962a764e1SPhilipp Zabel } 9008e4c97e0SPhilipp Zabel 9018e4c97e0SPhilipp Zabel return IRQ_HANDLED; 9028e4c97e0SPhilipp Zabel } 9038e4c97e0SPhilipp Zabel 9048e4c97e0SPhilipp Zabel regmap_read(map, TVP5150_INT_ACTIVE_REG_B, &active); 9058e4c97e0SPhilipp Zabel if (active) { 9068e4c97e0SPhilipp Zabel status = 0; 9078e4c97e0SPhilipp Zabel regmap_read(map, TVP5150_INT_STATUS_REG_B, &status); 9088e4c97e0SPhilipp Zabel if (status) 9098e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INT_RESET_REG_B, status); 9108e4c97e0SPhilipp Zabel } 9118e4c97e0SPhilipp Zabel 9128e4c97e0SPhilipp Zabel return IRQ_HANDLED; 9138e4c97e0SPhilipp Zabel } 9148e4c97e0SPhilipp Zabel 915cb7a01acSMauro Carvalho Chehab static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) 916cb7a01acSMauro Carvalho Chehab { 917cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 9188105e1bcSPhilipp Zabel struct regmap *map = decoder->regmap; 919cb7a01acSMauro Carvalho Chehab 920cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to its default values */ 921cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_default); 922cb7a01acSMauro Carvalho Chehab 9238e4c97e0SPhilipp Zabel if (decoder->irq) { 9248e4c97e0SPhilipp Zabel /* Configure pins: FID, VSYNC, INTREQ, SCLK */ 9258e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x0); 9268e4c97e0SPhilipp Zabel /* Set interrupt polarity to active high */ 9278e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE | 0x1); 9288e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x1); 9298e4c97e0SPhilipp Zabel } else { 9308105e1bcSPhilipp Zabel /* Configure pins: FID, VSYNC, GPCL/VBLK, SCLK */ 9318105e1bcSPhilipp Zabel regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x2); 9328e4c97e0SPhilipp Zabel /* Keep interrupt polarity active low */ 9338e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE); 9348e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x0); 9358e4c97e0SPhilipp Zabel } 9368105e1bcSPhilipp Zabel 937cb7a01acSMauro Carvalho Chehab /* Initializes VDP registers */ 9383dd6b560SMauro Carvalho Chehab tvp5150_vdp_init(sd); 939cb7a01acSMauro Carvalho Chehab 940cb7a01acSMauro Carvalho Chehab /* Selects decoder input */ 941cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 942cb7a01acSMauro Carvalho Chehab 943cb7a01acSMauro Carvalho Chehab /* Initialize image preferences */ 944cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&decoder->hdl); 945cb7a01acSMauro Carvalho Chehab 9461bb086bcSPhilipp Zabel return 0; 9471bb086bcSPhilipp Zabel } 9481bb086bcSPhilipp Zabel 9491bb086bcSPhilipp Zabel static int tvp5150_enable(struct v4l2_subdev *sd) 9501bb086bcSPhilipp Zabel { 9511bb086bcSPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 9521bb086bcSPhilipp Zabel v4l2_std_id std; 9531bb086bcSPhilipp Zabel 9541bb086bcSPhilipp Zabel /* Initializes TVP5150 to stream enabled values */ 9551bb086bcSPhilipp Zabel tvp5150_write_inittab(sd, tvp5150_init_enable); 9561bb086bcSPhilipp Zabel 95715695866SPhilipp Zabel if (decoder->norm == V4L2_STD_ALL) 95815695866SPhilipp Zabel std = tvp5150_read_std(sd); 95915695866SPhilipp Zabel else 96015695866SPhilipp Zabel std = decoder->norm; 96115695866SPhilipp Zabel 96215695866SPhilipp Zabel /* Disable autoswitch mode */ 96315695866SPhilipp Zabel tvp5150_set_std(sd, std); 964a2e5f1b3SJavier Martinez Canillas 96562a764e1SPhilipp Zabel /* 96662a764e1SPhilipp Zabel * Enable the YCbCr and clock outputs. In discrete sync mode 96762a764e1SPhilipp Zabel * (non-BT.656) additionally enable the the sync outputs. 96862a764e1SPhilipp Zabel */ 96962a764e1SPhilipp Zabel switch (decoder->mbus_type) { 97062a764e1SPhilipp Zabel case V4L2_MBUS_PARALLEL: 9718a7441baSMarco Felsch /* 8-bit 4:2:2 YUV with discrete sync output */ 9728a7441baSMarco Felsch regmap_update_bits(decoder->regmap, TVP5150_DATA_RATE_SEL, 9738a7441baSMarco Felsch 0x7, 0x0); 97462a764e1SPhilipp Zabel decoder->oe = TVP5150_MISC_CTL_YCBCR_OE | 97562a764e1SPhilipp Zabel TVP5150_MISC_CTL_CLOCK_OE | 97662a764e1SPhilipp Zabel TVP5150_MISC_CTL_SYNC_OE; 97762a764e1SPhilipp Zabel break; 97862a764e1SPhilipp Zabel case V4L2_MBUS_BT656: 97962a764e1SPhilipp Zabel decoder->oe = TVP5150_MISC_CTL_YCBCR_OE | 98062a764e1SPhilipp Zabel TVP5150_MISC_CTL_CLOCK_OE; 98162a764e1SPhilipp Zabel break; 98262a764e1SPhilipp Zabel default: 98362a764e1SPhilipp Zabel return -EINVAL; 98462a764e1SPhilipp Zabel } 985a2e5f1b3SJavier Martinez Canillas 986cb7a01acSMauro Carvalho Chehab return 0; 987cb7a01acSMauro Carvalho Chehab }; 988cb7a01acSMauro Carvalho Chehab 989cb7a01acSMauro Carvalho Chehab static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) 990cb7a01acSMauro Carvalho Chehab { 991cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_sd(ctrl); 992c43875f6SMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 993cb7a01acSMauro Carvalho Chehab 994cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 995cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 99628b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_BRIGHT_CTL, ctrl->val); 997cb7a01acSMauro Carvalho Chehab return 0; 998cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 99928b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_CONTRAST_CTL, ctrl->val); 1000cb7a01acSMauro Carvalho Chehab return 0; 1001cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 100228b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_SATURATION_CTL, 100328b9e227SPhilipp Zabel ctrl->val); 1004cb7a01acSMauro Carvalho Chehab return 0; 1005cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 100628b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_HUE_CTL, ctrl->val); 10072d29bcc8SMarco Felsch return 0; 1008c43875f6SMauro Carvalho Chehab case V4L2_CID_TEST_PATTERN: 1009c43875f6SMauro Carvalho Chehab decoder->enable = ctrl->val ? false : true; 1010c43875f6SMauro Carvalho Chehab tvp5150_selmux(sd); 1011cb7a01acSMauro Carvalho Chehab return 0; 1012cb7a01acSMauro Carvalho Chehab } 1013cb7a01acSMauro Carvalho Chehab return -EINVAL; 1014cb7a01acSMauro Carvalho Chehab } 1015cb7a01acSMauro Carvalho Chehab 10165cb82940SMarco Felsch static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop) 10175cb82940SMarco Felsch { 10185cb82940SMarco Felsch /* Default is no cropping */ 10195cb82940SMarco Felsch crop->top = 0; 10205cb82940SMarco Felsch crop->left = 0; 10215cb82940SMarco Felsch crop->width = TVP5150_H_MAX; 10225cb82940SMarco Felsch if (std & V4L2_STD_525_60) 10235cb82940SMarco Felsch crop->height = TVP5150_V_MAX_525_60; 10245cb82940SMarco Felsch else 10255cb82940SMarco Felsch crop->height = TVP5150_V_MAX_OTHERS; 10265cb82940SMarco Felsch } 10275cb82940SMarco Felsch 102846fe6e7dSMarco Felsch static struct v4l2_rect * 102946fe6e7dSMarco Felsch tvp5150_get_pad_crop(struct tvp5150 *decoder, 103046fe6e7dSMarco Felsch struct v4l2_subdev_pad_config *cfg, unsigned int pad, 103146fe6e7dSMarco Felsch enum v4l2_subdev_format_whence which) 103246fe6e7dSMarco Felsch { 103346fe6e7dSMarco Felsch switch (which) { 103446fe6e7dSMarco Felsch case V4L2_SUBDEV_FORMAT_ACTIVE: 103546fe6e7dSMarco Felsch return &decoder->rect; 103646fe6e7dSMarco Felsch case V4L2_SUBDEV_FORMAT_TRY: 103746fe6e7dSMarco Felsch #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 103846fe6e7dSMarco Felsch return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad); 103946fe6e7dSMarco Felsch #else 104046fe6e7dSMarco Felsch return ERR_PTR(-EINVAL); 104146fe6e7dSMarco Felsch #endif 104246fe6e7dSMarco Felsch default: 104346fe6e7dSMarco Felsch return ERR_PTR(-EINVAL); 104446fe6e7dSMarco Felsch } 104546fe6e7dSMarco Felsch } 104646fe6e7dSMarco Felsch 1047da298c6dSHans Verkuil static int tvp5150_fill_fmt(struct v4l2_subdev *sd, 1048da298c6dSHans Verkuil struct v4l2_subdev_pad_config *cfg, 1049da298c6dSHans Verkuil struct v4l2_subdev_format *format) 1050cb7a01acSMauro Carvalho Chehab { 1051da298c6dSHans Verkuil struct v4l2_mbus_framefmt *f; 1052cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1053cb7a01acSMauro Carvalho Chehab 1054bc322c0dSMauro Carvalho Chehab if (!format || (format->pad != TVP5150_PAD_VID_OUT)) 1055cb7a01acSMauro Carvalho Chehab return -EINVAL; 1056cb7a01acSMauro Carvalho Chehab 1057da298c6dSHans Verkuil f = &format->format; 1058da298c6dSHans Verkuil 1059cb7a01acSMauro Carvalho Chehab f->width = decoder->rect.width; 10601831af09SJavier Martinez Canillas f->height = decoder->rect.height / 2; 1061cb7a01acSMauro Carvalho Chehab 10625cb82940SMarco Felsch f->code = TVP5150_MBUS_FMT; 10635cb82940SMarco Felsch f->field = TVP5150_FIELD; 10645cb82940SMarco Felsch f->colorspace = TVP5150_COLORSPACE; 1065cb7a01acSMauro Carvalho Chehab 1066257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "width = %d, height = %d\n", f->width, 1067cb7a01acSMauro Carvalho Chehab f->height); 1068cb7a01acSMauro Carvalho Chehab return 0; 1069cb7a01acSMauro Carvalho Chehab } 1070cb7a01acSMauro Carvalho Chehab 107146fe6e7dSMarco Felsch static unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd) 1072cb7a01acSMauro Carvalho Chehab { 1073cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1074cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 1075cb7a01acSMauro Carvalho Chehab 1076cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 1077cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 1078cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 1079cb7a01acSMauro Carvalho Chehab else 1080cb7a01acSMauro Carvalho Chehab std = decoder->norm; 1081cb7a01acSMauro Carvalho Chehab 108246fe6e7dSMarco Felsch return (std & V4L2_STD_525_60) ? 108346fe6e7dSMarco Felsch TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS; 108446fe6e7dSMarco Felsch } 1085cb7a01acSMauro Carvalho Chehab 108646fe6e7dSMarco Felsch static void tvp5150_set_hw_selection(struct v4l2_subdev *sd, 108746fe6e7dSMarco Felsch struct v4l2_rect *rect) 108846fe6e7dSMarco Felsch { 108946fe6e7dSMarco Felsch struct tvp5150 *decoder = to_tvp5150(sd); 109046fe6e7dSMarco Felsch unsigned int hmax = tvp5150_get_hmax(sd); 1091cb7a01acSMauro Carvalho Chehab 1092b4125e5bSMarco Felsch regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect->top); 109328b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, 1094b4125e5bSMarco Felsch rect->top + rect->height - hmax); 109528b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB, 1096b4125e5bSMarco Felsch rect->left >> TVP5150_CROP_SHIFT); 109728b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB, 1098b4125e5bSMarco Felsch rect->left | (1 << TVP5150_CROP_SHIFT)); 109928b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB, 1100b4125e5bSMarco Felsch (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >> 1101cb7a01acSMauro Carvalho Chehab TVP5150_CROP_SHIFT); 110228b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB, 1103b4125e5bSMarco Felsch rect->left + rect->width - TVP5150_MAX_CROP_LEFT); 110446fe6e7dSMarco Felsch } 1105cb7a01acSMauro Carvalho Chehab 110646fe6e7dSMarco Felsch static int tvp5150_set_selection(struct v4l2_subdev *sd, 110746fe6e7dSMarco Felsch struct v4l2_subdev_pad_config *cfg, 110846fe6e7dSMarco Felsch struct v4l2_subdev_selection *sel) 110946fe6e7dSMarco Felsch { 111046fe6e7dSMarco Felsch struct tvp5150 *decoder = to_tvp5150(sd); 111146fe6e7dSMarco Felsch struct v4l2_rect *rect = &sel->r; 111246fe6e7dSMarco Felsch struct v4l2_rect *crop; 111346fe6e7dSMarco Felsch unsigned int hmax; 111446fe6e7dSMarco Felsch 111546fe6e7dSMarco Felsch if (sel->target != V4L2_SEL_TGT_CROP) 111646fe6e7dSMarco Felsch return -EINVAL; 111746fe6e7dSMarco Felsch 111846fe6e7dSMarco Felsch dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n", 111946fe6e7dSMarco Felsch __func__, rect->left, rect->top, rect->width, rect->height); 112046fe6e7dSMarco Felsch 112146fe6e7dSMarco Felsch /* tvp5150 has some special limits */ 112246fe6e7dSMarco Felsch rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT); 112346fe6e7dSMarco Felsch rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP); 112446fe6e7dSMarco Felsch hmax = tvp5150_get_hmax(sd); 112546fe6e7dSMarco Felsch 112646fe6e7dSMarco Felsch /* 112746fe6e7dSMarco Felsch * alignments: 112846fe6e7dSMarco Felsch * - width = 2 due to UYVY colorspace 112946fe6e7dSMarco Felsch * - height, image = no special alignment 113046fe6e7dSMarco Felsch */ 113146fe6e7dSMarco Felsch v4l_bound_align_image(&rect->width, 113246fe6e7dSMarco Felsch TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left, 113346fe6e7dSMarco Felsch TVP5150_H_MAX - rect->left, 1, &rect->height, 113446fe6e7dSMarco Felsch hmax - TVP5150_MAX_CROP_TOP - rect->top, 113546fe6e7dSMarco Felsch hmax - rect->top, 0, 0); 113646fe6e7dSMarco Felsch 113746fe6e7dSMarco Felsch if (!IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API) && 113846fe6e7dSMarco Felsch sel->which == V4L2_SUBDEV_FORMAT_TRY) 113946fe6e7dSMarco Felsch return 0; 114046fe6e7dSMarco Felsch 114146fe6e7dSMarco Felsch crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which); 114246fe6e7dSMarco Felsch if (IS_ERR(crop)) 114346fe6e7dSMarco Felsch return PTR_ERR(crop); 114446fe6e7dSMarco Felsch 114546fe6e7dSMarco Felsch /* 114646fe6e7dSMarco Felsch * Update output image size if the selection (crop) rectangle size or 114746fe6e7dSMarco Felsch * position has been modified. 114846fe6e7dSMarco Felsch */ 114946fe6e7dSMarco Felsch if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && 115046fe6e7dSMarco Felsch !v4l2_rect_equal(rect, crop)) 115146fe6e7dSMarco Felsch tvp5150_set_hw_selection(sd, rect); 115246fe6e7dSMarco Felsch 115346fe6e7dSMarco Felsch *crop = *rect; 1154cb7a01acSMauro Carvalho Chehab 1155cb7a01acSMauro Carvalho Chehab return 0; 1156cb7a01acSMauro Carvalho Chehab } 1157cb7a01acSMauro Carvalho Chehab 115810d5509cSHans Verkuil static int tvp5150_get_selection(struct v4l2_subdev *sd, 115910d5509cSHans Verkuil struct v4l2_subdev_pad_config *cfg, 116010d5509cSHans Verkuil struct v4l2_subdev_selection *sel) 1161cb7a01acSMauro Carvalho Chehab { 116210d5509cSHans Verkuil struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); 116346fe6e7dSMarco Felsch struct v4l2_rect *crop; 1164cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 1165cb7a01acSMauro Carvalho Chehab 116610d5509cSHans Verkuil switch (sel->target) { 116710d5509cSHans Verkuil case V4L2_SEL_TGT_CROP_BOUNDS: 116810d5509cSHans Verkuil sel->r.left = 0; 116910d5509cSHans Verkuil sel->r.top = 0; 117010d5509cSHans Verkuil sel->r.width = TVP5150_H_MAX; 1171cb7a01acSMauro Carvalho Chehab 1172cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 1173cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 1174cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 1175cb7a01acSMauro Carvalho Chehab else 1176cb7a01acSMauro Carvalho Chehab std = decoder->norm; 1177cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 117810d5509cSHans Verkuil sel->r.height = TVP5150_V_MAX_525_60; 1179cb7a01acSMauro Carvalho Chehab else 118010d5509cSHans Verkuil sel->r.height = TVP5150_V_MAX_OTHERS; 1181cb7a01acSMauro Carvalho Chehab return 0; 118210d5509cSHans Verkuil case V4L2_SEL_TGT_CROP: 118346fe6e7dSMarco Felsch crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad, 118446fe6e7dSMarco Felsch sel->which); 118546fe6e7dSMarco Felsch if (IS_ERR(crop)) 118646fe6e7dSMarco Felsch return PTR_ERR(crop); 118746fe6e7dSMarco Felsch sel->r = *crop; 118810d5509cSHans Verkuil return 0; 118910d5509cSHans Verkuil default: 119010d5509cSHans Verkuil return -EINVAL; 119110d5509cSHans Verkuil } 1192cb7a01acSMauro Carvalho Chehab } 1193cb7a01acSMauro Carvalho Chehab 1194dd3a46bbSLaurent Pinchart static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, 1195dd3a46bbSLaurent Pinchart struct v4l2_mbus_config *cfg) 1196dd3a46bbSLaurent Pinchart { 1197a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1198a2e5f1b3SJavier Martinez Canillas 1199a2e5f1b3SJavier Martinez Canillas cfg->type = decoder->mbus_type; 1200dd3a46bbSLaurent Pinchart cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING 1201dd3a46bbSLaurent Pinchart | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; 1202dd3a46bbSLaurent Pinchart 1203dd3a46bbSLaurent Pinchart return 0; 1204dd3a46bbSLaurent Pinchart } 1205dd3a46bbSLaurent Pinchart 1206cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1207e545ac87SLaurent Pinchart V4L2 subdev pad ops 1208e545ac87SLaurent Pinchart ****************************************************************************/ 1209b440b733SPhilipp Zabel static int tvp5150_init_cfg(struct v4l2_subdev *sd, 1210b440b733SPhilipp Zabel struct v4l2_subdev_pad_config *cfg) 1211b440b733SPhilipp Zabel { 1212b440b733SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 1213b440b733SPhilipp Zabel v4l2_std_id std; 1214b440b733SPhilipp Zabel 1215b440b733SPhilipp Zabel /* 1216b440b733SPhilipp Zabel * Reset selection to maximum on subdev_open() if autodetection is on 1217b440b733SPhilipp Zabel * and a standard change is detected. 1218b440b733SPhilipp Zabel */ 1219b440b733SPhilipp Zabel if (decoder->norm == V4L2_STD_ALL) { 1220b440b733SPhilipp Zabel std = tvp5150_read_std(sd); 1221b440b733SPhilipp Zabel if (std != decoder->detected_norm) { 1222b440b733SPhilipp Zabel decoder->detected_norm = std; 1223b440b733SPhilipp Zabel tvp5150_set_default(std, &decoder->rect); 1224b440b733SPhilipp Zabel } 1225b440b733SPhilipp Zabel } 1226b440b733SPhilipp Zabel 1227b440b733SPhilipp Zabel return 0; 1228b440b733SPhilipp Zabel } 1229b440b733SPhilipp Zabel 1230e545ac87SLaurent Pinchart static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, 1231e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 1232e545ac87SLaurent Pinchart struct v4l2_subdev_mbus_code_enum *code) 1233e545ac87SLaurent Pinchart { 1234e545ac87SLaurent Pinchart if (code->pad || code->index) 1235e545ac87SLaurent Pinchart return -EINVAL; 1236e545ac87SLaurent Pinchart 12375cb82940SMarco Felsch code->code = TVP5150_MBUS_FMT; 1238e545ac87SLaurent Pinchart return 0; 1239e545ac87SLaurent Pinchart } 1240e545ac87SLaurent Pinchart 1241e545ac87SLaurent Pinchart static int tvp5150_enum_frame_size(struct v4l2_subdev *sd, 1242e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 1243e545ac87SLaurent Pinchart struct v4l2_subdev_frame_size_enum *fse) 1244e545ac87SLaurent Pinchart { 1245e545ac87SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 1246e545ac87SLaurent Pinchart 12475cb82940SMarco Felsch if (fse->index >= 8 || fse->code != TVP5150_MBUS_FMT) 1248e545ac87SLaurent Pinchart return -EINVAL; 1249e545ac87SLaurent Pinchart 12505cb82940SMarco Felsch fse->code = TVP5150_MBUS_FMT; 1251e545ac87SLaurent Pinchart fse->min_width = decoder->rect.width; 1252e545ac87SLaurent Pinchart fse->max_width = decoder->rect.width; 1253e545ac87SLaurent Pinchart fse->min_height = decoder->rect.height / 2; 1254e545ac87SLaurent Pinchart fse->max_height = decoder->rect.height / 2; 1255e545ac87SLaurent Pinchart 1256e545ac87SLaurent Pinchart return 0; 1257e545ac87SLaurent Pinchart } 1258e545ac87SLaurent Pinchart 1259e545ac87SLaurent Pinchart /**************************************************************************** 12600556f1d5SMarco Felsch * Media entity ops 12610556f1d5SMarco Felsch ****************************************************************************/ 12620556f1d5SMarco Felsch #if defined(CONFIG_MEDIA_CONTROLLER) 12630556f1d5SMarco Felsch static int tvp5150_set_link(struct media_pad *connector_pad, 12640556f1d5SMarco Felsch struct media_pad *tvp5150_pad, u32 flags) 12650556f1d5SMarco Felsch { 12660556f1d5SMarco Felsch struct media_link *link; 12670556f1d5SMarco Felsch 12680556f1d5SMarco Felsch link = media_entity_find_link(connector_pad, tvp5150_pad); 12690556f1d5SMarco Felsch if (!link) 12700556f1d5SMarco Felsch return -EINVAL; 12710556f1d5SMarco Felsch 12720556f1d5SMarco Felsch link->flags = flags; 12730556f1d5SMarco Felsch link->reverse->flags = link->flags; 12740556f1d5SMarco Felsch 12750556f1d5SMarco Felsch return 0; 12760556f1d5SMarco Felsch } 12770556f1d5SMarco Felsch 12780556f1d5SMarco Felsch static int tvp5150_disable_all_input_links(struct tvp5150 *decoder) 12790556f1d5SMarco Felsch { 12800556f1d5SMarco Felsch struct media_pad *connector_pad; 12810556f1d5SMarco Felsch unsigned int i; 12820556f1d5SMarco Felsch int err; 12830556f1d5SMarco Felsch 12840556f1d5SMarco Felsch for (i = 0; i < TVP5150_NUM_PADS - 1; i++) { 12850556f1d5SMarco Felsch connector_pad = media_entity_remote_pad(&decoder->pads[i]); 12860556f1d5SMarco Felsch if (!connector_pad) 12870556f1d5SMarco Felsch continue; 12880556f1d5SMarco Felsch 12890556f1d5SMarco Felsch err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0); 12900556f1d5SMarco Felsch if (err) 12910556f1d5SMarco Felsch return err; 12920556f1d5SMarco Felsch } 12930556f1d5SMarco Felsch 12940556f1d5SMarco Felsch return 0; 12950556f1d5SMarco Felsch } 12960556f1d5SMarco Felsch 12970556f1d5SMarco Felsch static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, 12980556f1d5SMarco Felsch u32 config); 12990556f1d5SMarco Felsch 13000556f1d5SMarco Felsch static int tvp5150_link_setup(struct media_entity *entity, 13010556f1d5SMarco Felsch const struct media_pad *tvp5150_pad, 13020556f1d5SMarco Felsch const struct media_pad *remote, u32 flags) 13030556f1d5SMarco Felsch { 13040556f1d5SMarco Felsch struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 13050556f1d5SMarco Felsch struct tvp5150 *decoder = to_tvp5150(sd); 13060556f1d5SMarco Felsch struct media_pad *other_tvp5150_pad = 13070556f1d5SMarco Felsch &decoder->pads[tvp5150_pad->index ^ 1]; 13080556f1d5SMarco Felsch struct v4l2_fwnode_connector *v4l2c; 13090556f1d5SMarco Felsch bool is_svideo = false; 13100556f1d5SMarco Felsch unsigned int i; 13110556f1d5SMarco Felsch int err; 13120556f1d5SMarco Felsch 13130556f1d5SMarco Felsch /* 13140556f1d5SMarco Felsch * The TVP5150 state is determined by the enabled sink pad link(s). 13150556f1d5SMarco Felsch * Enabling or disabling the source pad link has no effect. 13160556f1d5SMarco Felsch */ 13170556f1d5SMarco Felsch if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE) 13180556f1d5SMarco Felsch return 0; 13190556f1d5SMarco Felsch 13200556f1d5SMarco Felsch /* Check if the svideo connector should be enabled */ 13210556f1d5SMarco Felsch for (i = 0; i < decoder->connectors_num; i++) { 13220556f1d5SMarco Felsch if (remote->entity == &decoder->connectors[i].ent) { 13230556f1d5SMarco Felsch v4l2c = &decoder->connectors[i].base; 13240556f1d5SMarco Felsch is_svideo = v4l2c->type == V4L2_CONN_SVIDEO; 13250556f1d5SMarco Felsch break; 13260556f1d5SMarco Felsch } 13270556f1d5SMarco Felsch } 13280556f1d5SMarco Felsch 13290556f1d5SMarco Felsch dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]", 13300556f1d5SMarco Felsch remote->entity->name, remote->index, 13310556f1d5SMarco Felsch tvp5150_pad->entity->name, tvp5150_pad->index, 13320556f1d5SMarco Felsch flags & MEDIA_LNK_FL_ENABLED); 13330556f1d5SMarco Felsch if (is_svideo) 13340556f1d5SMarco Felsch dev_dbg_lvl(sd->dev, 1, debug, 13350556f1d5SMarco Felsch "link setup '%s':%d->'%s':%d[%d]", 13360556f1d5SMarco Felsch remote->entity->name, remote->index, 13370556f1d5SMarco Felsch other_tvp5150_pad->entity->name, 13380556f1d5SMarco Felsch other_tvp5150_pad->index, 13390556f1d5SMarco Felsch flags & MEDIA_LNK_FL_ENABLED); 13400556f1d5SMarco Felsch 13410556f1d5SMarco Felsch /* 13420556f1d5SMarco Felsch * The TVP5150 has an internal mux which allows the following setup: 13430556f1d5SMarco Felsch * 13440556f1d5SMarco Felsch * comp-connector1 --\ 13450556f1d5SMarco Felsch * |---> AIP1A 13460556f1d5SMarco Felsch * / 13470556f1d5SMarco Felsch * svideo-connector -| 13480556f1d5SMarco Felsch * \ 13490556f1d5SMarco Felsch * |---> AIP1B 13500556f1d5SMarco Felsch * comp-connector2 --/ 13510556f1d5SMarco Felsch * 13520556f1d5SMarco Felsch * We can't rely on user space that the current connector gets disabled 13530556f1d5SMarco Felsch * first before enabling the new connector. Disable all active 13540556f1d5SMarco Felsch * connector links to be on the safe side. 13550556f1d5SMarco Felsch */ 13560556f1d5SMarco Felsch err = tvp5150_disable_all_input_links(decoder); 13570556f1d5SMarco Felsch if (err) 13580556f1d5SMarco Felsch return err; 13590556f1d5SMarco Felsch 13600556f1d5SMarco Felsch tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index, 13610556f1d5SMarco Felsch flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL : 13620556f1d5SMarco Felsch TVP5150_BLACK_SCREEN, 0); 13630556f1d5SMarco Felsch 13640556f1d5SMarco Felsch if (flags & MEDIA_LNK_FL_ENABLED) { 1365baf17821SMarco Felsch struct v4l2_fwnode_connector_analog *v4l2ca; 1366baf17821SMarco Felsch u32 new_norm; 1367baf17821SMarco Felsch 13680556f1d5SMarco Felsch /* 13690556f1d5SMarco Felsch * S-Video connector is conneted to both ports AIP1A and AIP1B. 13700556f1d5SMarco Felsch * Both links must be enabled in one-shot regardless which link 13710556f1d5SMarco Felsch * the user requests. 13720556f1d5SMarco Felsch */ 13730556f1d5SMarco Felsch if (is_svideo) { 13740556f1d5SMarco Felsch err = tvp5150_set_link((struct media_pad *)remote, 13750556f1d5SMarco Felsch other_tvp5150_pad, flags); 13760556f1d5SMarco Felsch if (err) 13770556f1d5SMarco Felsch return err; 13780556f1d5SMarco Felsch } 1379baf17821SMarco Felsch 1380baf17821SMarco Felsch if (!decoder->connectors_num) 1381baf17821SMarco Felsch return 0; 1382baf17821SMarco Felsch 1383baf17821SMarco Felsch /* Update the current connector */ 1384baf17821SMarco Felsch decoder->cur_connector = 1385baf17821SMarco Felsch container_of(remote, struct tvp5150_connector, pad); 1386baf17821SMarco Felsch 1387baf17821SMarco Felsch /* 1388baf17821SMarco Felsch * Do nothing if the new connector supports the same tv-norms as 1389baf17821SMarco Felsch * the old one. 1390baf17821SMarco Felsch */ 1391baf17821SMarco Felsch v4l2ca = &decoder->cur_connector->base.connector.analog; 1392baf17821SMarco Felsch new_norm = decoder->norm & v4l2ca->sdtv_stds; 1393baf17821SMarco Felsch if (decoder->norm == new_norm) 1394baf17821SMarco Felsch return 0; 1395baf17821SMarco Felsch 1396baf17821SMarco Felsch /* 1397baf17821SMarco Felsch * Fallback to the new connector tv-norms if we can't find any 1398baf17821SMarco Felsch * common between the current tv-norm and the new one. 1399baf17821SMarco Felsch */ 1400baf17821SMarco Felsch tvp5150_s_std(sd, new_norm ? new_norm : v4l2ca->sdtv_stds); 14010556f1d5SMarco Felsch } 14020556f1d5SMarco Felsch 14030556f1d5SMarco Felsch return 0; 14040556f1d5SMarco Felsch } 14050556f1d5SMarco Felsch 14060556f1d5SMarco Felsch static const struct media_entity_operations tvp5150_sd_media_ops = { 14070556f1d5SMarco Felsch .link_setup = tvp5150_link_setup, 14080556f1d5SMarco Felsch }; 14090556f1d5SMarco Felsch #endif 14100556f1d5SMarco Felsch /**************************************************************************** 1411cb7a01acSMauro Carvalho Chehab I2C Command 1412cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 141373549a69SMarco Felsch static int __maybe_unused tvp5150_runtime_suspend(struct device *dev) 141473549a69SMarco Felsch { 141573549a69SMarco Felsch struct i2c_client *client = to_i2c_client(dev); 141673549a69SMarco Felsch struct v4l2_subdev *sd = i2c_get_clientdata(client); 141773549a69SMarco Felsch struct tvp5150 *decoder = to_tvp5150(sd); 141873549a69SMarco Felsch 141973549a69SMarco Felsch if (decoder->irq) 142073549a69SMarco Felsch /* Disable lock interrupt */ 142173549a69SMarco Felsch return regmap_update_bits(decoder->regmap, 142273549a69SMarco Felsch TVP5150_INT_ENABLE_REG_A, 142373549a69SMarco Felsch TVP5150_INT_A_LOCK, 0); 142473549a69SMarco Felsch return 0; 142573549a69SMarco Felsch } 142673549a69SMarco Felsch 142773549a69SMarco Felsch static int __maybe_unused tvp5150_runtime_resume(struct device *dev) 142873549a69SMarco Felsch { 142973549a69SMarco Felsch struct i2c_client *client = to_i2c_client(dev); 143073549a69SMarco Felsch struct v4l2_subdev *sd = i2c_get_clientdata(client); 143173549a69SMarco Felsch struct tvp5150 *decoder = to_tvp5150(sd); 143273549a69SMarco Felsch 143373549a69SMarco Felsch if (decoder->irq) 143473549a69SMarco Felsch /* Enable lock interrupt */ 143573549a69SMarco Felsch return regmap_update_bits(decoder->regmap, 143673549a69SMarco Felsch TVP5150_INT_ENABLE_REG_A, 143773549a69SMarco Felsch TVP5150_INT_A_LOCK, 143873549a69SMarco Felsch TVP5150_INT_A_LOCK); 143973549a69SMarco Felsch return 0; 144073549a69SMarco Felsch } 1441cb7a01acSMauro Carvalho Chehab 1442460b6c08SLaurent Pinchart static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) 1443460b6c08SLaurent Pinchart { 1444a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 144573549a69SMarco Felsch unsigned int mask, val = 0; 144673549a69SMarco Felsch int ret; 1447a2e5f1b3SJavier Martinez Canillas 14488a7441baSMarco Felsch mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE | 14498a7441baSMarco Felsch TVP5150_MISC_CTL_CLOCK_OE; 145079d6205aSLaurent Pinchart 145179d6205aSLaurent Pinchart if (enable) { 145273549a69SMarco Felsch ret = pm_runtime_get_sync(sd->dev); 145373549a69SMarco Felsch if (ret < 0) { 145473549a69SMarco Felsch pm_runtime_put_noidle(sd->dev); 145573549a69SMarco Felsch return ret; 145673549a69SMarco Felsch } 145773549a69SMarco Felsch 14581bb086bcSPhilipp Zabel tvp5150_enable(sd); 14591bb086bcSPhilipp Zabel 146062a764e1SPhilipp Zabel /* Enable outputs if decoder is locked */ 14615bd1d91dSMauro Carvalho Chehab if (decoder->irq) 146262a764e1SPhilipp Zabel val = decoder->lock ? decoder->oe : 0; 14635bd1d91dSMauro Carvalho Chehab else 14645bd1d91dSMauro Carvalho Chehab val = decoder->oe; 146573549a69SMarco Felsch 14662f0a5c65SPhilipp Zabel v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt); 146773549a69SMarco Felsch } else { 146873549a69SMarco Felsch pm_runtime_put(sd->dev); 146979d6205aSLaurent Pinchart } 1470a2e5f1b3SJavier Martinez Canillas 14718a7441baSMarco Felsch regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val); 1472460b6c08SLaurent Pinchart 1473460b6c08SLaurent Pinchart return 0; 1474460b6c08SLaurent Pinchart } 1475460b6c08SLaurent Pinchart 1476cb7a01acSMauro Carvalho Chehab static int tvp5150_s_routing(struct v4l2_subdev *sd, 1477cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 1478cb7a01acSMauro Carvalho Chehab { 1479cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1480cb7a01acSMauro Carvalho Chehab 1481cb7a01acSMauro Carvalho Chehab decoder->input = input; 1482cb7a01acSMauro Carvalho Chehab decoder->output = output; 1483c43875f6SMauro Carvalho Chehab 1484c43875f6SMauro Carvalho Chehab if (output == TVP5150_BLACK_SCREEN) 1485c43875f6SMauro Carvalho Chehab decoder->enable = false; 1486c43875f6SMauro Carvalho Chehab else 1487c43875f6SMauro Carvalho Chehab decoder->enable = true; 1488c43875f6SMauro Carvalho Chehab 1489cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 1490cb7a01acSMauro Carvalho Chehab return 0; 1491cb7a01acSMauro Carvalho Chehab } 1492cb7a01acSMauro Carvalho Chehab 1493cb7a01acSMauro Carvalho Chehab static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) 1494cb7a01acSMauro Carvalho Chehab { 149528b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 149628b9e227SPhilipp Zabel 14979bfd8f88SNasser Afshin /* 14989bfd8f88SNasser Afshin * this is for capturing 36 raw vbi lines 14999bfd8f88SNasser Afshin * if there's a way to cut off the beginning 2 vbi lines 15009bfd8f88SNasser Afshin * with the tvp5150 then the vbi line count could be lowered 15019bfd8f88SNasser Afshin * to 17 lines/field again, although I couldn't find a register 15029bfd8f88SNasser Afshin * which could do that cropping 15039bfd8f88SNasser Afshin */ 15049bfd8f88SNasser Afshin 1505cb7a01acSMauro Carvalho Chehab if (fmt->sample_format == V4L2_PIX_FMT_GREY) 150628b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_LUMA_PROC_CTL_1, 0x70); 1507cb7a01acSMauro Carvalho Chehab if (fmt->count[0] == 18 && fmt->count[1] == 18) { 150828b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, 150928b9e227SPhilipp Zabel 0x00); 151028b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, 0x01); 1511cb7a01acSMauro Carvalho Chehab } 1512cb7a01acSMauro Carvalho Chehab return 0; 1513cb7a01acSMauro Carvalho Chehab } 1514cb7a01acSMauro Carvalho Chehab 1515cb7a01acSMauro Carvalho Chehab static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1516cb7a01acSMauro Carvalho Chehab { 151728b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 1518cb7a01acSMauro Carvalho Chehab int i; 1519cb7a01acSMauro Carvalho Chehab 1520cb7a01acSMauro Carvalho Chehab if (svbi->service_set != 0) { 1521cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1522cb7a01acSMauro Carvalho Chehab svbi->service_lines[1][i] = 0; 1523cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 15243dd6b560SMauro Carvalho Chehab tvp5150_set_vbi(sd, svbi->service_lines[0][i], 15253dd6b560SMauro Carvalho Chehab 0xf0, i, 3); 1526cb7a01acSMauro Carvalho Chehab } 1527cb7a01acSMauro Carvalho Chehab /* Enables FIFO */ 152828b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 1); 1529cb7a01acSMauro Carvalho Chehab } else { 1530cb7a01acSMauro Carvalho Chehab /* Disables FIFO*/ 153128b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 0); 1532cb7a01acSMauro Carvalho Chehab 1533cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 153428b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_FULL_FIELD_ENA, 0); 1535cb7a01acSMauro Carvalho Chehab 1536cb7a01acSMauro Carvalho Chehab /* Disable Line modes */ 1537cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 153828b9e227SPhilipp Zabel regmap_write(decoder->regmap, i, 0xff); 1539cb7a01acSMauro Carvalho Chehab } 1540cb7a01acSMauro Carvalho Chehab return 0; 1541cb7a01acSMauro Carvalho Chehab } 1542cb7a01acSMauro Carvalho Chehab 1543cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1544cb7a01acSMauro Carvalho Chehab { 1545cb7a01acSMauro Carvalho Chehab int i, mask = 0; 1546cb7a01acSMauro Carvalho Chehab 154730634e8eSHans Verkuil memset(svbi->service_lines, 0, sizeof(svbi->service_lines)); 1548cb7a01acSMauro Carvalho Chehab 1549cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1550cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 15513dd6b560SMauro Carvalho Chehab tvp5150_get_vbi(sd, i); 1552cb7a01acSMauro Carvalho Chehab mask |= svbi->service_lines[0][i]; 1553cb7a01acSMauro Carvalho Chehab } 1554cb7a01acSMauro Carvalho Chehab svbi->service_set = mask; 1555cb7a01acSMauro Carvalho Chehab return 0; 1556cb7a01acSMauro Carvalho Chehab } 1557cb7a01acSMauro Carvalho Chehab 1558cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1559cb7a01acSMauro Carvalho Chehab static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 1560cb7a01acSMauro Carvalho Chehab { 1561cb7a01acSMauro Carvalho Chehab int res; 1562cb7a01acSMauro Carvalho Chehab 1563cb7a01acSMauro Carvalho Chehab res = tvp5150_read(sd, reg->reg & 0xff); 1564cb7a01acSMauro Carvalho Chehab if (res < 0) { 1565257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "%s: failed with error = %d\n", __func__, res); 1566cb7a01acSMauro Carvalho Chehab return res; 1567cb7a01acSMauro Carvalho Chehab } 1568cb7a01acSMauro Carvalho Chehab 1569cb7a01acSMauro Carvalho Chehab reg->val = res; 1570cb7a01acSMauro Carvalho Chehab reg->size = 1; 1571cb7a01acSMauro Carvalho Chehab return 0; 1572cb7a01acSMauro Carvalho Chehab } 1573cb7a01acSMauro Carvalho Chehab 1574977ba3b1SHans Verkuil static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 1575cb7a01acSMauro Carvalho Chehab { 157628b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 157728b9e227SPhilipp Zabel 157828b9e227SPhilipp Zabel return regmap_write(decoder->regmap, reg->reg & 0xff, reg->val & 0xff); 1579cb7a01acSMauro Carvalho Chehab } 1580cb7a01acSMauro Carvalho Chehab #endif 1581cb7a01acSMauro Carvalho Chehab 1582e953c103SMarco Felsch static int tvp5150_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, 1583e953c103SMarco Felsch struct v4l2_event_subscription *sub) 1584e953c103SMarco Felsch { 1585e953c103SMarco Felsch switch (sub->type) { 1586e953c103SMarco Felsch case V4L2_EVENT_SOURCE_CHANGE: 1587e953c103SMarco Felsch return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 1588e953c103SMarco Felsch case V4L2_EVENT_CTRL: 1589e953c103SMarco Felsch return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 1590e953c103SMarco Felsch default: 1591e953c103SMarco Felsch return -EINVAL; 1592e953c103SMarco Felsch } 1593e953c103SMarco Felsch } 1594e953c103SMarco Felsch 1595cb7a01acSMauro Carvalho Chehab static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) 1596cb7a01acSMauro Carvalho Chehab { 1597cb7a01acSMauro Carvalho Chehab int status = tvp5150_read(sd, 0x88); 1598cb7a01acSMauro Carvalho Chehab 1599cb7a01acSMauro Carvalho Chehab vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0; 1600cb7a01acSMauro Carvalho Chehab return 0; 1601cb7a01acSMauro Carvalho Chehab } 1602cb7a01acSMauro Carvalho Chehab 16030556f1d5SMarco Felsch static int tvp5150_registered(struct v4l2_subdev *sd) 16040556f1d5SMarco Felsch { 16050556f1d5SMarco Felsch #if defined(CONFIG_MEDIA_CONTROLLER) 16060556f1d5SMarco Felsch struct tvp5150 *decoder = to_tvp5150(sd); 16070556f1d5SMarco Felsch unsigned int i; 16080556f1d5SMarco Felsch int ret; 16090556f1d5SMarco Felsch 16100556f1d5SMarco Felsch /* 16110556f1d5SMarco Felsch * Setup connector pads and links. Enable the link to the first 16120556f1d5SMarco Felsch * available connector per default. 16130556f1d5SMarco Felsch */ 16140556f1d5SMarco Felsch for (i = 0; i < decoder->connectors_num; i++) { 16150556f1d5SMarco Felsch struct media_entity *con = &decoder->connectors[i].ent; 16160556f1d5SMarco Felsch struct media_pad *pad = &decoder->connectors[i].pad; 16170556f1d5SMarco Felsch struct v4l2_fwnode_connector *v4l2c = 16180556f1d5SMarco Felsch &decoder->connectors[i].base; 16190556f1d5SMarco Felsch struct v4l2_connector_link *link = 16200556f1d5SMarco Felsch v4l2_connector_first_link(v4l2c); 16210556f1d5SMarco Felsch unsigned int port = link->fwnode_link.remote_port; 16220556f1d5SMarco Felsch unsigned int flags = i ? 0 : MEDIA_LNK_FL_ENABLED; 16230556f1d5SMarco Felsch bool is_svideo = v4l2c->type == V4L2_CONN_SVIDEO; 16240556f1d5SMarco Felsch 16250556f1d5SMarco Felsch pad->flags = MEDIA_PAD_FL_SOURCE; 16260556f1d5SMarco Felsch ret = media_entity_pads_init(con, 1, pad); 16270556f1d5SMarco Felsch if (ret < 0) 16280556f1d5SMarco Felsch goto err; 16290556f1d5SMarco Felsch 16300556f1d5SMarco Felsch ret = media_device_register_entity(sd->v4l2_dev->mdev, con); 16310556f1d5SMarco Felsch if (ret < 0) 16320556f1d5SMarco Felsch goto err; 16330556f1d5SMarco Felsch 16340556f1d5SMarco Felsch ret = media_create_pad_link(con, 0, &sd->entity, port, flags); 16350556f1d5SMarco Felsch if (ret < 0) 16360556f1d5SMarco Felsch goto err; 16370556f1d5SMarco Felsch 16380556f1d5SMarco Felsch if (is_svideo) { 16390556f1d5SMarco Felsch /* 16400556f1d5SMarco Felsch * Check tvp5150_link_setup() comments for more 16410556f1d5SMarco Felsch * information. 16420556f1d5SMarco Felsch */ 16430556f1d5SMarco Felsch link = v4l2_connector_last_link(v4l2c); 16440556f1d5SMarco Felsch port = link->fwnode_link.remote_port; 16450556f1d5SMarco Felsch ret = media_create_pad_link(con, 0, &sd->entity, port, 16460556f1d5SMarco Felsch flags); 16470556f1d5SMarco Felsch if (ret < 0) 16480556f1d5SMarco Felsch goto err; 16490556f1d5SMarco Felsch } 16500556f1d5SMarco Felsch 16510556f1d5SMarco Felsch /* Enable default input. */ 16520556f1d5SMarco Felsch if (flags == MEDIA_LNK_FL_ENABLED) { 16530556f1d5SMarco Felsch decoder->input = 16540556f1d5SMarco Felsch is_svideo ? TVP5150_SVIDEO : 16550556f1d5SMarco Felsch port == 0 ? TVP5150_COMPOSITE0 : 16560556f1d5SMarco Felsch TVP5150_COMPOSITE1; 16570556f1d5SMarco Felsch 16580556f1d5SMarco Felsch tvp5150_selmux(sd); 1659baf17821SMarco Felsch decoder->cur_connector = &decoder->connectors[i]; 1660baf17821SMarco Felsch tvp5150_s_std(sd, v4l2c->connector.analog.sdtv_stds); 16610556f1d5SMarco Felsch } 16620556f1d5SMarco Felsch } 16630556f1d5SMarco Felsch 16640556f1d5SMarco Felsch return 0; 16650556f1d5SMarco Felsch 16660556f1d5SMarco Felsch err: 1667d000e9b5SChuhong Yuan for (i = 0; i < decoder->connectors_num; i++) { 16680556f1d5SMarco Felsch media_device_unregister_entity(&decoder->connectors[i].ent); 1669d000e9b5SChuhong Yuan media_entity_cleanup(&decoder->connectors[i].ent); 1670d000e9b5SChuhong Yuan } 16710556f1d5SMarco Felsch return ret; 16720556f1d5SMarco Felsch #endif 16730556f1d5SMarco Felsch 16740556f1d5SMarco Felsch return 0; 16750556f1d5SMarco Felsch } 16760556f1d5SMarco Felsch 16779c8e5098SMarco Felsch static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 16789c8e5098SMarco Felsch { 16799c8e5098SMarco Felsch int ret; 16809c8e5098SMarco Felsch 16819c8e5098SMarco Felsch ret = pm_runtime_get_sync(sd->dev); 16829c8e5098SMarco Felsch if (ret < 0) { 16839c8e5098SMarco Felsch pm_runtime_put_noidle(sd->dev); 16849c8e5098SMarco Felsch return ret; 16859c8e5098SMarco Felsch } 16869c8e5098SMarco Felsch 16879c8e5098SMarco Felsch return 0; 16889c8e5098SMarco Felsch } 16899c8e5098SMarco Felsch 16909c8e5098SMarco Felsch static int tvp5150_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 16919c8e5098SMarco Felsch { 16929c8e5098SMarco Felsch pm_runtime_put(sd->dev); 16939c8e5098SMarco Felsch 16949c8e5098SMarco Felsch return 0; 16959c8e5098SMarco Felsch } 16969c8e5098SMarco Felsch 1697cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1698cb7a01acSMauro Carvalho Chehab 1699cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { 1700cb7a01acSMauro Carvalho Chehab .s_ctrl = tvp5150_s_ctrl, 1701cb7a01acSMauro Carvalho Chehab }; 1702cb7a01acSMauro Carvalho Chehab 1703cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tvp5150_core_ops = { 1704cb7a01acSMauro Carvalho Chehab .log_status = tvp5150_log_status, 1705cb7a01acSMauro Carvalho Chehab .reset = tvp5150_reset, 1706cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1707cb7a01acSMauro Carvalho Chehab .g_register = tvp5150_g_register, 1708cb7a01acSMauro Carvalho Chehab .s_register = tvp5150_s_register, 1709cb7a01acSMauro Carvalho Chehab #endif 1710e953c103SMarco Felsch .subscribe_event = tvp5150_subscribe_event, 1711e953c103SMarco Felsch .unsubscribe_event = v4l2_event_subdev_unsubscribe, 1712cb7a01acSMauro Carvalho Chehab }; 1713cb7a01acSMauro Carvalho Chehab 1714cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { 1715cb7a01acSMauro Carvalho Chehab .g_tuner = tvp5150_g_tuner, 1716cb7a01acSMauro Carvalho Chehab }; 1717cb7a01acSMauro Carvalho Chehab 1718cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tvp5150_video_ops = { 17198774bed9SLaurent Pinchart .s_std = tvp5150_s_std, 17200db87cc7SMarco Felsch .g_std = tvp5150_g_std, 1721ee9a6ff6SPhilipp Zabel .querystd = tvp5150_querystd, 1722460b6c08SLaurent Pinchart .s_stream = tvp5150_s_stream, 1723cb7a01acSMauro Carvalho Chehab .s_routing = tvp5150_s_routing, 1724dd3a46bbSLaurent Pinchart .g_mbus_config = tvp5150_g_mbus_config, 1725cb7a01acSMauro Carvalho Chehab }; 1726cb7a01acSMauro Carvalho Chehab 1727cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { 1728cb7a01acSMauro Carvalho Chehab .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap, 1729cb7a01acSMauro Carvalho Chehab .g_sliced_fmt = tvp5150_g_sliced_fmt, 1730cb7a01acSMauro Carvalho Chehab .s_sliced_fmt = tvp5150_s_sliced_fmt, 1731cb7a01acSMauro Carvalho Chehab .s_raw_fmt = tvp5150_s_raw_fmt, 1732cb7a01acSMauro Carvalho Chehab }; 1733cb7a01acSMauro Carvalho Chehab 1734ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { 1735b440b733SPhilipp Zabel .init_cfg = tvp5150_init_cfg, 1736ebcff5fcSHans Verkuil .enum_mbus_code = tvp5150_enum_mbus_code, 1737e545ac87SLaurent Pinchart .enum_frame_size = tvp5150_enum_frame_size, 1738da298c6dSHans Verkuil .set_fmt = tvp5150_fill_fmt, 1739da298c6dSHans Verkuil .get_fmt = tvp5150_fill_fmt, 174010d5509cSHans Verkuil .get_selection = tvp5150_get_selection, 174110d5509cSHans Verkuil .set_selection = tvp5150_set_selection, 1742ebcff5fcSHans Verkuil }; 1743ebcff5fcSHans Verkuil 1744cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvp5150_ops = { 1745cb7a01acSMauro Carvalho Chehab .core = &tvp5150_core_ops, 1746cb7a01acSMauro Carvalho Chehab .tuner = &tvp5150_tuner_ops, 1747cb7a01acSMauro Carvalho Chehab .video = &tvp5150_video_ops, 1748cb7a01acSMauro Carvalho Chehab .vbi = &tvp5150_vbi_ops, 1749ebcff5fcSHans Verkuil .pad = &tvp5150_pad_ops, 1750cb7a01acSMauro Carvalho Chehab }; 1751cb7a01acSMauro Carvalho Chehab 17520556f1d5SMarco Felsch static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = { 17530556f1d5SMarco Felsch .registered = tvp5150_registered, 17549c8e5098SMarco Felsch .open = tvp5150_open, 17559c8e5098SMarco Felsch .close = tvp5150_close, 17560556f1d5SMarco Felsch }; 17570556f1d5SMarco Felsch 1758cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1759cb7a01acSMauro Carvalho Chehab I2C Client & Driver 1760cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1761cb7a01acSMauro Carvalho Chehab 176228b9e227SPhilipp Zabel static const struct regmap_range tvp5150_readable_ranges[] = { 176328b9e227SPhilipp Zabel { 176428b9e227SPhilipp Zabel .range_min = TVP5150_VD_IN_SRC_SEL_1, 176528b9e227SPhilipp Zabel .range_max = TVP5150_AUTOSW_MSK, 176628b9e227SPhilipp Zabel }, { 176728b9e227SPhilipp Zabel .range_min = TVP5150_COLOR_KIL_THSH_CTL, 176828b9e227SPhilipp Zabel .range_max = TVP5150_CONF_SHARED_PIN, 176928b9e227SPhilipp Zabel }, { 177028b9e227SPhilipp Zabel .range_min = TVP5150_ACT_VD_CROP_ST_MSB, 177128b9e227SPhilipp Zabel .range_max = TVP5150_HORIZ_SYNC_START, 177228b9e227SPhilipp Zabel }, { 177328b9e227SPhilipp Zabel .range_min = TVP5150_VERT_BLANKING_START, 177428b9e227SPhilipp Zabel .range_max = TVP5150_INTT_CONFIG_REG_B, 177528b9e227SPhilipp Zabel }, { 177628b9e227SPhilipp Zabel .range_min = TVP5150_VIDEO_STD, 177728b9e227SPhilipp Zabel .range_max = TVP5150_VIDEO_STD, 177828b9e227SPhilipp Zabel }, { 177928b9e227SPhilipp Zabel .range_min = TVP5150_CB_GAIN_FACT, 178028b9e227SPhilipp Zabel .range_max = TVP5150_REV_SELECT, 178128b9e227SPhilipp Zabel }, { 178228b9e227SPhilipp Zabel .range_min = TVP5150_MSB_DEV_ID, 178328b9e227SPhilipp Zabel .range_max = TVP5150_STATUS_REG_5, 178428b9e227SPhilipp Zabel }, { 178528b9e227SPhilipp Zabel .range_min = TVP5150_CC_DATA_INI, 178628b9e227SPhilipp Zabel .range_max = TVP5150_TELETEXT_FIL_ENA, 178728b9e227SPhilipp Zabel }, { 178828b9e227SPhilipp Zabel .range_min = TVP5150_INT_STATUS_REG_A, 178928b9e227SPhilipp Zabel .range_max = TVP5150_FIFO_OUT_CTRL, 179028b9e227SPhilipp Zabel }, { 179128b9e227SPhilipp Zabel .range_min = TVP5150_FULL_FIELD_ENA, 179228b9e227SPhilipp Zabel .range_max = TVP5150_FULL_FIELD_MODE_REG, 179328b9e227SPhilipp Zabel }, 179428b9e227SPhilipp Zabel }; 179528b9e227SPhilipp Zabel 1796c135e997SMauro Carvalho Chehab static bool tvp5150_volatile_reg(struct device *dev, unsigned int reg) 179728b9e227SPhilipp Zabel { 179828b9e227SPhilipp Zabel switch (reg) { 179928b9e227SPhilipp Zabel case TVP5150_VERT_LN_COUNT_MSB: 180028b9e227SPhilipp Zabel case TVP5150_VERT_LN_COUNT_LSB: 180128b9e227SPhilipp Zabel case TVP5150_INT_STATUS_REG_A: 180228b9e227SPhilipp Zabel case TVP5150_INT_STATUS_REG_B: 180328b9e227SPhilipp Zabel case TVP5150_INT_ACTIVE_REG_B: 180428b9e227SPhilipp Zabel case TVP5150_STATUS_REG_1: 180528b9e227SPhilipp Zabel case TVP5150_STATUS_REG_2: 180628b9e227SPhilipp Zabel case TVP5150_STATUS_REG_3: 180728b9e227SPhilipp Zabel case TVP5150_STATUS_REG_4: 180828b9e227SPhilipp Zabel case TVP5150_STATUS_REG_5: 180928b9e227SPhilipp Zabel /* CC, WSS, VPS, VITC data? */ 181028b9e227SPhilipp Zabel case TVP5150_VBI_FIFO_READ_DATA: 181128b9e227SPhilipp Zabel case TVP5150_VDP_STATUS_REG: 181228b9e227SPhilipp Zabel case TVP5150_FIFO_WORD_COUNT: 181328b9e227SPhilipp Zabel return true; 181428b9e227SPhilipp Zabel default: 181528b9e227SPhilipp Zabel return false; 181628b9e227SPhilipp Zabel } 181728b9e227SPhilipp Zabel } 181828b9e227SPhilipp Zabel 181928b9e227SPhilipp Zabel static const struct regmap_access_table tvp5150_readable_table = { 182028b9e227SPhilipp Zabel .yes_ranges = tvp5150_readable_ranges, 182128b9e227SPhilipp Zabel .n_yes_ranges = ARRAY_SIZE(tvp5150_readable_ranges), 182228b9e227SPhilipp Zabel }; 182328b9e227SPhilipp Zabel 182428b9e227SPhilipp Zabel static struct regmap_config tvp5150_config = { 182528b9e227SPhilipp Zabel .reg_bits = 8, 182628b9e227SPhilipp Zabel .val_bits = 8, 182728b9e227SPhilipp Zabel .max_register = 0xff, 182828b9e227SPhilipp Zabel 182928b9e227SPhilipp Zabel .cache_type = REGCACHE_RBTREE, 183028b9e227SPhilipp Zabel 183128b9e227SPhilipp Zabel .rd_table = &tvp5150_readable_table, 183228b9e227SPhilipp Zabel .volatile_reg = tvp5150_volatile_reg, 183328b9e227SPhilipp Zabel }; 183428b9e227SPhilipp Zabel 18357871597aSLaurent Pinchart static int tvp5150_detect_version(struct tvp5150 *core) 18367871597aSLaurent Pinchart { 18377871597aSLaurent Pinchart struct v4l2_subdev *sd = &core->sd; 18387871597aSLaurent Pinchart struct i2c_client *c = v4l2_get_subdevdata(sd); 18397871597aSLaurent Pinchart u8 regs[4]; 18407871597aSLaurent Pinchart int res; 18417871597aSLaurent Pinchart 18427871597aSLaurent Pinchart /* 18437871597aSLaurent Pinchart * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID, 18447871597aSLaurent Pinchart * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 18457871597aSLaurent Pinchart */ 184628b9e227SPhilipp Zabel res = regmap_bulk_read(core->regmap, TVP5150_MSB_DEV_ID, regs, 4); 184728b9e227SPhilipp Zabel if (res < 0) { 184828b9e227SPhilipp Zabel dev_err(&c->dev, "reading ID registers failed: %d\n", res); 18497871597aSLaurent Pinchart return res; 18507871597aSLaurent Pinchart } 18517871597aSLaurent Pinchart 185282275133SJavier Martinez Canillas core->dev_id = (regs[0] << 8) | regs[1]; 185382275133SJavier Martinez Canillas core->rom_ver = (regs[2] << 8) | regs[3]; 18547871597aSLaurent Pinchart 1855257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n", 185682275133SJavier Martinez Canillas core->dev_id, regs[2], regs[3], c->addr << 1, 185782275133SJavier Martinez Canillas c->adapter->name); 18587871597aSLaurent Pinchart 185982275133SJavier Martinez Canillas if (core->dev_id == 0x5150 && core->rom_ver == 0x0321) { 1860257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5150a detected.\n"); 186182275133SJavier Martinez Canillas } else if (core->dev_id == 0x5150 && core->rom_ver == 0x0400) { 1862257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5150am1 detected.\n"); 18637871597aSLaurent Pinchart 18647871597aSLaurent Pinchart /* ITU-T BT.656.4 timing */ 186528b9e227SPhilipp Zabel regmap_write(core->regmap, TVP5150_REV_SELECT, 0); 186682275133SJavier Martinez Canillas } else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) { 1867257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5151 detected.\n"); 18687871597aSLaurent Pinchart } else { 1869257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "*** unknown tvp%04x chip detected.\n", 187082275133SJavier Martinez Canillas core->dev_id); 18717871597aSLaurent Pinchart } 18727871597aSLaurent Pinchart 18737871597aSLaurent Pinchart return 0; 18747871597aSLaurent Pinchart } 18757871597aSLaurent Pinchart 187609aa2609SJavier Martinez Canillas static int tvp5150_init(struct i2c_client *c) 187709aa2609SJavier Martinez Canillas { 187809aa2609SJavier Martinez Canillas struct gpio_desc *pdn_gpio; 187909aa2609SJavier Martinez Canillas struct gpio_desc *reset_gpio; 188009aa2609SJavier Martinez Canillas 188109aa2609SJavier Martinez Canillas pdn_gpio = devm_gpiod_get_optional(&c->dev, "pdn", GPIOD_OUT_HIGH); 188209aa2609SJavier Martinez Canillas if (IS_ERR(pdn_gpio)) 188309aa2609SJavier Martinez Canillas return PTR_ERR(pdn_gpio); 188409aa2609SJavier Martinez Canillas 188509aa2609SJavier Martinez Canillas if (pdn_gpio) { 188609aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(pdn_gpio, 0); 188709aa2609SJavier Martinez Canillas /* Delay time between power supplies active and reset */ 188809aa2609SJavier Martinez Canillas msleep(20); 188909aa2609SJavier Martinez Canillas } 189009aa2609SJavier Martinez Canillas 189109aa2609SJavier Martinez Canillas reset_gpio = devm_gpiod_get_optional(&c->dev, "reset", GPIOD_OUT_HIGH); 189209aa2609SJavier Martinez Canillas if (IS_ERR(reset_gpio)) 189309aa2609SJavier Martinez Canillas return PTR_ERR(reset_gpio); 189409aa2609SJavier Martinez Canillas 189509aa2609SJavier Martinez Canillas if (reset_gpio) { 189609aa2609SJavier Martinez Canillas /* RESETB pulse duration */ 189709aa2609SJavier Martinez Canillas ndelay(500); 189809aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(reset_gpio, 0); 189909aa2609SJavier Martinez Canillas /* Delay time between end of reset to I2C active */ 190009aa2609SJavier Martinez Canillas usleep_range(200, 250); 190109aa2609SJavier Martinez Canillas } 190209aa2609SJavier Martinez Canillas 190309aa2609SJavier Martinez Canillas return 0; 190409aa2609SJavier Martinez Canillas } 190509aa2609SJavier Martinez Canillas 19060556f1d5SMarco Felsch #if defined(CONFIG_MEDIA_CONTROLLER) 19070556f1d5SMarco Felsch static int tvp5150_mc_init(struct tvp5150 *decoder) 19080556f1d5SMarco Felsch { 19090556f1d5SMarco Felsch struct v4l2_subdev *sd = &decoder->sd; 19100556f1d5SMarco Felsch unsigned int i; 19110556f1d5SMarco Felsch 19120556f1d5SMarco Felsch sd->entity.ops = &tvp5150_sd_media_ops; 19130556f1d5SMarco Felsch sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 19140556f1d5SMarco Felsch 19150556f1d5SMarco Felsch for (i = 0; i < TVP5150_NUM_PADS - 1; i++) { 19160556f1d5SMarco Felsch decoder->pads[i].flags = MEDIA_PAD_FL_SINK; 19170556f1d5SMarco Felsch decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG; 19180556f1d5SMarco Felsch } 19190556f1d5SMarco Felsch 19200556f1d5SMarco Felsch decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE; 19210556f1d5SMarco Felsch decoder->pads[i].sig_type = PAD_SIGNAL_DV; 19220556f1d5SMarco Felsch 19230556f1d5SMarco Felsch return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, 19240556f1d5SMarco Felsch decoder->pads); 19250556f1d5SMarco Felsch } 19260556f1d5SMarco Felsch 19270556f1d5SMarco Felsch #else /* !defined(CONFIG_MEDIA_CONTROLLER) */ 19280556f1d5SMarco Felsch 19290556f1d5SMarco Felsch static inline int tvp5150_mc_init(struct tvp5150 *decoder) 19300556f1d5SMarco Felsch { 19310556f1d5SMarco Felsch return 0; 19320556f1d5SMarco Felsch } 19330556f1d5SMarco Felsch #endif /* defined(CONFIG_MEDIA_CONTROLLER) */ 19340556f1d5SMarco Felsch 19350556f1d5SMarco Felsch static int tvp5150_validate_connectors(struct tvp5150 *decoder) 19360556f1d5SMarco Felsch { 19370556f1d5SMarco Felsch struct device *dev = decoder->sd.dev; 19380556f1d5SMarco Felsch struct tvp5150_connector *tvpc; 19390556f1d5SMarco Felsch struct v4l2_fwnode_connector *v4l2c; 19400556f1d5SMarco Felsch unsigned int i; 19410556f1d5SMarco Felsch 19420556f1d5SMarco Felsch if (!decoder->connectors_num) { 19430556f1d5SMarco Felsch dev_err(dev, "No valid connector found\n"); 19440556f1d5SMarco Felsch return -ENODEV; 19450556f1d5SMarco Felsch } 19460556f1d5SMarco Felsch 19470556f1d5SMarco Felsch for (i = 0; i < decoder->connectors_num; i++) { 19480556f1d5SMarco Felsch struct v4l2_connector_link *link0 = NULL; 19490556f1d5SMarco Felsch struct v4l2_connector_link *link1; 19500556f1d5SMarco Felsch 19510556f1d5SMarco Felsch tvpc = &decoder->connectors[i]; 19520556f1d5SMarco Felsch v4l2c = &tvpc->base; 19530556f1d5SMarco Felsch 19540556f1d5SMarco Felsch if (v4l2c->type == V4L2_CONN_COMPOSITE) { 19550556f1d5SMarco Felsch if (v4l2c->nr_of_links != 1) { 19560556f1d5SMarco Felsch dev_err(dev, "Composite: connector needs 1 link\n"); 19570556f1d5SMarco Felsch return -EINVAL; 19580556f1d5SMarco Felsch } 19590556f1d5SMarco Felsch link0 = v4l2_connector_first_link(v4l2c); 19600556f1d5SMarco Felsch if (!link0) { 19610556f1d5SMarco Felsch dev_err(dev, "Composite: invalid first link\n"); 19620556f1d5SMarco Felsch return -EINVAL; 19630556f1d5SMarco Felsch } 19640556f1d5SMarco Felsch if (link0->fwnode_link.remote_id == 1) { 19650556f1d5SMarco Felsch dev_err(dev, "Composite: invalid endpoint id\n"); 19660556f1d5SMarco Felsch return -EINVAL; 19670556f1d5SMarco Felsch } 19680556f1d5SMarco Felsch } 19690556f1d5SMarco Felsch 19700556f1d5SMarco Felsch if (v4l2c->type == V4L2_CONN_SVIDEO) { 19710556f1d5SMarco Felsch if (v4l2c->nr_of_links != 2) { 19720556f1d5SMarco Felsch dev_err(dev, "SVideo: connector needs 2 links\n"); 19730556f1d5SMarco Felsch return -EINVAL; 19740556f1d5SMarco Felsch } 19750556f1d5SMarco Felsch link0 = v4l2_connector_first_link(v4l2c); 19760556f1d5SMarco Felsch if (!link0) { 19770556f1d5SMarco Felsch dev_err(dev, "SVideo: invalid first link\n"); 19780556f1d5SMarco Felsch return -EINVAL; 19790556f1d5SMarco Felsch } 19800556f1d5SMarco Felsch link1 = v4l2_connector_last_link(v4l2c); 19810556f1d5SMarco Felsch if (link0->fwnode_link.remote_port == 19820556f1d5SMarco Felsch link1->fwnode_link.remote_port) { 19830556f1d5SMarco Felsch dev_err(dev, "SVideo: invalid link setup\n"); 19840556f1d5SMarco Felsch return -EINVAL; 19850556f1d5SMarco Felsch } 19860556f1d5SMarco Felsch } 1987baf17821SMarco Felsch 1988baf17821SMarco Felsch if (!(v4l2c->connector.analog.sdtv_stds & TVP5150_STD_MASK)) { 1989baf17821SMarco Felsch dev_err(dev, "Unsupported tv-norm on connector %s\n", 1990baf17821SMarco Felsch v4l2c->name); 1991baf17821SMarco Felsch return -EINVAL; 1992baf17821SMarco Felsch } 19930556f1d5SMarco Felsch } 19940556f1d5SMarco Felsch 19950556f1d5SMarco Felsch return 0; 19960556f1d5SMarco Felsch } 19970556f1d5SMarco Felsch 1998a2e5f1b3SJavier Martinez Canillas static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) 1999a2e5f1b3SJavier Martinez Canillas { 20000556f1d5SMarco Felsch struct device *dev = decoder->sd.dev; 20010556f1d5SMarco Felsch struct v4l2_fwnode_endpoint bus_cfg = { 20020556f1d5SMarco Felsch .bus_type = V4L2_MBUS_UNKNOWN 20030556f1d5SMarco Felsch }; 20040556f1d5SMarco Felsch struct device_node *ep_np; 20050556f1d5SMarco Felsch struct tvp5150_connector *tvpc; 20060556f1d5SMarco Felsch struct v4l2_fwnode_connector *v4l2c; 20070556f1d5SMarco Felsch unsigned int flags, ep_num; 20080556f1d5SMarco Felsch unsigned int i; 20090556f1d5SMarco Felsch int ret; 2010a2e5f1b3SJavier Martinez Canillas 20110556f1d5SMarco Felsch /* At least 1 output and 1 input */ 20120556f1d5SMarco Felsch ep_num = of_graph_get_endpoint_count(np); 20130556f1d5SMarco Felsch if (ep_num < 2 || ep_num > 5) { 20140556f1d5SMarco Felsch dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n"); 2015a2e5f1b3SJavier Martinez Canillas return -EINVAL; 20160556f1d5SMarco Felsch } 2017a2e5f1b3SJavier Martinez Canillas 20180556f1d5SMarco Felsch /* Layout if all connectors are used: 20190556f1d5SMarco Felsch * 20200556f1d5SMarco Felsch * tvp-5150 port@0 (AIP1A) 20210556f1d5SMarco Felsch * endpoint@0 -----------> Comp0-Con port 20220556f1d5SMarco Felsch * endpoint@1 --------+--> Svideo-Con port 20230556f1d5SMarco Felsch * tvp-5150 port@1 (AIP1B) | 20240556f1d5SMarco Felsch * endpoint@1 --------+ 20250556f1d5SMarco Felsch * endpoint@0 -----------> Comp1-Con port 20260556f1d5SMarco Felsch * tvp-5150 port@2 20270556f1d5SMarco Felsch * endpoint (video bitstream output at YOUT[0-7] parallel bus) 20280556f1d5SMarco Felsch */ 20290556f1d5SMarco Felsch for_each_endpoint_of_node(np, ep_np) { 20300556f1d5SMarco Felsch struct fwnode_handle *ep_fwnode = of_fwnode_handle(ep_np); 20310556f1d5SMarco Felsch unsigned int next_connector = decoder->connectors_num; 20320556f1d5SMarco Felsch struct of_endpoint ep; 20330556f1d5SMarco Felsch 20340556f1d5SMarco Felsch of_graph_parse_endpoint(ep_np, &ep); 20350556f1d5SMarco Felsch if (ep.port > 1 || ep.id > 1) { 20360556f1d5SMarco Felsch dev_dbg(dev, "Ignore connector on port@%u/ep@%u\n", 20370556f1d5SMarco Felsch ep.port, ep.id); 20380556f1d5SMarco Felsch continue; 20390556f1d5SMarco Felsch } 20400556f1d5SMarco Felsch 20410556f1d5SMarco Felsch tvpc = &decoder->connectors[next_connector]; 20420556f1d5SMarco Felsch v4l2c = &tvpc->base; 20430556f1d5SMarco Felsch 20440556f1d5SMarco Felsch if (ep.port == 0 || (ep.port == 1 && ep.id == 0)) { 20450556f1d5SMarco Felsch ret = v4l2_fwnode_connector_parse(ep_fwnode, v4l2c); 2046a2e5f1b3SJavier Martinez Canillas if (ret) 20470556f1d5SMarco Felsch goto err_put; 20480556f1d5SMarco Felsch ret = v4l2_fwnode_connector_add_link(ep_fwnode, v4l2c); 20490556f1d5SMarco Felsch if (ret) 20500556f1d5SMarco Felsch goto err_put; 20510556f1d5SMarco Felsch decoder->connectors_num++; 20520556f1d5SMarco Felsch } else { 20530556f1d5SMarco Felsch /* Adding the 2nd svideo link */ 20540556f1d5SMarco Felsch for (i = 0; i < TVP5150_MAX_CONNECTORS; i++) { 20550556f1d5SMarco Felsch tvpc = &decoder->connectors[i]; 20560556f1d5SMarco Felsch v4l2c = &tvpc->base; 20570556f1d5SMarco Felsch if (v4l2c->type == V4L2_CONN_SVIDEO) 20580556f1d5SMarco Felsch break; 20590556f1d5SMarco Felsch } 20600556f1d5SMarco Felsch 20610556f1d5SMarco Felsch ret = v4l2_fwnode_connector_add_link(ep_fwnode, v4l2c); 20620556f1d5SMarco Felsch if (ret) 20630556f1d5SMarco Felsch goto err_put; 20640556f1d5SMarco Felsch } 20650556f1d5SMarco Felsch } 20660556f1d5SMarco Felsch 20670556f1d5SMarco Felsch ret = tvp5150_validate_connectors(decoder); 20680556f1d5SMarco Felsch if (ret) 20690556f1d5SMarco Felsch goto err_free; 20700556f1d5SMarco Felsch 20710556f1d5SMarco Felsch for (i = 0; i < decoder->connectors_num; i++) { 20720556f1d5SMarco Felsch tvpc = &decoder->connectors[i]; 20730556f1d5SMarco Felsch v4l2c = &tvpc->base; 20740556f1d5SMarco Felsch tvpc->ent.flags = MEDIA_ENT_FL_CONNECTOR; 20750556f1d5SMarco Felsch tvpc->ent.function = v4l2c->type == V4L2_CONN_SVIDEO ? 20760556f1d5SMarco Felsch MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE; 20770556f1d5SMarco Felsch tvpc->ent.name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", 20780556f1d5SMarco Felsch v4l2c->name, v4l2c->label ? 20790556f1d5SMarco Felsch v4l2c->label : ""); 20800556f1d5SMarco Felsch } 20810556f1d5SMarco Felsch 20820556f1d5SMarco Felsch ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0); 20830556f1d5SMarco Felsch if (!ep_np) { 20840556f1d5SMarco Felsch dev_err(dev, "Error no output endpoint available\n"); 20850556f1d5SMarco Felsch goto err_free; 20860556f1d5SMarco Felsch } 20870556f1d5SMarco Felsch ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np), &bus_cfg); 20880556f1d5SMarco Felsch of_node_put(ep_np); 20890556f1d5SMarco Felsch if (ret) 20900556f1d5SMarco Felsch goto err_free; 2091a2e5f1b3SJavier Martinez Canillas 2092a2e5f1b3SJavier Martinez Canillas flags = bus_cfg.bus.parallel.flags; 2093a2e5f1b3SJavier Martinez Canillas if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL && 2094a2e5f1b3SJavier Martinez Canillas !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH && 2095a2e5f1b3SJavier Martinez Canillas flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH && 20962bd5e437SJavier Martinez Canillas flags & V4L2_MBUS_FIELD_EVEN_LOW)) { 20972bd5e437SJavier Martinez Canillas ret = -EINVAL; 20980556f1d5SMarco Felsch goto err_free; 20992bd5e437SJavier Martinez Canillas } 2100a2e5f1b3SJavier Martinez Canillas 2101a2e5f1b3SJavier Martinez Canillas decoder->mbus_type = bus_cfg.bus_type; 2102a2e5f1b3SJavier Martinez Canillas 21030556f1d5SMarco Felsch return 0; 21040556f1d5SMarco Felsch 21050556f1d5SMarco Felsch err_put: 21060556f1d5SMarco Felsch of_node_put(ep_np); 21070556f1d5SMarco Felsch err_free: 21080556f1d5SMarco Felsch for (i = 0; i < TVP5150_MAX_CONNECTORS; i++) 21090556f1d5SMarco Felsch v4l2_fwnode_connector_free(&decoder->connectors[i].base); 21100556f1d5SMarco Felsch 2111a2e5f1b3SJavier Martinez Canillas return ret; 2112a2e5f1b3SJavier Martinez Canillas } 2113a2e5f1b3SJavier Martinez Canillas 2114c43875f6SMauro Carvalho Chehab static const char * const tvp5150_test_patterns[2] = { 2115c43875f6SMauro Carvalho Chehab "Disabled", 2116c43875f6SMauro Carvalho Chehab "Black screen" 2117c43875f6SMauro Carvalho Chehab }; 2118c43875f6SMauro Carvalho Chehab 2119e6714993SKieran Bingham static int tvp5150_probe(struct i2c_client *c) 2120cb7a01acSMauro Carvalho Chehab { 2121cb7a01acSMauro Carvalho Chehab struct tvp5150 *core; 2122cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 2123a2e5f1b3SJavier Martinez Canillas struct device_node *np = c->dev.of_node; 212428b9e227SPhilipp Zabel struct regmap *map; 2125baf17821SMarco Felsch unsigned int i; 21267871597aSLaurent Pinchart int res; 2127cb7a01acSMauro Carvalho Chehab 2128cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 2129cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(c->adapter, 2130cb7a01acSMauro Carvalho Chehab I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 2131cb7a01acSMauro Carvalho Chehab return -EIO; 2132cb7a01acSMauro Carvalho Chehab 213309aa2609SJavier Martinez Canillas res = tvp5150_init(c); 213409aa2609SJavier Martinez Canillas if (res) 213509aa2609SJavier Martinez Canillas return res; 213609aa2609SJavier Martinez Canillas 2137c02b211dSLaurent Pinchart core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL); 2138c02b211dSLaurent Pinchart if (!core) 2139cb7a01acSMauro Carvalho Chehab return -ENOMEM; 2140a2e5f1b3SJavier Martinez Canillas 214128b9e227SPhilipp Zabel map = devm_regmap_init_i2c(c, &tvp5150_config); 214228b9e227SPhilipp Zabel if (IS_ERR(map)) 214328b9e227SPhilipp Zabel return PTR_ERR(map); 214428b9e227SPhilipp Zabel 214528b9e227SPhilipp Zabel core->regmap = map; 2146cb7a01acSMauro Carvalho Chehab sd = &core->sd; 214796ca7c41SMichael Tretter v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); 214896ca7c41SMichael Tretter sd->internal_ops = &tvp5150_internal_ops; 2149e953c103SMarco Felsch sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 2150a2e5f1b3SJavier Martinez Canillas 2151a2e5f1b3SJavier Martinez Canillas if (IS_ENABLED(CONFIG_OF) && np) { 2152a2e5f1b3SJavier Martinez Canillas res = tvp5150_parse_dt(core, np); 2153a2e5f1b3SJavier Martinez Canillas if (res) { 2154257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "DT parsing error: %d\n", res); 2155a2e5f1b3SJavier Martinez Canillas return res; 2156a2e5f1b3SJavier Martinez Canillas } 2157a2e5f1b3SJavier Martinez Canillas } else { 2158a2e5f1b3SJavier Martinez Canillas /* Default to BT.656 embedded sync */ 2159a2e5f1b3SJavier Martinez Canillas core->mbus_type = V4L2_MBUS_BT656; 2160a2e5f1b3SJavier Martinez Canillas } 2161a2e5f1b3SJavier Martinez Canillas 21620556f1d5SMarco Felsch res = tvp5150_mc_init(core); 21630556f1d5SMarco Felsch if (res) 2164e545ac87SLaurent Pinchart return res; 2165f7b4b54eSJavier Martinez Canillas 21667871597aSLaurent Pinchart res = tvp5150_detect_version(core); 2167cb7a01acSMauro Carvalho Chehab if (res < 0) 2168c02b211dSLaurent Pinchart return res; 2169cb7a01acSMauro Carvalho Chehab 2170baf17821SMarco Felsch /* 2171baf17821SMarco Felsch * Iterate over all available connectors in case they are supported and 2172baf17821SMarco Felsch * successfully parsed. Fallback to default autodetect in case they 2173baf17821SMarco Felsch * aren't supported. 2174baf17821SMarco Felsch */ 2175baf17821SMarco Felsch for (i = 0; i < core->connectors_num; i++) { 2176baf17821SMarco Felsch struct v4l2_fwnode_connector *v4l2c; 2177baf17821SMarco Felsch 2178baf17821SMarco Felsch v4l2c = &core->connectors[i].base; 2179baf17821SMarco Felsch core->norm |= v4l2c->connector.analog.sdtv_stds; 2180baf17821SMarco Felsch } 2181baf17821SMarco Felsch 2182baf17821SMarco Felsch if (!core->connectors_num) 2183baf17821SMarco Felsch core->norm = V4L2_STD_ALL; 2184baf17821SMarco Felsch 2185b440b733SPhilipp Zabel core->detected_norm = V4L2_STD_UNKNOWN; 2186cb7a01acSMauro Carvalho Chehab core->input = TVP5150_COMPOSITE1; 2187c43875f6SMauro Carvalho Chehab core->enable = true; 2188cb7a01acSMauro Carvalho Chehab 2189b1950b8dSLaurent Pinchart v4l2_ctrl_handler_init(&core->hdl, 5); 2190cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 2191cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 2192cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 2193cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 255, 1, 128); 2194cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 2195cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, 0, 255, 1, 128); 2196cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 2197cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, -128, 127, 1, 0); 2198b1950b8dSLaurent Pinchart v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 2199b1950b8dSLaurent Pinchart V4L2_CID_PIXEL_RATE, 27000000, 2200b1950b8dSLaurent Pinchart 27000000, 1, 27000000); 2201c43875f6SMauro Carvalho Chehab v4l2_ctrl_new_std_menu_items(&core->hdl, &tvp5150_ctrl_ops, 2202c43875f6SMauro Carvalho Chehab V4L2_CID_TEST_PATTERN, 22035c4c4505SMauro Carvalho Chehab ARRAY_SIZE(tvp5150_test_patterns) - 1, 2204c43875f6SMauro Carvalho Chehab 0, 0, tvp5150_test_patterns); 2205cb7a01acSMauro Carvalho Chehab sd->ctrl_handler = &core->hdl; 2206cb7a01acSMauro Carvalho Chehab if (core->hdl.error) { 2207cb7a01acSMauro Carvalho Chehab res = core->hdl.error; 2208c7d97499SJavier Martinez Canillas goto err; 2209cb7a01acSMauro Carvalho Chehab } 2210cb7a01acSMauro Carvalho Chehab 22115cb82940SMarco Felsch tvp5150_set_default(tvp5150_read_std(sd), &core->rect); 2212cb7a01acSMauro Carvalho Chehab 22138e4c97e0SPhilipp Zabel core->irq = c->irq; 2214aff808e8SLaurent Pinchart tvp5150_reset(sd, 0); /* Calls v4l2_ctrl_handler_setup() */ 22158e4c97e0SPhilipp Zabel if (c->irq) { 22168e4c97e0SPhilipp Zabel res = devm_request_threaded_irq(&c->dev, c->irq, NULL, 22178e4c97e0SPhilipp Zabel tvp5150_isr, IRQF_TRIGGER_HIGH | 22188e4c97e0SPhilipp Zabel IRQF_ONESHOT, "tvp5150", core); 22198e4c97e0SPhilipp Zabel if (res) 222081fd5fd4SMarco Felsch goto err; 22218e4c97e0SPhilipp Zabel } 2222aff808e8SLaurent Pinchart 2223c7d97499SJavier Martinez Canillas res = v4l2_async_register_subdev(sd); 2224c7d97499SJavier Martinez Canillas if (res < 0) 2225c7d97499SJavier Martinez Canillas goto err; 2226c7d97499SJavier Martinez Canillas 2227cb7a01acSMauro Carvalho Chehab if (debug > 1) 2228cb7a01acSMauro Carvalho Chehab tvp5150_log_status(sd); 222973549a69SMarco Felsch 223073549a69SMarco Felsch pm_runtime_set_active(&c->dev); 223173549a69SMarco Felsch pm_runtime_enable(&c->dev); 223273549a69SMarco Felsch pm_runtime_idle(&c->dev); 223373549a69SMarco Felsch 2234cb7a01acSMauro Carvalho Chehab return 0; 2235c7d97499SJavier Martinez Canillas 2236c7d97499SJavier Martinez Canillas err: 2237c7d97499SJavier Martinez Canillas v4l2_ctrl_handler_free(&core->hdl); 2238c7d97499SJavier Martinez Canillas return res; 2239cb7a01acSMauro Carvalho Chehab } 2240cb7a01acSMauro Carvalho Chehab 2241cb7a01acSMauro Carvalho Chehab static int tvp5150_remove(struct i2c_client *c) 2242cb7a01acSMauro Carvalho Chehab { 2243cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(c); 2244cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 22450556f1d5SMarco Felsch unsigned int i; 2246cb7a01acSMauro Carvalho Chehab 2247257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, 2248cb7a01acSMauro Carvalho Chehab "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", 2249cb7a01acSMauro Carvalho Chehab c->addr << 1); 2250cb7a01acSMauro Carvalho Chehab 22510556f1d5SMarco Felsch for (i = 0; i < decoder->connectors_num; i++) 22520556f1d5SMarco Felsch v4l2_fwnode_connector_free(&decoder->connectors[i].base); 2253d000e9b5SChuhong Yuan for (i = 0; i < decoder->connectors_num; i++) { 22540556f1d5SMarco Felsch media_device_unregister_entity(&decoder->connectors[i].ent); 2255d000e9b5SChuhong Yuan media_entity_cleanup(&decoder->connectors[i].ent); 2256d000e9b5SChuhong Yuan } 2257c7d97499SJavier Martinez Canillas v4l2_async_unregister_subdev(sd); 2258cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&decoder->hdl); 225973549a69SMarco Felsch pm_runtime_disable(&c->dev); 226073549a69SMarco Felsch pm_runtime_set_suspended(&c->dev); 226173549a69SMarco Felsch 2262cb7a01acSMauro Carvalho Chehab return 0; 2263cb7a01acSMauro Carvalho Chehab } 2264cb7a01acSMauro Carvalho Chehab 2265cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 2266cb7a01acSMauro Carvalho Chehab 226773549a69SMarco Felsch static const struct dev_pm_ops tvp5150_pm_ops = { 226873549a69SMarco Felsch SET_RUNTIME_PM_OPS(tvp5150_runtime_suspend, 226973549a69SMarco Felsch tvp5150_runtime_resume, 227073549a69SMarco Felsch NULL) 227173549a69SMarco Felsch }; 227273549a69SMarco Felsch 2273cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvp5150_id[] = { 2274cb7a01acSMauro Carvalho Chehab { "tvp5150", 0 }, 2275cb7a01acSMauro Carvalho Chehab { } 2276cb7a01acSMauro Carvalho Chehab }; 2277cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvp5150_id); 2278cb7a01acSMauro Carvalho Chehab 22797ef930a7SEduard Gavin #if IS_ENABLED(CONFIG_OF) 22807ef930a7SEduard Gavin static const struct of_device_id tvp5150_of_match[] = { 22817ef930a7SEduard Gavin { .compatible = "ti,tvp5150", }, 22827ef930a7SEduard Gavin { /* sentinel */ }, 22837ef930a7SEduard Gavin }; 22847ef930a7SEduard Gavin MODULE_DEVICE_TABLE(of, tvp5150_of_match); 22857ef930a7SEduard Gavin #endif 22867ef930a7SEduard Gavin 2287cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvp5150_driver = { 2288cb7a01acSMauro Carvalho Chehab .driver = { 22897ef930a7SEduard Gavin .of_match_table = of_match_ptr(tvp5150_of_match), 2290cb7a01acSMauro Carvalho Chehab .name = "tvp5150", 229173549a69SMarco Felsch .pm = &tvp5150_pm_ops, 2292cb7a01acSMauro Carvalho Chehab }, 2293e6714993SKieran Bingham .probe_new = tvp5150_probe, 2294cb7a01acSMauro Carvalho Chehab .remove = tvp5150_remove, 2295cb7a01acSMauro Carvalho Chehab .id_table = tvp5150_id, 2296cb7a01acSMauro Carvalho Chehab }; 2297cb7a01acSMauro Carvalho Chehab 2298cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvp5150_driver); 2299