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> 13cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 14859969b3SSakari Ailus #include <linux/of_graph.h> 15c7d97499SJavier Martinez Canillas #include <media/v4l2-async.h> 16cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 17cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 18859969b3SSakari Ailus #include <media/v4l2-fwnode.h> 1955606310SMauro Carvalho Chehab #include <media/v4l2-mc.h> 20cb7a01acSMauro Carvalho Chehab 21cb7a01acSMauro Carvalho Chehab #include "tvp5150_reg.h" 22cb7a01acSMauro Carvalho Chehab 23785a3de1SPhilipp Zabel #define TVP5150_H_MAX 720U 24785a3de1SPhilipp Zabel #define TVP5150_V_MAX_525_60 480U 25785a3de1SPhilipp Zabel #define TVP5150_V_MAX_OTHERS 576U 26cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_LEFT 511 27cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_TOP 127 28cb7a01acSMauro Carvalho Chehab #define TVP5150_CROP_SHIFT 2 29cb7a01acSMauro Carvalho Chehab 30c43875f6SMauro Carvalho Chehab MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver"); 31cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab"); 32459ee17cSMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 33cb7a01acSMauro Carvalho Chehab 34cb7a01acSMauro Carvalho Chehab 35cb7a01acSMauro Carvalho Chehab static int debug; 362a0489d3SPhilipp Zabel module_param(debug, int, 0644); 37cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-2)"); 38cb7a01acSMauro Carvalho Chehab 39ad0e3744SMauro Carvalho Chehab #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg) 40ad0e3744SMauro Carvalho Chehab 41bc322c0dSMauro Carvalho Chehab enum tvp5150_pads { 42bc322c0dSMauro Carvalho Chehab TVP5150_PAD_IF_INPUT, 43bc322c0dSMauro Carvalho Chehab TVP5150_PAD_VID_OUT, 44bc322c0dSMauro Carvalho Chehab TVP5150_NUM_PADS 45bc322c0dSMauro Carvalho Chehab }; 46bc322c0dSMauro Carvalho Chehab 47cb7a01acSMauro Carvalho Chehab struct tvp5150 { 48cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 4955606310SMauro Carvalho Chehab #ifdef CONFIG_MEDIA_CONTROLLER 50bc322c0dSMauro Carvalho Chehab struct media_pad pads[TVP5150_NUM_PADS]; 51f7b4b54eSJavier Martinez Canillas struct media_entity input_ent[TVP5150_INPUT_NUM]; 52f7b4b54eSJavier Martinez Canillas struct media_pad input_pad[TVP5150_INPUT_NUM]; 5355606310SMauro Carvalho Chehab #endif 54cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler hdl; 55cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect; 56cb7a01acSMauro Carvalho Chehab 57cb7a01acSMauro Carvalho Chehab v4l2_std_id norm; /* Current set standard */ 58cb7a01acSMauro Carvalho Chehab u32 input; 59cb7a01acSMauro Carvalho Chehab u32 output; 60cb7a01acSMauro Carvalho Chehab int enable; 61a2e5f1b3SJavier Martinez Canillas 6282275133SJavier Martinez Canillas u16 dev_id; 6382275133SJavier Martinez Canillas u16 rom_ver; 6482275133SJavier Martinez Canillas 65a2e5f1b3SJavier Martinez Canillas enum v4l2_mbus_type mbus_type; 66cb7a01acSMauro Carvalho Chehab }; 67cb7a01acSMauro Carvalho Chehab 68cb7a01acSMauro Carvalho Chehab static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) 69cb7a01acSMauro Carvalho Chehab { 70cb7a01acSMauro Carvalho Chehab return container_of(sd, struct tvp5150, sd); 71cb7a01acSMauro Carvalho Chehab } 72cb7a01acSMauro Carvalho Chehab 73cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 74cb7a01acSMauro Carvalho Chehab { 75cb7a01acSMauro Carvalho Chehab return &container_of(ctrl->handler, struct tvp5150, hdl)->sd; 76cb7a01acSMauro Carvalho Chehab } 77cb7a01acSMauro Carvalho Chehab 78cb7a01acSMauro Carvalho Chehab static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) 79cb7a01acSMauro Carvalho Chehab { 80cb7a01acSMauro Carvalho Chehab struct i2c_client *c = v4l2_get_subdevdata(sd); 81cb7a01acSMauro Carvalho Chehab int rc; 82cb7a01acSMauro Carvalho Chehab 83e35ce2e4SLaurent Pinchart rc = i2c_smbus_read_byte_data(c, addr); 84e35ce2e4SLaurent Pinchart if (rc < 0) { 85257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "i2c i/o error: rc == %d\n", rc); 86e35ce2e4SLaurent Pinchart return rc; 87cb7a01acSMauro Carvalho Chehab } 88cb7a01acSMauro Carvalho Chehab 89257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 2, debug, "tvp5150: read 0x%02x = %02x\n", addr, rc); 90cb7a01acSMauro Carvalho Chehab 91e35ce2e4SLaurent Pinchart return rc; 92cb7a01acSMauro Carvalho Chehab } 93cb7a01acSMauro Carvalho Chehab 94cacdd6a4SJavier Martinez Canillas static int tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, 95cb7a01acSMauro Carvalho Chehab unsigned char value) 96cb7a01acSMauro Carvalho Chehab { 97cb7a01acSMauro Carvalho Chehab struct i2c_client *c = v4l2_get_subdevdata(sd); 98cb7a01acSMauro Carvalho Chehab int rc; 99cb7a01acSMauro Carvalho Chehab 100257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 2, debug, "tvp5150: writing %02x %02x\n", addr, value); 101e35ce2e4SLaurent Pinchart rc = i2c_smbus_write_byte_data(c, addr, value); 102e35ce2e4SLaurent Pinchart if (rc < 0) 103257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "i2c i/o error: rc == %d\n", rc); 104cacdd6a4SJavier Martinez Canillas 105cacdd6a4SJavier Martinez Canillas return rc; 106cb7a01acSMauro Carvalho Chehab } 107cb7a01acSMauro Carvalho Chehab 108cb7a01acSMauro Carvalho Chehab static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, 109cb7a01acSMauro Carvalho Chehab const u8 end, int max_line) 110cb7a01acSMauro Carvalho Chehab { 111e5134114SMauro Carvalho Chehab u8 buf[16]; 112e5134114SMauro Carvalho Chehab int i = 0, j, len; 113cb7a01acSMauro Carvalho Chehab 114e5134114SMauro Carvalho Chehab if (max_line > 16) { 115e5134114SMauro Carvalho Chehab dprintk0(sd->dev, "too much data to dump\n"); 116e5134114SMauro Carvalho Chehab return; 117cb7a01acSMauro Carvalho Chehab } 118cb7a01acSMauro Carvalho Chehab 119e5134114SMauro Carvalho Chehab for (i = init; i < end; i += max_line) { 120e5134114SMauro Carvalho Chehab len = (end - i > max_line) ? max_line : end - i; 121e5134114SMauro Carvalho Chehab 122e5134114SMauro Carvalho Chehab for (j = 0; j < len; j++) 123e5134114SMauro Carvalho Chehab buf[j] = tvp5150_read(sd, i + j); 124e5134114SMauro Carvalho Chehab 125e5134114SMauro Carvalho Chehab dprintk0(sd->dev, "%s reg %02x = %*ph\n", s, i, len, buf); 126cb7a01acSMauro Carvalho Chehab } 127cb7a01acSMauro Carvalho Chehab } 128cb7a01acSMauro Carvalho Chehab 129cb7a01acSMauro Carvalho Chehab static int tvp5150_log_status(struct v4l2_subdev *sd) 130cb7a01acSMauro Carvalho Chehab { 131ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Video input source selection #1 = 0x%02x\n", 132cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); 133ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Analog channel controls = 0x%02x\n", 134cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); 135ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Operation mode controls = 0x%02x\n", 136cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_OP_MODE_CTL)); 137ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Miscellaneous controls = 0x%02x\n", 138cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MISC_CTL)); 139ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Autoswitch mask= 0x%02x\n", 140cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_AUTOSW_MSK)); 141ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Color killer threshold control = 0x%02x\n", 142cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); 143ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", 144cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), 145cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), 146cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); 147ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Brightness control = 0x%02x\n", 148cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_BRIGHT_CTL)); 149ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Color saturation control = 0x%02x\n", 150cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_SATURATION_CTL)); 151ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Hue control = 0x%02x\n", 152cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HUE_CTL)); 153ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Contrast control = 0x%02x\n", 154cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONTRAST_CTL)); 155ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Outputs and data rates select = 0x%02x\n", 156cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); 157ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Configuration shared pins = 0x%02x\n", 158cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); 159ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Active video cropping start = 0x%02x%02x\n", 160cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), 161cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); 162ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Active video cropping stop = 0x%02x%02x\n", 163cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), 164cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); 165ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Genlock/RTC = 0x%02x\n", 166cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_GENLOCK)); 167ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Horizontal sync start = 0x%02x\n", 168cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); 169ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical blanking start = 0x%02x\n", 170cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); 171ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical blanking stop = 0x%02x\n", 172cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); 173ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", 174cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), 175cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); 176ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt reset register B = 0x%02x\n", 177cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); 178ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt enable register B = 0x%02x\n", 179cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); 180ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt configuration register B = 0x%02x\n", 181cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); 182ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Video standard = 0x%02x\n", 183cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VIDEO_STD)); 184ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", 185cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CB_GAIN_FACT), 186cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); 187ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Macrovision on counter = 0x%02x\n", 188cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); 189ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Macrovision off counter = 0x%02x\n", 190cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); 191ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", 192cb7a01acSMauro Carvalho Chehab (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); 193ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Device ID = %02x%02x\n", 194cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MSB_DEV_ID), 195cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LSB_DEV_ID)); 196ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: ROM version = (hex) %02x.%02x\n", 197cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), 198cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); 199ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical line count = 0x%02x%02x\n", 200cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), 201cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); 202ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt status register B = 0x%02x\n", 203cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); 204ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt active register B = 0x%02x\n", 205cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); 206ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", 207cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_1), 208cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_2), 209cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_3), 210cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_4), 211cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_5)); 212cb7a01acSMauro Carvalho Chehab 213cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, 214cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL1_END, 8); 215cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, 216cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL2_END, 8); 217cb7a01acSMauro Carvalho Chehab 218ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Teletext filter enable = 0x%02x\n", 219cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); 220ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt status register A = 0x%02x\n", 221cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); 222ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt enable register A = 0x%02x\n", 223cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); 224ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt configuration = 0x%02x\n", 225cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_CONF)); 226ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: VDP status register = 0x%02x\n", 227cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); 228ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO word count = 0x%02x\n", 229cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); 230ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO interrupt threshold = 0x%02x\n", 231cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); 232ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO reset = 0x%02x\n", 233cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_RESET)); 234ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Line number interrupt = 0x%02x\n", 235cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); 236ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Pixel alignment register = 0x%02x%02x\n", 237cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), 238cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); 239ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO output control = 0x%02x\n", 240cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); 241ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Full field enable = 0x%02x\n", 242cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); 243ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Full field mode register = 0x%02x\n", 244cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); 245cb7a01acSMauro Carvalho Chehab 246cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI, 247cb7a01acSMauro Carvalho Chehab TVP5150_CC_DATA_END, 8); 248cb7a01acSMauro Carvalho Chehab 249cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "WSS data", TVP5150_WSS_DATA_INI, 250cb7a01acSMauro Carvalho Chehab TVP5150_WSS_DATA_END, 8); 251cb7a01acSMauro Carvalho Chehab 252cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VPS data", TVP5150_VPS_DATA_INI, 253cb7a01acSMauro Carvalho Chehab TVP5150_VPS_DATA_END, 8); 254cb7a01acSMauro Carvalho Chehab 255cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VITC data", TVP5150_VITC_DATA_INI, 256cb7a01acSMauro Carvalho Chehab TVP5150_VITC_DATA_END, 10); 257cb7a01acSMauro Carvalho Chehab 258cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Line mode", TVP5150_LINE_MODE_INI, 259cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_END, 8); 260cb7a01acSMauro Carvalho Chehab return 0; 261cb7a01acSMauro Carvalho Chehab } 262cb7a01acSMauro Carvalho Chehab 263cb7a01acSMauro Carvalho Chehab /**************************************************************************** 264cb7a01acSMauro Carvalho Chehab Basic functions 265cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 266cb7a01acSMauro Carvalho Chehab 2676e98bee2SLaurent Pinchart static void tvp5150_selmux(struct v4l2_subdev *sd) 268cb7a01acSMauro Carvalho Chehab { 269cb7a01acSMauro Carvalho Chehab int opmode = 0; 270cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 271cb7a01acSMauro Carvalho Chehab int input = 0; 272cb7a01acSMauro Carvalho Chehab int val; 273cb7a01acSMauro Carvalho Chehab 274c43875f6SMauro Carvalho Chehab /* Only tvp5150am1 and tvp5151 have signal generator support */ 275c43875f6SMauro Carvalho Chehab if ((decoder->dev_id == 0x5150 && decoder->rom_ver == 0x0400) || 276c43875f6SMauro Carvalho Chehab (decoder->dev_id == 0x5151 && decoder->rom_ver == 0x0100)) { 277c43875f6SMauro Carvalho Chehab if (!decoder->enable) 278cb7a01acSMauro Carvalho Chehab input = 8; 279c43875f6SMauro Carvalho Chehab } 280cb7a01acSMauro Carvalho Chehab 281cb7a01acSMauro Carvalho Chehab switch (decoder->input) { 282cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE1: 283cb7a01acSMauro Carvalho Chehab input |= 2; 284cb7a01acSMauro Carvalho Chehab /* fall through */ 285cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE0: 286cb7a01acSMauro Carvalho Chehab break; 287cb7a01acSMauro Carvalho Chehab case TVP5150_SVIDEO: 288cb7a01acSMauro Carvalho Chehab default: 289cb7a01acSMauro Carvalho Chehab input |= 1; 290cb7a01acSMauro Carvalho Chehab break; 291cb7a01acSMauro Carvalho Chehab } 292cb7a01acSMauro Carvalho Chehab 293257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n", 294cb7a01acSMauro Carvalho Chehab decoder->input, decoder->output, 295cb7a01acSMauro Carvalho Chehab input, opmode); 296cb7a01acSMauro Carvalho Chehab 297cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode); 298cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input); 299cb7a01acSMauro Carvalho Chehab 300b4b2de38SLaurent Pinchart /* 301b4b2de38SLaurent Pinchart * Setup the FID/GLCO/VLK/HVLK and INTREQ/GPCL/VBLK output signals. For 302b4b2de38SLaurent Pinchart * S-Video we output the vertical lock (VLK) signal on FID/GLCO/VLK/HVLK 303b4b2de38SLaurent Pinchart * and set INTREQ/GPCL/VBLK to logic 0. For composite we output the 304b4b2de38SLaurent Pinchart * field indicator (FID) signal on FID/GLCO/VLK/HVLK and set 305b4b2de38SLaurent Pinchart * INTREQ/GPCL/VBLK to logic 1. 306cb7a01acSMauro Carvalho Chehab */ 307cb7a01acSMauro Carvalho Chehab val = tvp5150_read(sd, TVP5150_MISC_CTL); 308cb7a01acSMauro Carvalho Chehab if (val < 0) { 309257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "%s: failed with error = %d\n", __func__, val); 310cb7a01acSMauro Carvalho Chehab return; 311cb7a01acSMauro Carvalho Chehab } 312cb7a01acSMauro Carvalho Chehab 313cb7a01acSMauro Carvalho Chehab if (decoder->input == TVP5150_SVIDEO) 314b4b2de38SLaurent Pinchart val = (val & ~TVP5150_MISC_CTL_GPCL) | TVP5150_MISC_CTL_HVLK; 315cb7a01acSMauro Carvalho Chehab else 316b4b2de38SLaurent Pinchart val = (val & ~TVP5150_MISC_CTL_HVLK) | TVP5150_MISC_CTL_GPCL; 317cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_MISC_CTL, val); 318cb7a01acSMauro Carvalho Chehab }; 319cb7a01acSMauro Carvalho Chehab 320cb7a01acSMauro Carvalho Chehab struct i2c_reg_value { 321cb7a01acSMauro Carvalho Chehab unsigned char reg; 322cb7a01acSMauro Carvalho Chehab unsigned char value; 323cb7a01acSMauro Carvalho Chehab }; 324cb7a01acSMauro Carvalho Chehab 325cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 326cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_default[] = { 327cb7a01acSMauro Carvalho Chehab { /* 0x00 */ 328cb7a01acSMauro Carvalho Chehab TVP5150_VD_IN_SRC_SEL_1, 0x00 329cb7a01acSMauro Carvalho Chehab }, 330cb7a01acSMauro Carvalho Chehab { /* 0x01 */ 331cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 332cb7a01acSMauro Carvalho Chehab }, 333cb7a01acSMauro Carvalho Chehab { /* 0x02 */ 334cb7a01acSMauro Carvalho Chehab TVP5150_OP_MODE_CTL, 0x00 335cb7a01acSMauro Carvalho Chehab }, 336cb7a01acSMauro Carvalho Chehab { /* 0x03 */ 337cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL, 0x01 338cb7a01acSMauro Carvalho Chehab }, 339cb7a01acSMauro Carvalho Chehab { /* 0x06 */ 340cb7a01acSMauro Carvalho Chehab TVP5150_COLOR_KIL_THSH_CTL, 0x10 341cb7a01acSMauro Carvalho Chehab }, 342cb7a01acSMauro Carvalho Chehab { /* 0x07 */ 343cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_1, 0x60 344cb7a01acSMauro Carvalho Chehab }, 345cb7a01acSMauro Carvalho Chehab { /* 0x08 */ 346cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_2, 0x00 347cb7a01acSMauro Carvalho Chehab }, 348cb7a01acSMauro Carvalho Chehab { /* 0x09 */ 349cb7a01acSMauro Carvalho Chehab TVP5150_BRIGHT_CTL, 0x80 350cb7a01acSMauro Carvalho Chehab }, 351cb7a01acSMauro Carvalho Chehab { /* 0x0a */ 352cb7a01acSMauro Carvalho Chehab TVP5150_SATURATION_CTL, 0x80 353cb7a01acSMauro Carvalho Chehab }, 354cb7a01acSMauro Carvalho Chehab { /* 0x0b */ 355cb7a01acSMauro Carvalho Chehab TVP5150_HUE_CTL, 0x00 356cb7a01acSMauro Carvalho Chehab }, 357cb7a01acSMauro Carvalho Chehab { /* 0x0c */ 358cb7a01acSMauro Carvalho Chehab TVP5150_CONTRAST_CTL, 0x80 359cb7a01acSMauro Carvalho Chehab }, 360cb7a01acSMauro Carvalho Chehab { /* 0x0d */ 361cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 362cb7a01acSMauro Carvalho Chehab }, 363cb7a01acSMauro Carvalho Chehab { /* 0x0e */ 364cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_3, 0x00 365cb7a01acSMauro Carvalho Chehab }, 366cb7a01acSMauro Carvalho Chehab { /* 0x0f */ 367cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN, 0x08 368cb7a01acSMauro Carvalho Chehab }, 369cb7a01acSMauro Carvalho Chehab { /* 0x11 */ 370cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_MSB, 0x00 371cb7a01acSMauro Carvalho Chehab }, 372cb7a01acSMauro Carvalho Chehab { /* 0x12 */ 373cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_LSB, 0x00 374cb7a01acSMauro Carvalho Chehab }, 375cb7a01acSMauro Carvalho Chehab { /* 0x13 */ 376cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_MSB, 0x00 377cb7a01acSMauro Carvalho Chehab }, 378cb7a01acSMauro Carvalho Chehab { /* 0x14 */ 379cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_LSB, 0x00 380cb7a01acSMauro Carvalho Chehab }, 381cb7a01acSMauro Carvalho Chehab { /* 0x15 */ 382cb7a01acSMauro Carvalho Chehab TVP5150_GENLOCK, 0x01 383cb7a01acSMauro Carvalho Chehab }, 384cb7a01acSMauro Carvalho Chehab { /* 0x16 */ 385cb7a01acSMauro Carvalho Chehab TVP5150_HORIZ_SYNC_START, 0x80 386cb7a01acSMauro Carvalho Chehab }, 387cb7a01acSMauro Carvalho Chehab { /* 0x18 */ 388cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_START, 0x00 389cb7a01acSMauro Carvalho Chehab }, 390cb7a01acSMauro Carvalho Chehab { /* 0x19 */ 391cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_STOP, 0x00 392cb7a01acSMauro Carvalho Chehab }, 393cb7a01acSMauro Carvalho Chehab { /* 0x1a */ 394cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 395cb7a01acSMauro Carvalho Chehab }, 396cb7a01acSMauro Carvalho Chehab { /* 0x1b */ 397cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x14 398cb7a01acSMauro Carvalho Chehab }, 399cb7a01acSMauro Carvalho Chehab { /* 0x1c */ 400cb7a01acSMauro Carvalho Chehab TVP5150_INT_RESET_REG_B, 0x00 401cb7a01acSMauro Carvalho Chehab }, 402cb7a01acSMauro Carvalho Chehab { /* 0x1d */ 403cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_B, 0x00 404cb7a01acSMauro Carvalho Chehab }, 405cb7a01acSMauro Carvalho Chehab { /* 0x1e */ 406cb7a01acSMauro Carvalho Chehab TVP5150_INTT_CONFIG_REG_B, 0x00 407cb7a01acSMauro Carvalho Chehab }, 408cb7a01acSMauro Carvalho Chehab { /* 0x28 */ 409cb7a01acSMauro Carvalho Chehab TVP5150_VIDEO_STD, 0x00 410cb7a01acSMauro Carvalho Chehab }, 411cb7a01acSMauro Carvalho Chehab { /* 0x2e */ 412cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_ON_CTR, 0x0f 413cb7a01acSMauro Carvalho Chehab }, 414cb7a01acSMauro Carvalho Chehab { /* 0x2f */ 415cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_OFF_CTR, 0x01 416cb7a01acSMauro Carvalho Chehab }, 417cb7a01acSMauro Carvalho Chehab { /* 0xbb */ 418cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL_ENA, 0x00 419cb7a01acSMauro Carvalho Chehab }, 420cb7a01acSMauro Carvalho Chehab { /* 0xc0 */ 421cb7a01acSMauro Carvalho Chehab TVP5150_INT_STATUS_REG_A, 0x00 422cb7a01acSMauro Carvalho Chehab }, 423cb7a01acSMauro Carvalho Chehab { /* 0xc1 */ 424cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_A, 0x00 425cb7a01acSMauro Carvalho Chehab }, 426cb7a01acSMauro Carvalho Chehab { /* 0xc2 */ 427cb7a01acSMauro Carvalho Chehab TVP5150_INT_CONF, 0x04 428cb7a01acSMauro Carvalho Chehab }, 429cb7a01acSMauro Carvalho Chehab { /* 0xc8 */ 430cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_INT_THRESHOLD, 0x80 431cb7a01acSMauro Carvalho Chehab }, 432cb7a01acSMauro Carvalho Chehab { /* 0xc9 */ 433cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_RESET, 0x00 434cb7a01acSMauro Carvalho Chehab }, 435cb7a01acSMauro Carvalho Chehab { /* 0xca */ 436cb7a01acSMauro Carvalho Chehab TVP5150_LINE_NUMBER_INT, 0x00 437cb7a01acSMauro Carvalho Chehab }, 438cb7a01acSMauro Carvalho Chehab { /* 0xcb */ 439cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_LOW, 0x4e 440cb7a01acSMauro Carvalho Chehab }, 441cb7a01acSMauro Carvalho Chehab { /* 0xcc */ 442cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_HIGH, 0x00 443cb7a01acSMauro Carvalho Chehab }, 444cb7a01acSMauro Carvalho Chehab { /* 0xcd */ 445cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_OUT_CTRL, 0x01 446cb7a01acSMauro Carvalho Chehab }, 447cb7a01acSMauro Carvalho Chehab { /* 0xcf */ 448cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_ENA, 0x00 449cb7a01acSMauro Carvalho Chehab }, 450cb7a01acSMauro Carvalho Chehab { /* 0xd0 */ 451cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_INI, 0x00 452cb7a01acSMauro Carvalho Chehab }, 453cb7a01acSMauro Carvalho Chehab { /* 0xfc */ 454cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_MODE_REG, 0x7f 455cb7a01acSMauro Carvalho Chehab }, 456cb7a01acSMauro Carvalho Chehab { /* end of data */ 457cb7a01acSMauro Carvalho Chehab 0xff, 0xff 458cb7a01acSMauro Carvalho Chehab } 459cb7a01acSMauro Carvalho Chehab }; 460cb7a01acSMauro Carvalho Chehab 461cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 462cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_enable[] = { 463cb7a01acSMauro Carvalho Chehab { 464cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN, 2 465cb7a01acSMauro Carvalho Chehab }, { /* Automatic offset and AGC enabled */ 466cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 467cb7a01acSMauro Carvalho Chehab }, { /* Activate YCrCb output 0x9 or 0xd ? */ 468b4b2de38SLaurent Pinchart TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL | 469b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_INTREQ_OE | 470b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_YCBCR_OE | 471b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_SYNC_OE | 472b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_VBLANK | 473b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_CLOCK_OE, 474cb7a01acSMauro Carvalho Chehab }, { /* Activates video std autodetection for all standards */ 475cb7a01acSMauro Carvalho Chehab TVP5150_AUTOSW_MSK, 0x0 476cb7a01acSMauro Carvalho Chehab }, { /* Default format: 0x47. For 4:2:2: 0x40 */ 477cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 478cb7a01acSMauro Carvalho Chehab }, { 479cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 480cb7a01acSMauro Carvalho Chehab }, { 481cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x54 482cb7a01acSMauro Carvalho Chehab }, { /* Non documented, but initialized on WinTV USB2 */ 483cb7a01acSMauro Carvalho Chehab 0x27, 0x20 484cb7a01acSMauro Carvalho Chehab }, { 485cb7a01acSMauro Carvalho Chehab 0xff, 0xff 486cb7a01acSMauro Carvalho Chehab } 487cb7a01acSMauro Carvalho Chehab }; 488cb7a01acSMauro Carvalho Chehab 489cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type { 490cb7a01acSMauro Carvalho Chehab unsigned int vbi_type; 491cb7a01acSMauro Carvalho Chehab unsigned int ini_line; 492cb7a01acSMauro Carvalho Chehab unsigned int end_line; 493cb7a01acSMauro Carvalho Chehab unsigned int by_field :1; 494cb7a01acSMauro Carvalho Chehab }; 495cb7a01acSMauro Carvalho Chehab 496cb7a01acSMauro Carvalho Chehab struct i2c_vbi_ram_value { 497cb7a01acSMauro Carvalho Chehab u16 reg; 498cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type type; 499cb7a01acSMauro Carvalho Chehab unsigned char values[16]; 500cb7a01acSMauro Carvalho Chehab }; 501cb7a01acSMauro Carvalho Chehab 502cb7a01acSMauro Carvalho Chehab /* This struct have the values for each supported VBI Standard 503cb7a01acSMauro Carvalho Chehab * by 504cb7a01acSMauro Carvalho Chehab tvp5150_vbi_types should follow the same order as vbi_ram_default 505cb7a01acSMauro Carvalho Chehab * value 0 means rom position 0x10, value 1 means rom position 0x30 506cb7a01acSMauro Carvalho Chehab * and so on. There are 16 possible locations from 0 to 15. 507cb7a01acSMauro Carvalho Chehab */ 508cb7a01acSMauro Carvalho Chehab 50965dc760bSNasser Afshin static struct i2c_vbi_ram_value vbi_ram_default[] = { 51065dc760bSNasser Afshin 5119bfd8f88SNasser Afshin /* 5129bfd8f88SNasser Afshin * FIXME: Current api doesn't handle all VBI types, those not 5139bfd8f88SNasser Afshin * yet supported are placed under #if 0 5149bfd8f88SNasser Afshin */ 515cb7a01acSMauro Carvalho Chehab #if 0 5163dd6b560SMauro Carvalho Chehab [0] = {0x010, /* Teletext, SECAM, WST System A */ 517cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_SECAM, 6, 23, 1}, 518cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 519cb7a01acSMauro Carvalho Chehab 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } 520cb7a01acSMauro Carvalho Chehab }, 521cb7a01acSMauro Carvalho Chehab #endif 5223dd6b560SMauro Carvalho Chehab [1] = {0x030, /* Teletext, PAL, WST System B */ 523cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_B, 6, 22, 1}, 524cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 525cb7a01acSMauro Carvalho Chehab 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } 526cb7a01acSMauro Carvalho Chehab }, 527cb7a01acSMauro Carvalho Chehab #if 0 5283dd6b560SMauro Carvalho Chehab [2] = {0x050, /* Teletext, PAL, WST System C */ 529cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_PAL_C, 6, 22, 1}, 530cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 531cb7a01acSMauro Carvalho Chehab 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 532cb7a01acSMauro Carvalho Chehab }, 5333dd6b560SMauro Carvalho Chehab [3] = {0x070, /* Teletext, NTSC, WST System B */ 534cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_B, 10, 21, 1}, 535cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, 536cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 537cb7a01acSMauro Carvalho Chehab }, 5383dd6b560SMauro Carvalho Chehab [4] = {0x090, /* Tetetext, NTSC NABTS System C */ 539cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_C, 10, 21, 1}, 540cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 541cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } 542cb7a01acSMauro Carvalho Chehab }, 5433dd6b560SMauro Carvalho Chehab [5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */ 544cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_D, 10, 21, 1}, 545cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, 546cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 547cb7a01acSMauro Carvalho Chehab }, 5483dd6b560SMauro Carvalho Chehab [6] = {0x0d0, /* Closed Caption, PAL/SECAM */ 549cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_625, 22, 22, 1}, 550cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 551cb7a01acSMauro Carvalho Chehab 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 552cb7a01acSMauro Carvalho Chehab }, 553cb7a01acSMauro Carvalho Chehab #endif 5543dd6b560SMauro Carvalho Chehab [7] = {0x0f0, /* Closed Caption, NTSC */ 555cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_525, 21, 21, 1}, 556cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 557cb7a01acSMauro Carvalho Chehab 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 558cb7a01acSMauro Carvalho Chehab }, 5593dd6b560SMauro Carvalho Chehab [8] = {0x110, /* Wide Screen Signal, PAL/SECAM */ 560cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_625, 23, 23, 1}, 561cb7a01acSMauro Carvalho Chehab { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 562cb7a01acSMauro Carvalho Chehab 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } 563cb7a01acSMauro Carvalho Chehab }, 564cb7a01acSMauro Carvalho Chehab #if 0 5653dd6b560SMauro Carvalho Chehab [9] = {0x130, /* Wide Screen Signal, NTSC C */ 566cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_525, 20, 20, 1}, 567cb7a01acSMauro Carvalho Chehab { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, 568cb7a01acSMauro Carvalho Chehab 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } 569cb7a01acSMauro Carvalho Chehab }, 5703dd6b560SMauro Carvalho Chehab [10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ 571cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_625, 6, 22, 0}, 572cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 573cb7a01acSMauro Carvalho Chehab 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 574cb7a01acSMauro Carvalho Chehab }, 5753dd6b560SMauro Carvalho Chehab [11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */ 576cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_525, 10, 20, 0}, 577cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 578cb7a01acSMauro Carvalho Chehab 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 579cb7a01acSMauro Carvalho Chehab }, 580cb7a01acSMauro Carvalho Chehab #endif 5813dd6b560SMauro Carvalho Chehab [12] = {0x190, /* Video Program System (VPS), PAL */ 582cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_VPS, 16, 16, 0}, 583cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, 584cb7a01acSMauro Carvalho Chehab 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } 585cb7a01acSMauro Carvalho Chehab }, 586cb7a01acSMauro Carvalho Chehab /* 0x1d0 User programmable */ 587cb7a01acSMauro Carvalho Chehab }; 588cb7a01acSMauro Carvalho Chehab 589cb7a01acSMauro Carvalho Chehab static int tvp5150_write_inittab(struct v4l2_subdev *sd, 590cb7a01acSMauro Carvalho Chehab const struct i2c_reg_value *regs) 591cb7a01acSMauro Carvalho Chehab { 592cb7a01acSMauro Carvalho Chehab while (regs->reg != 0xff) { 593cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, regs->reg, regs->value); 594cb7a01acSMauro Carvalho Chehab regs++; 595cb7a01acSMauro Carvalho Chehab } 596cb7a01acSMauro Carvalho Chehab return 0; 597cb7a01acSMauro Carvalho Chehab } 598cb7a01acSMauro Carvalho Chehab 5993dd6b560SMauro Carvalho Chehab static int tvp5150_vdp_init(struct v4l2_subdev *sd) 600cb7a01acSMauro Carvalho Chehab { 601cb7a01acSMauro Carvalho Chehab unsigned int i; 6023dd6b560SMauro Carvalho Chehab int j; 603cb7a01acSMauro Carvalho Chehab 604cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 605cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); 606cb7a01acSMauro Carvalho Chehab 607cb7a01acSMauro Carvalho Chehab /* Before programming, Line mode should be at 0xff */ 608cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 609cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, i, 0xff); 610cb7a01acSMauro Carvalho Chehab 611cb7a01acSMauro Carvalho Chehab /* Load Ram Table */ 6123dd6b560SMauro Carvalho Chehab for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) { 6133dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j]; 6143dd6b560SMauro Carvalho Chehab 6153dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 6163dd6b560SMauro Carvalho Chehab continue; 6173dd6b560SMauro Carvalho Chehab 618cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); 619cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); 620cb7a01acSMauro Carvalho Chehab 621cb7a01acSMauro Carvalho Chehab for (i = 0; i < 16; i++) 622cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]); 623cb7a01acSMauro Carvalho Chehab } 624cb7a01acSMauro Carvalho Chehab return 0; 625cb7a01acSMauro Carvalho Chehab } 626cb7a01acSMauro Carvalho Chehab 627cb7a01acSMauro Carvalho Chehab /* Fills VBI capabilities based on i2c_vbi_ram_value struct */ 628cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, 629cb7a01acSMauro Carvalho Chehab struct v4l2_sliced_vbi_cap *cap) 630cb7a01acSMauro Carvalho Chehab { 6313dd6b560SMauro Carvalho Chehab int line, i; 632cb7a01acSMauro Carvalho Chehab 633257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n"); 634bb7a3681SNasser Afshin memset(cap, 0, sizeof(*cap)); 635cb7a01acSMauro Carvalho Chehab 6363dd6b560SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { 6373dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; 6383dd6b560SMauro Carvalho Chehab 6393dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 6403dd6b560SMauro Carvalho Chehab continue; 6413dd6b560SMauro Carvalho Chehab 6423dd6b560SMauro Carvalho Chehab for (line = regs->type.ini_line; 6433dd6b560SMauro Carvalho Chehab line <= regs->type.end_line; 6443dd6b560SMauro Carvalho Chehab line++) { 645cb7a01acSMauro Carvalho Chehab cap->service_lines[0][line] |= regs->type.vbi_type; 646cb7a01acSMauro Carvalho Chehab } 647cb7a01acSMauro Carvalho Chehab cap->service_set |= regs->type.vbi_type; 648cb7a01acSMauro Carvalho Chehab } 649cb7a01acSMauro Carvalho Chehab return 0; 650cb7a01acSMauro Carvalho Chehab } 651cb7a01acSMauro Carvalho Chehab 652cb7a01acSMauro Carvalho Chehab /* Set vbi processing 653cb7a01acSMauro Carvalho Chehab * type - one of tvp5150_vbi_types 654cb7a01acSMauro Carvalho Chehab * line - line to gather data 655cb7a01acSMauro Carvalho Chehab * fields: bit 0 field1, bit 1, field2 656cb7a01acSMauro Carvalho Chehab * flags (default=0xf0) is a bitmask, were set means: 657cb7a01acSMauro Carvalho Chehab * bit 7: enable filtering null bytes on CC 658cb7a01acSMauro Carvalho Chehab * bit 6: send data also to FIFO 659cb7a01acSMauro Carvalho Chehab * bit 5: don't allow data with errors on FIFO 660cb7a01acSMauro Carvalho Chehab * bit 4: enable ECC when possible 661cb7a01acSMauro Carvalho Chehab * pix_align = pix alignment: 662cb7a01acSMauro Carvalho Chehab * LSB = field1 663cb7a01acSMauro Carvalho Chehab * MSB = field2 664cb7a01acSMauro Carvalho Chehab */ 665cb7a01acSMauro Carvalho Chehab static int tvp5150_set_vbi(struct v4l2_subdev *sd, 666cb7a01acSMauro Carvalho Chehab unsigned int type, u8 flags, int line, 667cb7a01acSMauro Carvalho Chehab const int fields) 668cb7a01acSMauro Carvalho Chehab { 669cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 670cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 671cb7a01acSMauro Carvalho Chehab u8 reg; 6723dd6b560SMauro Carvalho Chehab int i, pos = 0; 673cb7a01acSMauro Carvalho Chehab 674cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 675257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); 676cb7a01acSMauro Carvalho Chehab return 0; 677cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 678cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 679cb7a01acSMauro Carvalho Chehab line += 3; 680cb7a01acSMauro Carvalho Chehab } 681cb7a01acSMauro Carvalho Chehab 682cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 683cb7a01acSMauro Carvalho Chehab return 0; 684cb7a01acSMauro Carvalho Chehab 6853dd6b560SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { 6863dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; 6873dd6b560SMauro Carvalho Chehab 6883dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 6893dd6b560SMauro Carvalho Chehab continue; 6903dd6b560SMauro Carvalho Chehab 691cb7a01acSMauro Carvalho Chehab if ((type & regs->type.vbi_type) && 692cb7a01acSMauro Carvalho Chehab (line >= regs->type.ini_line) && 693b3d930aaSGustavo A. R. Silva (line <= regs->type.end_line)) 694cb7a01acSMauro Carvalho Chehab break; 695cb7a01acSMauro Carvalho Chehab pos++; 696cb7a01acSMauro Carvalho Chehab } 697b3d930aaSGustavo A. R. Silva 698cb7a01acSMauro Carvalho Chehab type = pos | (flags & 0xf0); 699cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 700cb7a01acSMauro Carvalho Chehab 701b3d930aaSGustavo A. R. Silva if (fields & 1) 702cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg, type); 703cb7a01acSMauro Carvalho Chehab 704b3d930aaSGustavo A. R. Silva if (fields & 2) 705cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg + 1, type); 706cb7a01acSMauro Carvalho Chehab 707cb7a01acSMauro Carvalho Chehab return type; 708cb7a01acSMauro Carvalho Chehab } 709cb7a01acSMauro Carvalho Chehab 7103dd6b560SMauro Carvalho Chehab static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line) 711cb7a01acSMauro Carvalho Chehab { 712cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 713cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 714cb7a01acSMauro Carvalho Chehab u8 reg; 715cb7a01acSMauro Carvalho Chehab int pos, type = 0; 716cb7a01acSMauro Carvalho Chehab int i, ret = 0; 717cb7a01acSMauro Carvalho Chehab 718cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 719257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); 720cb7a01acSMauro Carvalho Chehab return 0; 721cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 722cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 723cb7a01acSMauro Carvalho Chehab line += 3; 724cb7a01acSMauro Carvalho Chehab } 725cb7a01acSMauro Carvalho Chehab 726cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 727cb7a01acSMauro Carvalho Chehab return 0; 728cb7a01acSMauro Carvalho Chehab 729cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 730cb7a01acSMauro Carvalho Chehab 731cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 1; i++) { 732cb7a01acSMauro Carvalho Chehab ret = tvp5150_read(sd, reg + i); 733cb7a01acSMauro Carvalho Chehab if (ret < 0) { 734257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "%s: failed with error = %d\n", 735cb7a01acSMauro Carvalho Chehab __func__, ret); 736cb7a01acSMauro Carvalho Chehab return 0; 737cb7a01acSMauro Carvalho Chehab } 738cb7a01acSMauro Carvalho Chehab pos = ret & 0x0f; 7393dd6b560SMauro Carvalho Chehab if (pos < ARRAY_SIZE(vbi_ram_default)) 7403dd6b560SMauro Carvalho Chehab type |= vbi_ram_default[pos].type.vbi_type; 741cb7a01acSMauro Carvalho Chehab } 742cb7a01acSMauro Carvalho Chehab 743cb7a01acSMauro Carvalho Chehab return type; 744cb7a01acSMauro Carvalho Chehab } 745cb7a01acSMauro Carvalho Chehab 746cb7a01acSMauro Carvalho Chehab static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) 747cb7a01acSMauro Carvalho Chehab { 748cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 749cb7a01acSMauro Carvalho Chehab int fmt = 0; 750cb7a01acSMauro Carvalho Chehab 751cb7a01acSMauro Carvalho Chehab decoder->norm = std; 752cb7a01acSMauro Carvalho Chehab 753cb7a01acSMauro Carvalho Chehab /* First tests should be against specific std */ 754cb7a01acSMauro Carvalho Chehab 75526811ae0SHans Verkuil if (std == V4L2_STD_NTSC_443) { 756cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_4_43_BIT; 75726811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_M) { 758cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_M_BIT; 75926811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) { 760cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_COMBINATION_N_BIT; 761cb7a01acSMauro Carvalho Chehab } else { 762cb7a01acSMauro Carvalho Chehab /* Then, test against generic ones */ 763cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 764cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_MJ_BIT; 765cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_PAL) 766cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_BDGHIN_BIT; 767cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_SECAM) 768cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_SECAM_BIT; 769cb7a01acSMauro Carvalho Chehab } 770cb7a01acSMauro Carvalho Chehab 771257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "Set video std register to %d.\n", fmt); 772cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VIDEO_STD, fmt); 773cb7a01acSMauro Carvalho Chehab return 0; 774cb7a01acSMauro Carvalho Chehab } 775cb7a01acSMauro Carvalho Chehab 776cb7a01acSMauro Carvalho Chehab static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 777cb7a01acSMauro Carvalho Chehab { 778cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 779cb7a01acSMauro Carvalho Chehab 780cb7a01acSMauro Carvalho Chehab if (decoder->norm == std) 781cb7a01acSMauro Carvalho Chehab return 0; 782cb7a01acSMauro Carvalho Chehab 783cb7a01acSMauro Carvalho Chehab /* Change cropping height limits */ 784cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 785cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_525_60; 786cb7a01acSMauro Carvalho Chehab else 787cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_OTHERS; 788cb7a01acSMauro Carvalho Chehab 789cb7a01acSMauro Carvalho Chehab 790cb7a01acSMauro Carvalho Chehab return tvp5150_set_std(sd, std); 791cb7a01acSMauro Carvalho Chehab } 792cb7a01acSMauro Carvalho Chehab 793cb7a01acSMauro Carvalho Chehab static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) 794cb7a01acSMauro Carvalho Chehab { 795cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 796cb7a01acSMauro Carvalho Chehab 797cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to its default values */ 798cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_default); 799cb7a01acSMauro Carvalho Chehab 800cb7a01acSMauro Carvalho Chehab /* Initializes VDP registers */ 8013dd6b560SMauro Carvalho Chehab tvp5150_vdp_init(sd); 802cb7a01acSMauro Carvalho Chehab 803cb7a01acSMauro Carvalho Chehab /* Selects decoder input */ 804cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 805cb7a01acSMauro Carvalho Chehab 806cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to stream enabled values */ 807cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_enable); 808cb7a01acSMauro Carvalho Chehab 809cb7a01acSMauro Carvalho Chehab /* Initialize image preferences */ 810cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&decoder->hdl); 811cb7a01acSMauro Carvalho Chehab 812cb7a01acSMauro Carvalho Chehab tvp5150_set_std(sd, decoder->norm); 813a2e5f1b3SJavier Martinez Canillas 814a2e5f1b3SJavier Martinez Canillas if (decoder->mbus_type == V4L2_MBUS_PARALLEL) 815a2e5f1b3SJavier Martinez Canillas tvp5150_write(sd, TVP5150_DATA_RATE_SEL, 0x40); 816a2e5f1b3SJavier Martinez Canillas 817cb7a01acSMauro Carvalho Chehab return 0; 818cb7a01acSMauro Carvalho Chehab }; 819cb7a01acSMauro Carvalho Chehab 820cb7a01acSMauro Carvalho Chehab static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) 821cb7a01acSMauro Carvalho Chehab { 822cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_sd(ctrl); 823c43875f6SMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 824cb7a01acSMauro Carvalho Chehab 825cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 826cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 827cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val); 828cb7a01acSMauro Carvalho Chehab return 0; 829cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 830cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val); 831cb7a01acSMauro Carvalho Chehab return 0; 832cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 833cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val); 834cb7a01acSMauro Carvalho Chehab return 0; 835cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 836cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val); 837d183e4efSLaurent Pinchart break; 838c43875f6SMauro Carvalho Chehab case V4L2_CID_TEST_PATTERN: 839c43875f6SMauro Carvalho Chehab decoder->enable = ctrl->val ? false : true; 840c43875f6SMauro Carvalho Chehab tvp5150_selmux(sd); 841cb7a01acSMauro Carvalho Chehab return 0; 842cb7a01acSMauro Carvalho Chehab } 843cb7a01acSMauro Carvalho Chehab return -EINVAL; 844cb7a01acSMauro Carvalho Chehab } 845cb7a01acSMauro Carvalho Chehab 846cb7a01acSMauro Carvalho Chehab static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) 847cb7a01acSMauro Carvalho Chehab { 848cb7a01acSMauro Carvalho Chehab int val = tvp5150_read(sd, TVP5150_STATUS_REG_5); 849cb7a01acSMauro Carvalho Chehab 850cb7a01acSMauro Carvalho Chehab switch (val & 0x0F) { 851cb7a01acSMauro Carvalho Chehab case 0x01: 852cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC; 853cb7a01acSMauro Carvalho Chehab case 0x03: 854cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL; 855cb7a01acSMauro Carvalho Chehab case 0x05: 856cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M; 857cb7a01acSMauro Carvalho Chehab case 0x07: 858cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc; 859cb7a01acSMauro Carvalho Chehab case 0x09: 860cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443; 861cb7a01acSMauro Carvalho Chehab case 0xb: 862cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 863cb7a01acSMauro Carvalho Chehab default: 864cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN; 865cb7a01acSMauro Carvalho Chehab } 866cb7a01acSMauro Carvalho Chehab } 867cb7a01acSMauro Carvalho Chehab 868da298c6dSHans Verkuil static int tvp5150_fill_fmt(struct v4l2_subdev *sd, 869da298c6dSHans Verkuil struct v4l2_subdev_pad_config *cfg, 870da298c6dSHans Verkuil struct v4l2_subdev_format *format) 871cb7a01acSMauro Carvalho Chehab { 872da298c6dSHans Verkuil struct v4l2_mbus_framefmt *f; 873cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 874cb7a01acSMauro Carvalho Chehab 875bc322c0dSMauro Carvalho Chehab if (!format || (format->pad != TVP5150_PAD_VID_OUT)) 876cb7a01acSMauro Carvalho Chehab return -EINVAL; 877cb7a01acSMauro Carvalho Chehab 878da298c6dSHans Verkuil f = &format->format; 879da298c6dSHans Verkuil 880cb7a01acSMauro Carvalho Chehab f->width = decoder->rect.width; 8811831af09SJavier Martinez Canillas f->height = decoder->rect.height / 2; 882cb7a01acSMauro Carvalho Chehab 883f5fe58fdSBoris BREZILLON f->code = MEDIA_BUS_FMT_UYVY8_2X8; 8844f57d27bSLaurent Pinchart f->field = V4L2_FIELD_ALTERNATE; 885cb7a01acSMauro Carvalho Chehab f->colorspace = V4L2_COLORSPACE_SMPTE170M; 886cb7a01acSMauro Carvalho Chehab 887257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "width = %d, height = %d\n", f->width, 888cb7a01acSMauro Carvalho Chehab f->height); 889cb7a01acSMauro Carvalho Chehab return 0; 890cb7a01acSMauro Carvalho Chehab } 891cb7a01acSMauro Carvalho Chehab 89210d5509cSHans Verkuil static int tvp5150_set_selection(struct v4l2_subdev *sd, 89310d5509cSHans Verkuil struct v4l2_subdev_pad_config *cfg, 89410d5509cSHans Verkuil struct v4l2_subdev_selection *sel) 895cb7a01acSMauro Carvalho Chehab { 896cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 89710d5509cSHans Verkuil struct v4l2_rect rect = sel->r; 898cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 89910d5509cSHans Verkuil int hmax; 90010d5509cSHans Verkuil 90110d5509cSHans Verkuil if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || 90210d5509cSHans Verkuil sel->target != V4L2_SEL_TGT_CROP) 90310d5509cSHans Verkuil return -EINVAL; 904cb7a01acSMauro Carvalho Chehab 905257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n", 906cb7a01acSMauro Carvalho Chehab __func__, rect.left, rect.top, rect.width, rect.height); 907cb7a01acSMauro Carvalho Chehab 908cb7a01acSMauro Carvalho Chehab /* tvp5150 has some special limits */ 909cb7a01acSMauro Carvalho Chehab rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); 910cb7a01acSMauro Carvalho Chehab rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); 911cb7a01acSMauro Carvalho Chehab 912cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 913cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 914cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 915cb7a01acSMauro Carvalho Chehab else 916cb7a01acSMauro Carvalho Chehab std = decoder->norm; 917cb7a01acSMauro Carvalho Chehab 918cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 919cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_525_60; 920cb7a01acSMauro Carvalho Chehab else 921cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_OTHERS; 922cb7a01acSMauro Carvalho Chehab 923bd24db04SMarco Felsch /* 924bd24db04SMarco Felsch * alignments: 925bd24db04SMarco Felsch * - width = 2 due to UYVY colorspace 926bd24db04SMarco Felsch * - height, image = no special alignment 927bd24db04SMarco Felsch */ 928bd24db04SMarco Felsch v4l_bound_align_image(&rect.width, 929bd24db04SMarco Felsch TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, 930bd24db04SMarco Felsch TVP5150_H_MAX - rect.left, 1, &rect.height, 931cb7a01acSMauro Carvalho Chehab hmax - TVP5150_MAX_CROP_TOP - rect.top, 932bd24db04SMarco Felsch hmax - rect.top, 0, 0); 933cb7a01acSMauro Carvalho Chehab 934cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); 935cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 936cb7a01acSMauro Carvalho Chehab rect.top + rect.height - hmax); 937cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB, 938cb7a01acSMauro Carvalho Chehab rect.left >> TVP5150_CROP_SHIFT); 939cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB, 940cb7a01acSMauro Carvalho Chehab rect.left | (1 << TVP5150_CROP_SHIFT)); 941cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB, 942cb7a01acSMauro Carvalho Chehab (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> 943cb7a01acSMauro Carvalho Chehab TVP5150_CROP_SHIFT); 944cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB, 945cb7a01acSMauro Carvalho Chehab rect.left + rect.width - TVP5150_MAX_CROP_LEFT); 946cb7a01acSMauro Carvalho Chehab 947cb7a01acSMauro Carvalho Chehab decoder->rect = rect; 948cb7a01acSMauro Carvalho Chehab 949cb7a01acSMauro Carvalho Chehab return 0; 950cb7a01acSMauro Carvalho Chehab } 951cb7a01acSMauro Carvalho Chehab 95210d5509cSHans Verkuil static int tvp5150_get_selection(struct v4l2_subdev *sd, 95310d5509cSHans Verkuil struct v4l2_subdev_pad_config *cfg, 95410d5509cSHans Verkuil struct v4l2_subdev_selection *sel) 955cb7a01acSMauro Carvalho Chehab { 95610d5509cSHans Verkuil struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); 957cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 958cb7a01acSMauro Carvalho Chehab 95910d5509cSHans Verkuil if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 960cb7a01acSMauro Carvalho Chehab return -EINVAL; 961cb7a01acSMauro Carvalho Chehab 96210d5509cSHans Verkuil switch (sel->target) { 96310d5509cSHans Verkuil case V4L2_SEL_TGT_CROP_BOUNDS: 96410d5509cSHans Verkuil case V4L2_SEL_TGT_CROP_DEFAULT: 96510d5509cSHans Verkuil sel->r.left = 0; 96610d5509cSHans Verkuil sel->r.top = 0; 96710d5509cSHans Verkuil sel->r.width = TVP5150_H_MAX; 968cb7a01acSMauro Carvalho Chehab 969cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 970cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 971cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 972cb7a01acSMauro Carvalho Chehab else 973cb7a01acSMauro Carvalho Chehab std = decoder->norm; 974cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 97510d5509cSHans Verkuil sel->r.height = TVP5150_V_MAX_525_60; 976cb7a01acSMauro Carvalho Chehab else 97710d5509cSHans Verkuil sel->r.height = TVP5150_V_MAX_OTHERS; 978cb7a01acSMauro Carvalho Chehab return 0; 97910d5509cSHans Verkuil case V4L2_SEL_TGT_CROP: 98010d5509cSHans Verkuil sel->r = decoder->rect; 98110d5509cSHans Verkuil return 0; 98210d5509cSHans Verkuil default: 98310d5509cSHans Verkuil return -EINVAL; 98410d5509cSHans Verkuil } 985cb7a01acSMauro Carvalho Chehab } 986cb7a01acSMauro Carvalho Chehab 987dd3a46bbSLaurent Pinchart static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, 988dd3a46bbSLaurent Pinchart struct v4l2_mbus_config *cfg) 989dd3a46bbSLaurent Pinchart { 990a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 991a2e5f1b3SJavier Martinez Canillas 992a2e5f1b3SJavier Martinez Canillas cfg->type = decoder->mbus_type; 993dd3a46bbSLaurent Pinchart cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING 994dd3a46bbSLaurent Pinchart | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; 995dd3a46bbSLaurent Pinchart 996dd3a46bbSLaurent Pinchart return 0; 997dd3a46bbSLaurent Pinchart } 998dd3a46bbSLaurent Pinchart 999cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1000e545ac87SLaurent Pinchart V4L2 subdev pad ops 1001e545ac87SLaurent Pinchart ****************************************************************************/ 1002e545ac87SLaurent Pinchart static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, 1003e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 1004e545ac87SLaurent Pinchart struct v4l2_subdev_mbus_code_enum *code) 1005e545ac87SLaurent Pinchart { 1006e545ac87SLaurent Pinchart if (code->pad || code->index) 1007e545ac87SLaurent Pinchart return -EINVAL; 1008e545ac87SLaurent Pinchart 1009e545ac87SLaurent Pinchart code->code = MEDIA_BUS_FMT_UYVY8_2X8; 1010e545ac87SLaurent Pinchart return 0; 1011e545ac87SLaurent Pinchart } 1012e545ac87SLaurent Pinchart 1013e545ac87SLaurent Pinchart static int tvp5150_enum_frame_size(struct v4l2_subdev *sd, 1014e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 1015e545ac87SLaurent Pinchart struct v4l2_subdev_frame_size_enum *fse) 1016e545ac87SLaurent Pinchart { 1017e545ac87SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 1018e545ac87SLaurent Pinchart 1019e545ac87SLaurent Pinchart if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_UYVY8_2X8) 1020e545ac87SLaurent Pinchart return -EINVAL; 1021e545ac87SLaurent Pinchart 1022e545ac87SLaurent Pinchart fse->code = MEDIA_BUS_FMT_UYVY8_2X8; 1023e545ac87SLaurent Pinchart fse->min_width = decoder->rect.width; 1024e545ac87SLaurent Pinchart fse->max_width = decoder->rect.width; 1025e545ac87SLaurent Pinchart fse->min_height = decoder->rect.height / 2; 1026e545ac87SLaurent Pinchart fse->max_height = decoder->rect.height / 2; 1027e545ac87SLaurent Pinchart 1028e545ac87SLaurent Pinchart return 0; 1029e545ac87SLaurent Pinchart } 1030e545ac87SLaurent Pinchart 1031e545ac87SLaurent Pinchart /**************************************************************************** 1032f7b4b54eSJavier Martinez Canillas Media entity ops 1033f7b4b54eSJavier Martinez Canillas ****************************************************************************/ 1034f7b4b54eSJavier Martinez Canillas 1035406ff67dSLaurent Pinchart #ifdef CONFIG_MEDIA_CONTROLLER 1036f7b4b54eSJavier Martinez Canillas static int tvp5150_link_setup(struct media_entity *entity, 1037f7b4b54eSJavier Martinez Canillas const struct media_pad *local, 1038f7b4b54eSJavier Martinez Canillas const struct media_pad *remote, u32 flags) 1039f7b4b54eSJavier Martinez Canillas { 1040f7b4b54eSJavier Martinez Canillas struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 1041f7b4b54eSJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1042f7b4b54eSJavier Martinez Canillas int i; 1043f7b4b54eSJavier Martinez Canillas 1044f7b4b54eSJavier Martinez Canillas for (i = 0; i < TVP5150_INPUT_NUM; i++) { 1045f7b4b54eSJavier Martinez Canillas if (remote->entity == &decoder->input_ent[i]) 1046f7b4b54eSJavier Martinez Canillas break; 1047f7b4b54eSJavier Martinez Canillas } 1048f7b4b54eSJavier Martinez Canillas 1049f7b4b54eSJavier Martinez Canillas /* Do nothing for entities that are not input connectors */ 1050f7b4b54eSJavier Martinez Canillas if (i == TVP5150_INPUT_NUM) 1051f7b4b54eSJavier Martinez Canillas return 0; 1052f7b4b54eSJavier Martinez Canillas 1053f7b4b54eSJavier Martinez Canillas decoder->input = i; 1054f7b4b54eSJavier Martinez Canillas 1055f7b4b54eSJavier Martinez Canillas tvp5150_selmux(sd); 1056f7b4b54eSJavier Martinez Canillas 1057f7b4b54eSJavier Martinez Canillas return 0; 1058f7b4b54eSJavier Martinez Canillas } 1059f7b4b54eSJavier Martinez Canillas 1060f7b4b54eSJavier Martinez Canillas static const struct media_entity_operations tvp5150_sd_media_ops = { 1061f7b4b54eSJavier Martinez Canillas .link_setup = tvp5150_link_setup, 1062f7b4b54eSJavier Martinez Canillas }; 1063406ff67dSLaurent Pinchart #endif 1064f7b4b54eSJavier Martinez Canillas 1065f7b4b54eSJavier Martinez Canillas /**************************************************************************** 1066cb7a01acSMauro Carvalho Chehab I2C Command 1067cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1068cb7a01acSMauro Carvalho Chehab 1069460b6c08SLaurent Pinchart static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) 1070460b6c08SLaurent Pinchart { 1071a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 107279d6205aSLaurent Pinchart int val; 1073a2e5f1b3SJavier Martinez Canillas 107479d6205aSLaurent Pinchart /* Enable or disable the video output signals. */ 107579d6205aSLaurent Pinchart val = tvp5150_read(sd, TVP5150_MISC_CTL); 107679d6205aSLaurent Pinchart if (val < 0) 107779d6205aSLaurent Pinchart return val; 107879d6205aSLaurent Pinchart 107979d6205aSLaurent Pinchart val &= ~(TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE | 108079d6205aSLaurent Pinchart TVP5150_MISC_CTL_CLOCK_OE); 108179d6205aSLaurent Pinchart 108279d6205aSLaurent Pinchart if (enable) { 108379d6205aSLaurent Pinchart /* 108479d6205aSLaurent Pinchart * Enable the YCbCr and clock outputs. In discrete sync mode 108579d6205aSLaurent Pinchart * (non-BT.656) additionally enable the the sync outputs. 108679d6205aSLaurent Pinchart */ 108779d6205aSLaurent Pinchart val |= TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_CLOCK_OE; 1088841502d7SMauro Carvalho Chehab if (decoder->mbus_type == V4L2_MBUS_PARALLEL) 108979d6205aSLaurent Pinchart val |= TVP5150_MISC_CTL_SYNC_OE; 109079d6205aSLaurent Pinchart } 1091a2e5f1b3SJavier Martinez Canillas 1092841502d7SMauro Carvalho Chehab tvp5150_write(sd, TVP5150_MISC_CTL, val); 1093460b6c08SLaurent Pinchart 1094460b6c08SLaurent Pinchart return 0; 1095460b6c08SLaurent Pinchart } 1096460b6c08SLaurent Pinchart 1097cb7a01acSMauro Carvalho Chehab static int tvp5150_s_routing(struct v4l2_subdev *sd, 1098cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 1099cb7a01acSMauro Carvalho Chehab { 1100cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1101cb7a01acSMauro Carvalho Chehab 1102cb7a01acSMauro Carvalho Chehab decoder->input = input; 1103cb7a01acSMauro Carvalho Chehab decoder->output = output; 1104c43875f6SMauro Carvalho Chehab 1105c43875f6SMauro Carvalho Chehab if (output == TVP5150_BLACK_SCREEN) 1106c43875f6SMauro Carvalho Chehab decoder->enable = false; 1107c43875f6SMauro Carvalho Chehab else 1108c43875f6SMauro Carvalho Chehab decoder->enable = true; 1109c43875f6SMauro Carvalho Chehab 1110cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 1111cb7a01acSMauro Carvalho Chehab return 0; 1112cb7a01acSMauro Carvalho Chehab } 1113cb7a01acSMauro Carvalho Chehab 1114cb7a01acSMauro Carvalho Chehab static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) 1115cb7a01acSMauro Carvalho Chehab { 11169bfd8f88SNasser Afshin /* 11179bfd8f88SNasser Afshin * this is for capturing 36 raw vbi lines 11189bfd8f88SNasser Afshin * if there's a way to cut off the beginning 2 vbi lines 11199bfd8f88SNasser Afshin * with the tvp5150 then the vbi line count could be lowered 11209bfd8f88SNasser Afshin * to 17 lines/field again, although I couldn't find a register 11219bfd8f88SNasser Afshin * which could do that cropping 11229bfd8f88SNasser Afshin */ 11239bfd8f88SNasser Afshin 1124cb7a01acSMauro Carvalho Chehab if (fmt->sample_format == V4L2_PIX_FMT_GREY) 1125cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70); 1126cb7a01acSMauro Carvalho Chehab if (fmt->count[0] == 18 && fmt->count[1] == 18) { 1127cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00); 1128cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01); 1129cb7a01acSMauro Carvalho Chehab } 1130cb7a01acSMauro Carvalho Chehab return 0; 1131cb7a01acSMauro Carvalho Chehab } 1132cb7a01acSMauro Carvalho Chehab 1133cb7a01acSMauro Carvalho Chehab static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1134cb7a01acSMauro Carvalho Chehab { 1135cb7a01acSMauro Carvalho Chehab int i; 1136cb7a01acSMauro Carvalho Chehab 1137cb7a01acSMauro Carvalho Chehab if (svbi->service_set != 0) { 1138cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1139cb7a01acSMauro Carvalho Chehab svbi->service_lines[1][i] = 0; 1140cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 11413dd6b560SMauro Carvalho Chehab tvp5150_set_vbi(sd, svbi->service_lines[0][i], 11423dd6b560SMauro Carvalho Chehab 0xf0, i, 3); 1143cb7a01acSMauro Carvalho Chehab } 1144cb7a01acSMauro Carvalho Chehab /* Enables FIFO */ 1145cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1); 1146cb7a01acSMauro Carvalho Chehab } else { 1147cb7a01acSMauro Carvalho Chehab /* Disables FIFO*/ 1148cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0); 1149cb7a01acSMauro Carvalho Chehab 1150cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 1151cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); 1152cb7a01acSMauro Carvalho Chehab 1153cb7a01acSMauro Carvalho Chehab /* Disable Line modes */ 1154cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 1155cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, i, 0xff); 1156cb7a01acSMauro Carvalho Chehab } 1157cb7a01acSMauro Carvalho Chehab return 0; 1158cb7a01acSMauro Carvalho Chehab } 1159cb7a01acSMauro Carvalho Chehab 1160cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1161cb7a01acSMauro Carvalho Chehab { 1162cb7a01acSMauro Carvalho Chehab int i, mask = 0; 1163cb7a01acSMauro Carvalho Chehab 116430634e8eSHans Verkuil memset(svbi->service_lines, 0, sizeof(svbi->service_lines)); 1165cb7a01acSMauro Carvalho Chehab 1166cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1167cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 11683dd6b560SMauro Carvalho Chehab tvp5150_get_vbi(sd, i); 1169cb7a01acSMauro Carvalho Chehab mask |= svbi->service_lines[0][i]; 1170cb7a01acSMauro Carvalho Chehab } 1171cb7a01acSMauro Carvalho Chehab svbi->service_set = mask; 1172cb7a01acSMauro Carvalho Chehab return 0; 1173cb7a01acSMauro Carvalho Chehab } 1174cb7a01acSMauro Carvalho Chehab 1175cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1176cb7a01acSMauro Carvalho Chehab static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 1177cb7a01acSMauro Carvalho Chehab { 1178cb7a01acSMauro Carvalho Chehab int res; 1179cb7a01acSMauro Carvalho Chehab 1180cb7a01acSMauro Carvalho Chehab res = tvp5150_read(sd, reg->reg & 0xff); 1181cb7a01acSMauro Carvalho Chehab if (res < 0) { 1182257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "%s: failed with error = %d\n", __func__, res); 1183cb7a01acSMauro Carvalho Chehab return res; 1184cb7a01acSMauro Carvalho Chehab } 1185cb7a01acSMauro Carvalho Chehab 1186cb7a01acSMauro Carvalho Chehab reg->val = res; 1187cb7a01acSMauro Carvalho Chehab reg->size = 1; 1188cb7a01acSMauro Carvalho Chehab return 0; 1189cb7a01acSMauro Carvalho Chehab } 1190cb7a01acSMauro Carvalho Chehab 1191977ba3b1SHans Verkuil static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 1192cb7a01acSMauro Carvalho Chehab { 1193eca4ca84SJavier Martinez Canillas return tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); 1194cb7a01acSMauro Carvalho Chehab } 1195cb7a01acSMauro Carvalho Chehab #endif 1196cb7a01acSMauro Carvalho Chehab 1197cb7a01acSMauro Carvalho Chehab static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) 1198cb7a01acSMauro Carvalho Chehab { 1199cb7a01acSMauro Carvalho Chehab int status = tvp5150_read(sd, 0x88); 1200cb7a01acSMauro Carvalho Chehab 1201cb7a01acSMauro Carvalho Chehab vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0; 1202cb7a01acSMauro Carvalho Chehab return 0; 1203cb7a01acSMauro Carvalho Chehab } 1204cb7a01acSMauro Carvalho Chehab 12055a08bc00SJavier Martinez Canillas static int tvp5150_registered(struct v4l2_subdev *sd) 1206f7b4b54eSJavier Martinez Canillas { 1207f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1208f7b4b54eSJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1209f7b4b54eSJavier Martinez Canillas int ret = 0; 1210f7b4b54eSJavier Martinez Canillas int i; 1211f7b4b54eSJavier Martinez Canillas 1212f7b4b54eSJavier Martinez Canillas for (i = 0; i < TVP5150_INPUT_NUM; i++) { 1213f7b4b54eSJavier Martinez Canillas struct media_entity *input = &decoder->input_ent[i]; 1214f7b4b54eSJavier Martinez Canillas struct media_pad *pad = &decoder->input_pad[i]; 1215f7b4b54eSJavier Martinez Canillas 1216f7b4b54eSJavier Martinez Canillas if (!input->name) 1217f7b4b54eSJavier Martinez Canillas continue; 1218f7b4b54eSJavier Martinez Canillas 1219f7b4b54eSJavier Martinez Canillas decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE; 1220f7b4b54eSJavier Martinez Canillas 1221f7b4b54eSJavier Martinez Canillas ret = media_entity_pads_init(input, 1, pad); 1222f7b4b54eSJavier Martinez Canillas if (ret < 0) 1223f7b4b54eSJavier Martinez Canillas return ret; 1224f7b4b54eSJavier Martinez Canillas 1225f7b4b54eSJavier Martinez Canillas ret = media_device_register_entity(sd->v4l2_dev->mdev, input); 1226f7b4b54eSJavier Martinez Canillas if (ret < 0) 1227f7b4b54eSJavier Martinez Canillas return ret; 1228f7b4b54eSJavier Martinez Canillas 1229f7b4b54eSJavier Martinez Canillas ret = media_create_pad_link(input, 0, &sd->entity, 1230bc322c0dSMauro Carvalho Chehab TVP5150_PAD_IF_INPUT, 0); 1231f7b4b54eSJavier Martinez Canillas if (ret < 0) { 1232f7b4b54eSJavier Martinez Canillas media_device_unregister_entity(input); 1233f7b4b54eSJavier Martinez Canillas return ret; 1234f7b4b54eSJavier Martinez Canillas } 1235f7b4b54eSJavier Martinez Canillas } 1236f7b4b54eSJavier Martinez Canillas #endif 1237f7b4b54eSJavier Martinez Canillas 1238f7b4b54eSJavier Martinez Canillas return 0; 1239f7b4b54eSJavier Martinez Canillas } 1240f7b4b54eSJavier Martinez Canillas 1241cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1242cb7a01acSMauro Carvalho Chehab 1243cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { 1244cb7a01acSMauro Carvalho Chehab .s_ctrl = tvp5150_s_ctrl, 1245cb7a01acSMauro Carvalho Chehab }; 1246cb7a01acSMauro Carvalho Chehab 1247cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tvp5150_core_ops = { 1248cb7a01acSMauro Carvalho Chehab .log_status = tvp5150_log_status, 1249cb7a01acSMauro Carvalho Chehab .reset = tvp5150_reset, 1250cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1251cb7a01acSMauro Carvalho Chehab .g_register = tvp5150_g_register, 1252cb7a01acSMauro Carvalho Chehab .s_register = tvp5150_s_register, 1253cb7a01acSMauro Carvalho Chehab #endif 1254cb7a01acSMauro Carvalho Chehab }; 1255cb7a01acSMauro Carvalho Chehab 1256cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { 1257cb7a01acSMauro Carvalho Chehab .g_tuner = tvp5150_g_tuner, 1258cb7a01acSMauro Carvalho Chehab }; 1259cb7a01acSMauro Carvalho Chehab 1260cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tvp5150_video_ops = { 12618774bed9SLaurent Pinchart .s_std = tvp5150_s_std, 1262460b6c08SLaurent Pinchart .s_stream = tvp5150_s_stream, 1263cb7a01acSMauro Carvalho Chehab .s_routing = tvp5150_s_routing, 1264dd3a46bbSLaurent Pinchart .g_mbus_config = tvp5150_g_mbus_config, 1265cb7a01acSMauro Carvalho Chehab }; 1266cb7a01acSMauro Carvalho Chehab 1267cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { 1268cb7a01acSMauro Carvalho Chehab .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap, 1269cb7a01acSMauro Carvalho Chehab .g_sliced_fmt = tvp5150_g_sliced_fmt, 1270cb7a01acSMauro Carvalho Chehab .s_sliced_fmt = tvp5150_s_sliced_fmt, 1271cb7a01acSMauro Carvalho Chehab .s_raw_fmt = tvp5150_s_raw_fmt, 1272cb7a01acSMauro Carvalho Chehab }; 1273cb7a01acSMauro Carvalho Chehab 1274ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { 1275ebcff5fcSHans Verkuil .enum_mbus_code = tvp5150_enum_mbus_code, 1276e545ac87SLaurent Pinchart .enum_frame_size = tvp5150_enum_frame_size, 1277da298c6dSHans Verkuil .set_fmt = tvp5150_fill_fmt, 1278da298c6dSHans Verkuil .get_fmt = tvp5150_fill_fmt, 127910d5509cSHans Verkuil .get_selection = tvp5150_get_selection, 128010d5509cSHans Verkuil .set_selection = tvp5150_set_selection, 1281ebcff5fcSHans Verkuil }; 1282ebcff5fcSHans Verkuil 1283cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvp5150_ops = { 1284cb7a01acSMauro Carvalho Chehab .core = &tvp5150_core_ops, 1285cb7a01acSMauro Carvalho Chehab .tuner = &tvp5150_tuner_ops, 1286cb7a01acSMauro Carvalho Chehab .video = &tvp5150_video_ops, 1287cb7a01acSMauro Carvalho Chehab .vbi = &tvp5150_vbi_ops, 1288ebcff5fcSHans Verkuil .pad = &tvp5150_pad_ops, 1289cb7a01acSMauro Carvalho Chehab }; 1290cb7a01acSMauro Carvalho Chehab 12915a08bc00SJavier Martinez Canillas static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = { 12925a08bc00SJavier Martinez Canillas .registered = tvp5150_registered, 12935a08bc00SJavier Martinez Canillas }; 12945a08bc00SJavier Martinez Canillas 1295cb7a01acSMauro Carvalho Chehab 1296cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1297cb7a01acSMauro Carvalho Chehab I2C Client & Driver 1298cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1299cb7a01acSMauro Carvalho Chehab 13007871597aSLaurent Pinchart static int tvp5150_detect_version(struct tvp5150 *core) 13017871597aSLaurent Pinchart { 13027871597aSLaurent Pinchart struct v4l2_subdev *sd = &core->sd; 13037871597aSLaurent Pinchart struct i2c_client *c = v4l2_get_subdevdata(sd); 13047871597aSLaurent Pinchart unsigned int i; 13057871597aSLaurent Pinchart u8 regs[4]; 13067871597aSLaurent Pinchart int res; 13077871597aSLaurent Pinchart 13087871597aSLaurent Pinchart /* 13097871597aSLaurent Pinchart * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID, 13107871597aSLaurent Pinchart * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 13117871597aSLaurent Pinchart */ 13127871597aSLaurent Pinchart for (i = 0; i < 4; i++) { 13137871597aSLaurent Pinchart res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i); 13147871597aSLaurent Pinchart if (res < 0) 13157871597aSLaurent Pinchart return res; 13167871597aSLaurent Pinchart regs[i] = res; 13177871597aSLaurent Pinchart } 13187871597aSLaurent Pinchart 131982275133SJavier Martinez Canillas core->dev_id = (regs[0] << 8) | regs[1]; 132082275133SJavier Martinez Canillas core->rom_ver = (regs[2] << 8) | regs[3]; 13217871597aSLaurent Pinchart 1322257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n", 132382275133SJavier Martinez Canillas core->dev_id, regs[2], regs[3], c->addr << 1, 132482275133SJavier Martinez Canillas c->adapter->name); 13257871597aSLaurent Pinchart 132682275133SJavier Martinez Canillas if (core->dev_id == 0x5150 && core->rom_ver == 0x0321) { 1327257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5150a detected.\n"); 132882275133SJavier Martinez Canillas } else if (core->dev_id == 0x5150 && core->rom_ver == 0x0400) { 1329257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5150am1 detected.\n"); 13307871597aSLaurent Pinchart 13317871597aSLaurent Pinchart /* ITU-T BT.656.4 timing */ 13327871597aSLaurent Pinchart tvp5150_write(sd, TVP5150_REV_SELECT, 0); 133382275133SJavier Martinez Canillas } else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) { 1334257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5151 detected.\n"); 13357871597aSLaurent Pinchart } else { 1336257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "*** unknown tvp%04x chip detected.\n", 133782275133SJavier Martinez Canillas core->dev_id); 13387871597aSLaurent Pinchart } 13397871597aSLaurent Pinchart 13407871597aSLaurent Pinchart return 0; 13417871597aSLaurent Pinchart } 13427871597aSLaurent Pinchart 134309aa2609SJavier Martinez Canillas static int tvp5150_init(struct i2c_client *c) 134409aa2609SJavier Martinez Canillas { 134509aa2609SJavier Martinez Canillas struct gpio_desc *pdn_gpio; 134609aa2609SJavier Martinez Canillas struct gpio_desc *reset_gpio; 134709aa2609SJavier Martinez Canillas 134809aa2609SJavier Martinez Canillas pdn_gpio = devm_gpiod_get_optional(&c->dev, "pdn", GPIOD_OUT_HIGH); 134909aa2609SJavier Martinez Canillas if (IS_ERR(pdn_gpio)) 135009aa2609SJavier Martinez Canillas return PTR_ERR(pdn_gpio); 135109aa2609SJavier Martinez Canillas 135209aa2609SJavier Martinez Canillas if (pdn_gpio) { 135309aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(pdn_gpio, 0); 135409aa2609SJavier Martinez Canillas /* Delay time between power supplies active and reset */ 135509aa2609SJavier Martinez Canillas msleep(20); 135609aa2609SJavier Martinez Canillas } 135709aa2609SJavier Martinez Canillas 135809aa2609SJavier Martinez Canillas reset_gpio = devm_gpiod_get_optional(&c->dev, "reset", GPIOD_OUT_HIGH); 135909aa2609SJavier Martinez Canillas if (IS_ERR(reset_gpio)) 136009aa2609SJavier Martinez Canillas return PTR_ERR(reset_gpio); 136109aa2609SJavier Martinez Canillas 136209aa2609SJavier Martinez Canillas if (reset_gpio) { 136309aa2609SJavier Martinez Canillas /* RESETB pulse duration */ 136409aa2609SJavier Martinez Canillas ndelay(500); 136509aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(reset_gpio, 0); 136609aa2609SJavier Martinez Canillas /* Delay time between end of reset to I2C active */ 136709aa2609SJavier Martinez Canillas usleep_range(200, 250); 136809aa2609SJavier Martinez Canillas } 136909aa2609SJavier Martinez Canillas 137009aa2609SJavier Martinez Canillas return 0; 137109aa2609SJavier Martinez Canillas } 137209aa2609SJavier Martinez Canillas 1373a2e5f1b3SJavier Martinez Canillas static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) 1374a2e5f1b3SJavier Martinez Canillas { 1375859969b3SSakari Ailus struct v4l2_fwnode_endpoint bus_cfg; 1376a2e5f1b3SJavier Martinez Canillas struct device_node *ep; 1377f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1378f7b4b54eSJavier Martinez Canillas struct device_node *connectors, *child; 1379f7b4b54eSJavier Martinez Canillas struct media_entity *input; 1380f7b4b54eSJavier Martinez Canillas const char *name; 1381f7b4b54eSJavier Martinez Canillas u32 input_type; 1382f7b4b54eSJavier Martinez Canillas #endif 1383a2e5f1b3SJavier Martinez Canillas unsigned int flags; 1384a2e5f1b3SJavier Martinez Canillas int ret = 0; 1385a2e5f1b3SJavier Martinez Canillas 1386a2e5f1b3SJavier Martinez Canillas ep = of_graph_get_next_endpoint(np, NULL); 1387a2e5f1b3SJavier Martinez Canillas if (!ep) 1388a2e5f1b3SJavier Martinez Canillas return -EINVAL; 1389a2e5f1b3SJavier Martinez Canillas 1390859969b3SSakari Ailus ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); 1391a2e5f1b3SJavier Martinez Canillas if (ret) 1392a2e5f1b3SJavier Martinez Canillas goto err; 1393a2e5f1b3SJavier Martinez Canillas 1394a2e5f1b3SJavier Martinez Canillas flags = bus_cfg.bus.parallel.flags; 1395a2e5f1b3SJavier Martinez Canillas 1396a2e5f1b3SJavier Martinez Canillas if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL && 1397a2e5f1b3SJavier Martinez Canillas !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH && 1398a2e5f1b3SJavier Martinez Canillas flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH && 13992bd5e437SJavier Martinez Canillas flags & V4L2_MBUS_FIELD_EVEN_LOW)) { 14002bd5e437SJavier Martinez Canillas ret = -EINVAL; 14012bd5e437SJavier Martinez Canillas goto err; 14022bd5e437SJavier Martinez Canillas } 1403a2e5f1b3SJavier Martinez Canillas 1404a2e5f1b3SJavier Martinez Canillas decoder->mbus_type = bus_cfg.bus_type; 1405a2e5f1b3SJavier Martinez Canillas 1406f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1407f7b4b54eSJavier Martinez Canillas connectors = of_get_child_by_name(np, "connectors"); 1408f7b4b54eSJavier Martinez Canillas 1409f7b4b54eSJavier Martinez Canillas if (!connectors) 1410f7b4b54eSJavier Martinez Canillas goto err; 1411f7b4b54eSJavier Martinez Canillas 1412f7b4b54eSJavier Martinez Canillas for_each_available_child_of_node(connectors, child) { 1413f7b4b54eSJavier Martinez Canillas ret = of_property_read_u32(child, "input", &input_type); 1414f7b4b54eSJavier Martinez Canillas if (ret) { 1415257e29f8SMauro Carvalho Chehab dev_err(decoder->sd.dev, 1416f764e6d6SRob Herring "missing type property in node %pOFn\n", 1417f764e6d6SRob Herring child); 1418f7b4b54eSJavier Martinez Canillas goto err_connector; 1419f7b4b54eSJavier Martinez Canillas } 1420f7b4b54eSJavier Martinez Canillas 142160ad7689SMauro Carvalho Chehab if (input_type >= TVP5150_INPUT_NUM) { 1422f7b4b54eSJavier Martinez Canillas ret = -EINVAL; 1423f7b4b54eSJavier Martinez Canillas goto err_connector; 1424f7b4b54eSJavier Martinez Canillas } 1425f7b4b54eSJavier Martinez Canillas 1426f7b4b54eSJavier Martinez Canillas input = &decoder->input_ent[input_type]; 1427f7b4b54eSJavier Martinez Canillas 1428f7b4b54eSJavier Martinez Canillas /* Each input connector can only be defined once */ 1429f7b4b54eSJavier Martinez Canillas if (input->name) { 1430257e29f8SMauro Carvalho Chehab dev_err(decoder->sd.dev, 1431f7b4b54eSJavier Martinez Canillas "input %s with same type already exists\n", 1432f7b4b54eSJavier Martinez Canillas input->name); 1433f7b4b54eSJavier Martinez Canillas ret = -EINVAL; 1434f7b4b54eSJavier Martinez Canillas goto err_connector; 1435f7b4b54eSJavier Martinez Canillas } 1436f7b4b54eSJavier Martinez Canillas 1437f7b4b54eSJavier Martinez Canillas switch (input_type) { 1438f7b4b54eSJavier Martinez Canillas case TVP5150_COMPOSITE0: 1439f7b4b54eSJavier Martinez Canillas case TVP5150_COMPOSITE1: 1440f7b4b54eSJavier Martinez Canillas input->function = MEDIA_ENT_F_CONN_COMPOSITE; 1441f7b4b54eSJavier Martinez Canillas break; 1442f7b4b54eSJavier Martinez Canillas case TVP5150_SVIDEO: 1443f7b4b54eSJavier Martinez Canillas input->function = MEDIA_ENT_F_CONN_SVIDEO; 1444f7b4b54eSJavier Martinez Canillas break; 1445f7b4b54eSJavier Martinez Canillas } 1446f7b4b54eSJavier Martinez Canillas 1447f7b4b54eSJavier Martinez Canillas input->flags = MEDIA_ENT_FL_CONNECTOR; 1448f7b4b54eSJavier Martinez Canillas 1449f7b4b54eSJavier Martinez Canillas ret = of_property_read_string(child, "label", &name); 1450f7b4b54eSJavier Martinez Canillas if (ret < 0) { 1451257e29f8SMauro Carvalho Chehab dev_err(decoder->sd.dev, 1452f764e6d6SRob Herring "missing label property in node %pOFn\n", 1453f764e6d6SRob Herring child); 1454f7b4b54eSJavier Martinez Canillas goto err_connector; 1455f7b4b54eSJavier Martinez Canillas } 1456f7b4b54eSJavier Martinez Canillas 1457f7b4b54eSJavier Martinez Canillas input->name = name; 1458f7b4b54eSJavier Martinez Canillas } 1459f7b4b54eSJavier Martinez Canillas 1460f7b4b54eSJavier Martinez Canillas err_connector: 1461f7b4b54eSJavier Martinez Canillas of_node_put(connectors); 1462f7b4b54eSJavier Martinez Canillas #endif 1463a2e5f1b3SJavier Martinez Canillas err: 1464a2e5f1b3SJavier Martinez Canillas of_node_put(ep); 1465a2e5f1b3SJavier Martinez Canillas return ret; 1466a2e5f1b3SJavier Martinez Canillas } 1467a2e5f1b3SJavier Martinez Canillas 1468c43875f6SMauro Carvalho Chehab static const char * const tvp5150_test_patterns[2] = { 1469c43875f6SMauro Carvalho Chehab "Disabled", 1470c43875f6SMauro Carvalho Chehab "Black screen" 1471c43875f6SMauro Carvalho Chehab }; 1472c43875f6SMauro Carvalho Chehab 1473cb7a01acSMauro Carvalho Chehab static int tvp5150_probe(struct i2c_client *c, 1474cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1475cb7a01acSMauro Carvalho Chehab { 1476cb7a01acSMauro Carvalho Chehab struct tvp5150 *core; 1477cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 1478a2e5f1b3SJavier Martinez Canillas struct device_node *np = c->dev.of_node; 14797871597aSLaurent Pinchart int res; 1480cb7a01acSMauro Carvalho Chehab 1481cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1482cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(c->adapter, 1483cb7a01acSMauro Carvalho Chehab I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 1484cb7a01acSMauro Carvalho Chehab return -EIO; 1485cb7a01acSMauro Carvalho Chehab 148609aa2609SJavier Martinez Canillas res = tvp5150_init(c); 148709aa2609SJavier Martinez Canillas if (res) 148809aa2609SJavier Martinez Canillas return res; 148909aa2609SJavier Martinez Canillas 1490c02b211dSLaurent Pinchart core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL); 1491c02b211dSLaurent Pinchart if (!core) 1492cb7a01acSMauro Carvalho Chehab return -ENOMEM; 1493a2e5f1b3SJavier Martinez Canillas 1494cb7a01acSMauro Carvalho Chehab sd = &core->sd; 1495a2e5f1b3SJavier Martinez Canillas 1496a2e5f1b3SJavier Martinez Canillas if (IS_ENABLED(CONFIG_OF) && np) { 1497a2e5f1b3SJavier Martinez Canillas res = tvp5150_parse_dt(core, np); 1498a2e5f1b3SJavier Martinez Canillas if (res) { 1499257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "DT parsing error: %d\n", res); 1500a2e5f1b3SJavier Martinez Canillas return res; 1501a2e5f1b3SJavier Martinez Canillas } 1502a2e5f1b3SJavier Martinez Canillas } else { 1503a2e5f1b3SJavier Martinez Canillas /* Default to BT.656 embedded sync */ 1504a2e5f1b3SJavier Martinez Canillas core->mbus_type = V4L2_MBUS_BT656; 1505a2e5f1b3SJavier Martinez Canillas } 1506a2e5f1b3SJavier Martinez Canillas 1507cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); 15085a08bc00SJavier Martinez Canillas sd->internal_ops = &tvp5150_internal_ops; 1509e545ac87SLaurent Pinchart sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1510e545ac87SLaurent Pinchart 1511e545ac87SLaurent Pinchart #if defined(CONFIG_MEDIA_CONTROLLER) 1512bc322c0dSMauro Carvalho Chehab core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; 1513bc322c0dSMauro Carvalho Chehab core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG; 1514bc322c0dSMauro Carvalho Chehab core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; 1515bc322c0dSMauro Carvalho Chehab core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV; 1516f92c70adSMauro Carvalho Chehab 1517f92c70adSMauro Carvalho Chehab sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 1518f92c70adSMauro Carvalho Chehab 1519bc322c0dSMauro Carvalho Chehab res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads); 1520e545ac87SLaurent Pinchart if (res < 0) 1521e545ac87SLaurent Pinchart return res; 1522f7b4b54eSJavier Martinez Canillas 1523f7b4b54eSJavier Martinez Canillas sd->entity.ops = &tvp5150_sd_media_ops; 1524e545ac87SLaurent Pinchart #endif 1525cb7a01acSMauro Carvalho Chehab 15267871597aSLaurent Pinchart res = tvp5150_detect_version(core); 1527cb7a01acSMauro Carvalho Chehab if (res < 0) 1528c02b211dSLaurent Pinchart return res; 1529cb7a01acSMauro Carvalho Chehab 1530cb7a01acSMauro Carvalho Chehab core->norm = V4L2_STD_ALL; /* Default is autodetect */ 1531cb7a01acSMauro Carvalho Chehab core->input = TVP5150_COMPOSITE1; 1532c43875f6SMauro Carvalho Chehab core->enable = true; 1533cb7a01acSMauro Carvalho Chehab 1534b1950b8dSLaurent Pinchart v4l2_ctrl_handler_init(&core->hdl, 5); 1535cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1536cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 1537cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1538cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 255, 1, 128); 1539cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1540cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, 0, 255, 1, 128); 1541cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1542cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, -128, 127, 1, 0); 1543b1950b8dSLaurent Pinchart v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1544b1950b8dSLaurent Pinchart V4L2_CID_PIXEL_RATE, 27000000, 1545b1950b8dSLaurent Pinchart 27000000, 1, 27000000); 1546c43875f6SMauro Carvalho Chehab v4l2_ctrl_new_std_menu_items(&core->hdl, &tvp5150_ctrl_ops, 1547c43875f6SMauro Carvalho Chehab V4L2_CID_TEST_PATTERN, 15485c4c4505SMauro Carvalho Chehab ARRAY_SIZE(tvp5150_test_patterns) - 1, 1549c43875f6SMauro Carvalho Chehab 0, 0, tvp5150_test_patterns); 1550cb7a01acSMauro Carvalho Chehab sd->ctrl_handler = &core->hdl; 1551cb7a01acSMauro Carvalho Chehab if (core->hdl.error) { 1552cb7a01acSMauro Carvalho Chehab res = core->hdl.error; 1553c7d97499SJavier Martinez Canillas goto err; 1554cb7a01acSMauro Carvalho Chehab } 1555cb7a01acSMauro Carvalho Chehab 1556cb7a01acSMauro Carvalho Chehab /* Default is no cropping */ 1557cb7a01acSMauro Carvalho Chehab core->rect.top = 0; 1558cb7a01acSMauro Carvalho Chehab if (tvp5150_read_std(sd) & V4L2_STD_525_60) 1559cb7a01acSMauro Carvalho Chehab core->rect.height = TVP5150_V_MAX_525_60; 1560cb7a01acSMauro Carvalho Chehab else 1561cb7a01acSMauro Carvalho Chehab core->rect.height = TVP5150_V_MAX_OTHERS; 1562cb7a01acSMauro Carvalho Chehab core->rect.left = 0; 1563cb7a01acSMauro Carvalho Chehab core->rect.width = TVP5150_H_MAX; 1564cb7a01acSMauro Carvalho Chehab 1565aff808e8SLaurent Pinchart tvp5150_reset(sd, 0); /* Calls v4l2_ctrl_handler_setup() */ 1566aff808e8SLaurent Pinchart 1567c7d97499SJavier Martinez Canillas res = v4l2_async_register_subdev(sd); 1568c7d97499SJavier Martinez Canillas if (res < 0) 1569c7d97499SJavier Martinez Canillas goto err; 1570c7d97499SJavier Martinez Canillas 1571cb7a01acSMauro Carvalho Chehab if (debug > 1) 1572cb7a01acSMauro Carvalho Chehab tvp5150_log_status(sd); 1573cb7a01acSMauro Carvalho Chehab return 0; 1574c7d97499SJavier Martinez Canillas 1575c7d97499SJavier Martinez Canillas err: 1576c7d97499SJavier Martinez Canillas v4l2_ctrl_handler_free(&core->hdl); 1577c7d97499SJavier Martinez Canillas return res; 1578cb7a01acSMauro Carvalho Chehab } 1579cb7a01acSMauro Carvalho Chehab 1580cb7a01acSMauro Carvalho Chehab static int tvp5150_remove(struct i2c_client *c) 1581cb7a01acSMauro Carvalho Chehab { 1582cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(c); 1583cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1584cb7a01acSMauro Carvalho Chehab 1585257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, 1586cb7a01acSMauro Carvalho Chehab "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", 1587cb7a01acSMauro Carvalho Chehab c->addr << 1); 1588cb7a01acSMauro Carvalho Chehab 1589c7d97499SJavier Martinez Canillas v4l2_async_unregister_subdev(sd); 1590cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&decoder->hdl); 1591cb7a01acSMauro Carvalho Chehab return 0; 1592cb7a01acSMauro Carvalho Chehab } 1593cb7a01acSMauro Carvalho Chehab 1594cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1595cb7a01acSMauro Carvalho Chehab 1596cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvp5150_id[] = { 1597cb7a01acSMauro Carvalho Chehab { "tvp5150", 0 }, 1598cb7a01acSMauro Carvalho Chehab { } 1599cb7a01acSMauro Carvalho Chehab }; 1600cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvp5150_id); 1601cb7a01acSMauro Carvalho Chehab 16027ef930a7SEduard Gavin #if IS_ENABLED(CONFIG_OF) 16037ef930a7SEduard Gavin static const struct of_device_id tvp5150_of_match[] = { 16047ef930a7SEduard Gavin { .compatible = "ti,tvp5150", }, 16057ef930a7SEduard Gavin { /* sentinel */ }, 16067ef930a7SEduard Gavin }; 16077ef930a7SEduard Gavin MODULE_DEVICE_TABLE(of, tvp5150_of_match); 16087ef930a7SEduard Gavin #endif 16097ef930a7SEduard Gavin 1610cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvp5150_driver = { 1611cb7a01acSMauro Carvalho Chehab .driver = { 16127ef930a7SEduard Gavin .of_match_table = of_match_ptr(tvp5150_of_match), 1613cb7a01acSMauro Carvalho Chehab .name = "tvp5150", 1614cb7a01acSMauro Carvalho Chehab }, 1615cb7a01acSMauro Carvalho Chehab .probe = tvp5150_probe, 1616cb7a01acSMauro Carvalho Chehab .remove = tvp5150_remove, 1617cb7a01acSMauro Carvalho Chehab .id_table = tvp5150_id, 1618cb7a01acSMauro Carvalho Chehab }; 1619cb7a01acSMauro Carvalho Chehab 1620cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvp5150_driver); 1621