1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver 3cb7a01acSMauro Carvalho Chehab * 4cb7a01acSMauro Carvalho Chehab * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org) 5cb7a01acSMauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License v2 6cb7a01acSMauro Carvalho Chehab */ 7cb7a01acSMauro Carvalho Chehab 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> 14c7d97499SJavier Martinez Canillas #include <media/v4l2-async.h> 15cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 16b5dcee22SMauro Carvalho Chehab #include <media/i2c/tvp5150.h> 17cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 18a2e5f1b3SJavier Martinez Canillas #include <media/v4l2-of.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 30cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); 31cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab"); 32cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 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 39cb7a01acSMauro Carvalho Chehab struct tvp5150 { 40cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 4155606310SMauro Carvalho Chehab #ifdef CONFIG_MEDIA_CONTROLLER 4255606310SMauro Carvalho Chehab struct media_pad pads[DEMOD_NUM_PADS]; 4355606310SMauro Carvalho Chehab #endif 44cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler hdl; 45cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect; 46cb7a01acSMauro Carvalho Chehab 47cb7a01acSMauro Carvalho Chehab v4l2_std_id norm; /* Current set standard */ 48cb7a01acSMauro Carvalho Chehab u32 input; 49cb7a01acSMauro Carvalho Chehab u32 output; 50cb7a01acSMauro Carvalho Chehab int enable; 51a2e5f1b3SJavier Martinez Canillas 52a2e5f1b3SJavier Martinez Canillas enum v4l2_mbus_type mbus_type; 53cb7a01acSMauro Carvalho Chehab }; 54cb7a01acSMauro Carvalho Chehab 55cb7a01acSMauro Carvalho Chehab static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) 56cb7a01acSMauro Carvalho Chehab { 57cb7a01acSMauro Carvalho Chehab return container_of(sd, struct tvp5150, sd); 58cb7a01acSMauro Carvalho Chehab } 59cb7a01acSMauro Carvalho Chehab 60cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 61cb7a01acSMauro Carvalho Chehab { 62cb7a01acSMauro Carvalho Chehab return &container_of(ctrl->handler, struct tvp5150, hdl)->sd; 63cb7a01acSMauro Carvalho Chehab } 64cb7a01acSMauro Carvalho Chehab 65cb7a01acSMauro Carvalho Chehab static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) 66cb7a01acSMauro Carvalho Chehab { 67cb7a01acSMauro Carvalho Chehab struct i2c_client *c = v4l2_get_subdevdata(sd); 68cb7a01acSMauro Carvalho Chehab int rc; 69cb7a01acSMauro Carvalho Chehab 70e35ce2e4SLaurent Pinchart rc = i2c_smbus_read_byte_data(c, addr); 71e35ce2e4SLaurent Pinchart if (rc < 0) { 72e35ce2e4SLaurent Pinchart v4l2_err(sd, "i2c i/o error: rc == %d\n", rc); 73e35ce2e4SLaurent Pinchart return rc; 74cb7a01acSMauro Carvalho Chehab } 75cb7a01acSMauro Carvalho Chehab 76e35ce2e4SLaurent Pinchart v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, rc); 77cb7a01acSMauro Carvalho Chehab 78e35ce2e4SLaurent Pinchart return rc; 79cb7a01acSMauro Carvalho Chehab } 80cb7a01acSMauro Carvalho Chehab 81cb7a01acSMauro Carvalho Chehab static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, 82cb7a01acSMauro Carvalho Chehab unsigned char value) 83cb7a01acSMauro Carvalho Chehab { 84cb7a01acSMauro Carvalho Chehab struct i2c_client *c = v4l2_get_subdevdata(sd); 85cb7a01acSMauro Carvalho Chehab int rc; 86cb7a01acSMauro Carvalho Chehab 87e35ce2e4SLaurent Pinchart v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value); 88e35ce2e4SLaurent Pinchart rc = i2c_smbus_write_byte_data(c, addr, value); 89e35ce2e4SLaurent Pinchart if (rc < 0) 90e35ce2e4SLaurent Pinchart v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d\n", rc); 91cb7a01acSMauro Carvalho Chehab } 92cb7a01acSMauro Carvalho Chehab 93cb7a01acSMauro Carvalho Chehab static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, 94cb7a01acSMauro Carvalho Chehab const u8 end, int max_line) 95cb7a01acSMauro Carvalho Chehab { 96cb7a01acSMauro Carvalho Chehab int i = 0; 97cb7a01acSMauro Carvalho Chehab 98cb7a01acSMauro Carvalho Chehab while (init != (u8)(end + 1)) { 99cb7a01acSMauro Carvalho Chehab if ((i % max_line) == 0) { 100cb7a01acSMauro Carvalho Chehab if (i > 0) 101cb7a01acSMauro Carvalho Chehab printk("\n"); 102cb7a01acSMauro Carvalho Chehab printk("tvp5150: %s reg 0x%02x = ", s, init); 103cb7a01acSMauro Carvalho Chehab } 104cb7a01acSMauro Carvalho Chehab printk("%02x ", tvp5150_read(sd, init)); 105cb7a01acSMauro Carvalho Chehab 106cb7a01acSMauro Carvalho Chehab init++; 107cb7a01acSMauro Carvalho Chehab i++; 108cb7a01acSMauro Carvalho Chehab } 109cb7a01acSMauro Carvalho Chehab printk("\n"); 110cb7a01acSMauro Carvalho Chehab } 111cb7a01acSMauro Carvalho Chehab 112cb7a01acSMauro Carvalho Chehab static int tvp5150_log_status(struct v4l2_subdev *sd) 113cb7a01acSMauro Carvalho Chehab { 114cb7a01acSMauro Carvalho Chehab printk("tvp5150: Video input source selection #1 = 0x%02x\n", 115cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); 116cb7a01acSMauro Carvalho Chehab printk("tvp5150: Analog channel controls = 0x%02x\n", 117cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); 118cb7a01acSMauro Carvalho Chehab printk("tvp5150: Operation mode controls = 0x%02x\n", 119cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_OP_MODE_CTL)); 120cb7a01acSMauro Carvalho Chehab printk("tvp5150: Miscellaneous controls = 0x%02x\n", 121cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MISC_CTL)); 122cb7a01acSMauro Carvalho Chehab printk("tvp5150: Autoswitch mask= 0x%02x\n", 123cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_AUTOSW_MSK)); 124cb7a01acSMauro Carvalho Chehab printk("tvp5150: Color killer threshold control = 0x%02x\n", 125cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); 126cb7a01acSMauro Carvalho Chehab printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", 127cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), 128cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), 129cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); 130cb7a01acSMauro Carvalho Chehab printk("tvp5150: Brightness control = 0x%02x\n", 131cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_BRIGHT_CTL)); 132cb7a01acSMauro Carvalho Chehab printk("tvp5150: Color saturation control = 0x%02x\n", 133cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_SATURATION_CTL)); 134cb7a01acSMauro Carvalho Chehab printk("tvp5150: Hue control = 0x%02x\n", 135cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HUE_CTL)); 136cb7a01acSMauro Carvalho Chehab printk("tvp5150: Contrast control = 0x%02x\n", 137cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONTRAST_CTL)); 138cb7a01acSMauro Carvalho Chehab printk("tvp5150: Outputs and data rates select = 0x%02x\n", 139cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); 140cb7a01acSMauro Carvalho Chehab printk("tvp5150: Configuration shared pins = 0x%02x\n", 141cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); 142cb7a01acSMauro Carvalho Chehab printk("tvp5150: Active video cropping start = 0x%02x%02x\n", 143cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), 144cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); 145cb7a01acSMauro Carvalho Chehab printk("tvp5150: Active video cropping stop = 0x%02x%02x\n", 146cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), 147cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); 148cb7a01acSMauro Carvalho Chehab printk("tvp5150: Genlock/RTC = 0x%02x\n", 149cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_GENLOCK)); 150cb7a01acSMauro Carvalho Chehab printk("tvp5150: Horizontal sync start = 0x%02x\n", 151cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); 152cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical blanking start = 0x%02x\n", 153cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); 154cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical blanking stop = 0x%02x\n", 155cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); 156cb7a01acSMauro Carvalho Chehab printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", 157cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), 158cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); 159cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt reset register B = 0x%02x\n", 160cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); 161cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt enable register B = 0x%02x\n", 162cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); 163cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt configuration register B = 0x%02x\n", 164cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); 165cb7a01acSMauro Carvalho Chehab printk("tvp5150: Video standard = 0x%02x\n", 166cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VIDEO_STD)); 167cb7a01acSMauro Carvalho Chehab printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", 168cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CB_GAIN_FACT), 169cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); 170cb7a01acSMauro Carvalho Chehab printk("tvp5150: Macrovision on counter = 0x%02x\n", 171cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); 172cb7a01acSMauro Carvalho Chehab printk("tvp5150: Macrovision off counter = 0x%02x\n", 173cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); 174cb7a01acSMauro Carvalho Chehab printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", 175cb7a01acSMauro Carvalho Chehab (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); 176cb7a01acSMauro Carvalho Chehab printk("tvp5150: Device ID = %02x%02x\n", 177cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MSB_DEV_ID), 178cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LSB_DEV_ID)); 179cb7a01acSMauro Carvalho Chehab printk("tvp5150: ROM version = (hex) %02x.%02x\n", 180cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), 181cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); 182cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical line count = 0x%02x%02x\n", 183cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), 184cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); 185cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt status register B = 0x%02x\n", 186cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); 187cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt active register B = 0x%02x\n", 188cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); 189cb7a01acSMauro Carvalho Chehab printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", 190cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_1), 191cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_2), 192cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_3), 193cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_4), 194cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_5)); 195cb7a01acSMauro Carvalho Chehab 196cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, 197cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL1_END, 8); 198cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, 199cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL2_END, 8); 200cb7a01acSMauro Carvalho Chehab 201cb7a01acSMauro Carvalho Chehab printk("tvp5150: Teletext filter enable = 0x%02x\n", 202cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); 203cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt status register A = 0x%02x\n", 204cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); 205cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt enable register A = 0x%02x\n", 206cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); 207cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt configuration = 0x%02x\n", 208cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_CONF)); 209cb7a01acSMauro Carvalho Chehab printk("tvp5150: VDP status register = 0x%02x\n", 210cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); 211cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO word count = 0x%02x\n", 212cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); 213cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO interrupt threshold = 0x%02x\n", 214cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); 215cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO reset = 0x%02x\n", 216cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_RESET)); 217cb7a01acSMauro Carvalho Chehab printk("tvp5150: Line number interrupt = 0x%02x\n", 218cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); 219cb7a01acSMauro Carvalho Chehab printk("tvp5150: Pixel alignment register = 0x%02x%02x\n", 220cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), 221cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); 222cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO output control = 0x%02x\n", 223cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); 224cb7a01acSMauro Carvalho Chehab printk("tvp5150: Full field enable = 0x%02x\n", 225cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); 226cb7a01acSMauro Carvalho Chehab printk("tvp5150: Full field mode register = 0x%02x\n", 227cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); 228cb7a01acSMauro Carvalho Chehab 229cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI, 230cb7a01acSMauro Carvalho Chehab TVP5150_CC_DATA_END, 8); 231cb7a01acSMauro Carvalho Chehab 232cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "WSS data", TVP5150_WSS_DATA_INI, 233cb7a01acSMauro Carvalho Chehab TVP5150_WSS_DATA_END, 8); 234cb7a01acSMauro Carvalho Chehab 235cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VPS data", TVP5150_VPS_DATA_INI, 236cb7a01acSMauro Carvalho Chehab TVP5150_VPS_DATA_END, 8); 237cb7a01acSMauro Carvalho Chehab 238cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VITC data", TVP5150_VITC_DATA_INI, 239cb7a01acSMauro Carvalho Chehab TVP5150_VITC_DATA_END, 10); 240cb7a01acSMauro Carvalho Chehab 241cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Line mode", TVP5150_LINE_MODE_INI, 242cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_END, 8); 243cb7a01acSMauro Carvalho Chehab return 0; 244cb7a01acSMauro Carvalho Chehab } 245cb7a01acSMauro Carvalho Chehab 246cb7a01acSMauro Carvalho Chehab /**************************************************************************** 247cb7a01acSMauro Carvalho Chehab Basic functions 248cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 249cb7a01acSMauro Carvalho Chehab 250cb7a01acSMauro Carvalho Chehab static inline void tvp5150_selmux(struct v4l2_subdev *sd) 251cb7a01acSMauro Carvalho Chehab { 252cb7a01acSMauro Carvalho Chehab int opmode = 0; 253cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 254cb7a01acSMauro Carvalho Chehab int input = 0; 255cb7a01acSMauro Carvalho Chehab int val; 256cb7a01acSMauro Carvalho Chehab 257cb7a01acSMauro Carvalho Chehab if ((decoder->output & TVP5150_BLACK_SCREEN) || !decoder->enable) 258cb7a01acSMauro Carvalho Chehab input = 8; 259cb7a01acSMauro Carvalho Chehab 260cb7a01acSMauro Carvalho Chehab switch (decoder->input) { 261cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE1: 262cb7a01acSMauro Carvalho Chehab input |= 2; 263cb7a01acSMauro Carvalho Chehab /* fall through */ 264cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE0: 265cb7a01acSMauro Carvalho Chehab break; 266cb7a01acSMauro Carvalho Chehab case TVP5150_SVIDEO: 267cb7a01acSMauro Carvalho Chehab default: 268cb7a01acSMauro Carvalho Chehab input |= 1; 269cb7a01acSMauro Carvalho Chehab break; 270cb7a01acSMauro Carvalho Chehab } 271cb7a01acSMauro Carvalho Chehab 272cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i " 273cb7a01acSMauro Carvalho Chehab "=> tvp5150 input=%i, opmode=%i\n", 274cb7a01acSMauro Carvalho Chehab decoder->input, decoder->output, 275cb7a01acSMauro Carvalho Chehab input, opmode); 276cb7a01acSMauro Carvalho Chehab 277cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode); 278cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input); 279cb7a01acSMauro Carvalho Chehab 280cb7a01acSMauro Carvalho Chehab /* Svideo should enable YCrCb output and disable GPCL output 281cb7a01acSMauro Carvalho Chehab * For Composite and TV, it should be the reverse 282cb7a01acSMauro Carvalho Chehab */ 283cb7a01acSMauro Carvalho Chehab val = tvp5150_read(sd, TVP5150_MISC_CTL); 284cb7a01acSMauro Carvalho Chehab if (val < 0) { 285cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", __func__, val); 286cb7a01acSMauro Carvalho Chehab return; 287cb7a01acSMauro Carvalho Chehab } 288cb7a01acSMauro Carvalho Chehab 289cb7a01acSMauro Carvalho Chehab if (decoder->input == TVP5150_SVIDEO) 290cb7a01acSMauro Carvalho Chehab val = (val & ~0x40) | 0x10; 291cb7a01acSMauro Carvalho Chehab else 292cb7a01acSMauro Carvalho Chehab val = (val & ~0x10) | 0x40; 293cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_MISC_CTL, val); 294cb7a01acSMauro Carvalho Chehab }; 295cb7a01acSMauro Carvalho Chehab 296cb7a01acSMauro Carvalho Chehab struct i2c_reg_value { 297cb7a01acSMauro Carvalho Chehab unsigned char reg; 298cb7a01acSMauro Carvalho Chehab unsigned char value; 299cb7a01acSMauro Carvalho Chehab }; 300cb7a01acSMauro Carvalho Chehab 301cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 302cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_default[] = { 303cb7a01acSMauro Carvalho Chehab { /* 0x00 */ 304cb7a01acSMauro Carvalho Chehab TVP5150_VD_IN_SRC_SEL_1,0x00 305cb7a01acSMauro Carvalho Chehab }, 306cb7a01acSMauro Carvalho Chehab { /* 0x01 */ 307cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL,0x15 308cb7a01acSMauro Carvalho Chehab }, 309cb7a01acSMauro Carvalho Chehab { /* 0x02 */ 310cb7a01acSMauro Carvalho Chehab TVP5150_OP_MODE_CTL,0x00 311cb7a01acSMauro Carvalho Chehab }, 312cb7a01acSMauro Carvalho Chehab { /* 0x03 */ 313cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL,0x01 314cb7a01acSMauro Carvalho Chehab }, 315cb7a01acSMauro Carvalho Chehab { /* 0x06 */ 316cb7a01acSMauro Carvalho Chehab TVP5150_COLOR_KIL_THSH_CTL,0x10 317cb7a01acSMauro Carvalho Chehab }, 318cb7a01acSMauro Carvalho Chehab { /* 0x07 */ 319cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_1,0x60 320cb7a01acSMauro Carvalho Chehab }, 321cb7a01acSMauro Carvalho Chehab { /* 0x08 */ 322cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_2,0x00 323cb7a01acSMauro Carvalho Chehab }, 324cb7a01acSMauro Carvalho Chehab { /* 0x09 */ 325cb7a01acSMauro Carvalho Chehab TVP5150_BRIGHT_CTL,0x80 326cb7a01acSMauro Carvalho Chehab }, 327cb7a01acSMauro Carvalho Chehab { /* 0x0a */ 328cb7a01acSMauro Carvalho Chehab TVP5150_SATURATION_CTL,0x80 329cb7a01acSMauro Carvalho Chehab }, 330cb7a01acSMauro Carvalho Chehab { /* 0x0b */ 331cb7a01acSMauro Carvalho Chehab TVP5150_HUE_CTL,0x00 332cb7a01acSMauro Carvalho Chehab }, 333cb7a01acSMauro Carvalho Chehab { /* 0x0c */ 334cb7a01acSMauro Carvalho Chehab TVP5150_CONTRAST_CTL,0x80 335cb7a01acSMauro Carvalho Chehab }, 336cb7a01acSMauro Carvalho Chehab { /* 0x0d */ 337cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL,0x47 338cb7a01acSMauro Carvalho Chehab }, 339cb7a01acSMauro Carvalho Chehab { /* 0x0e */ 340cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_3,0x00 341cb7a01acSMauro Carvalho Chehab }, 342cb7a01acSMauro Carvalho Chehab { /* 0x0f */ 343cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN,0x08 344cb7a01acSMauro Carvalho Chehab }, 345cb7a01acSMauro Carvalho Chehab { /* 0x11 */ 346cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_MSB,0x00 347cb7a01acSMauro Carvalho Chehab }, 348cb7a01acSMauro Carvalho Chehab { /* 0x12 */ 349cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_LSB,0x00 350cb7a01acSMauro Carvalho Chehab }, 351cb7a01acSMauro Carvalho Chehab { /* 0x13 */ 352cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_MSB,0x00 353cb7a01acSMauro Carvalho Chehab }, 354cb7a01acSMauro Carvalho Chehab { /* 0x14 */ 355cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_LSB,0x00 356cb7a01acSMauro Carvalho Chehab }, 357cb7a01acSMauro Carvalho Chehab { /* 0x15 */ 358cb7a01acSMauro Carvalho Chehab TVP5150_GENLOCK,0x01 359cb7a01acSMauro Carvalho Chehab }, 360cb7a01acSMauro Carvalho Chehab { /* 0x16 */ 361cb7a01acSMauro Carvalho Chehab TVP5150_HORIZ_SYNC_START,0x80 362cb7a01acSMauro Carvalho Chehab }, 363cb7a01acSMauro Carvalho Chehab { /* 0x18 */ 364cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_START,0x00 365cb7a01acSMauro Carvalho Chehab }, 366cb7a01acSMauro Carvalho Chehab { /* 0x19 */ 367cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_STOP,0x00 368cb7a01acSMauro Carvalho Chehab }, 369cb7a01acSMauro Carvalho Chehab { /* 0x1a */ 370cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1,0x0c 371cb7a01acSMauro Carvalho Chehab }, 372cb7a01acSMauro Carvalho Chehab { /* 0x1b */ 373cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2,0x14 374cb7a01acSMauro Carvalho Chehab }, 375cb7a01acSMauro Carvalho Chehab { /* 0x1c */ 376cb7a01acSMauro Carvalho Chehab TVP5150_INT_RESET_REG_B,0x00 377cb7a01acSMauro Carvalho Chehab }, 378cb7a01acSMauro Carvalho Chehab { /* 0x1d */ 379cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_B,0x00 380cb7a01acSMauro Carvalho Chehab }, 381cb7a01acSMauro Carvalho Chehab { /* 0x1e */ 382cb7a01acSMauro Carvalho Chehab TVP5150_INTT_CONFIG_REG_B,0x00 383cb7a01acSMauro Carvalho Chehab }, 384cb7a01acSMauro Carvalho Chehab { /* 0x28 */ 385cb7a01acSMauro Carvalho Chehab TVP5150_VIDEO_STD,0x00 386cb7a01acSMauro Carvalho Chehab }, 387cb7a01acSMauro Carvalho Chehab { /* 0x2e */ 388cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_ON_CTR,0x0f 389cb7a01acSMauro Carvalho Chehab }, 390cb7a01acSMauro Carvalho Chehab { /* 0x2f */ 391cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_OFF_CTR,0x01 392cb7a01acSMauro Carvalho Chehab }, 393cb7a01acSMauro Carvalho Chehab { /* 0xbb */ 394cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL_ENA,0x00 395cb7a01acSMauro Carvalho Chehab }, 396cb7a01acSMauro Carvalho Chehab { /* 0xc0 */ 397cb7a01acSMauro Carvalho Chehab TVP5150_INT_STATUS_REG_A,0x00 398cb7a01acSMauro Carvalho Chehab }, 399cb7a01acSMauro Carvalho Chehab { /* 0xc1 */ 400cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_A,0x00 401cb7a01acSMauro Carvalho Chehab }, 402cb7a01acSMauro Carvalho Chehab { /* 0xc2 */ 403cb7a01acSMauro Carvalho Chehab TVP5150_INT_CONF,0x04 404cb7a01acSMauro Carvalho Chehab }, 405cb7a01acSMauro Carvalho Chehab { /* 0xc8 */ 406cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_INT_THRESHOLD,0x80 407cb7a01acSMauro Carvalho Chehab }, 408cb7a01acSMauro Carvalho Chehab { /* 0xc9 */ 409cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_RESET,0x00 410cb7a01acSMauro Carvalho Chehab }, 411cb7a01acSMauro Carvalho Chehab { /* 0xca */ 412cb7a01acSMauro Carvalho Chehab TVP5150_LINE_NUMBER_INT,0x00 413cb7a01acSMauro Carvalho Chehab }, 414cb7a01acSMauro Carvalho Chehab { /* 0xcb */ 415cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_LOW,0x4e 416cb7a01acSMauro Carvalho Chehab }, 417cb7a01acSMauro Carvalho Chehab { /* 0xcc */ 418cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_HIGH,0x00 419cb7a01acSMauro Carvalho Chehab }, 420cb7a01acSMauro Carvalho Chehab { /* 0xcd */ 421cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_OUT_CTRL,0x01 422cb7a01acSMauro Carvalho Chehab }, 423cb7a01acSMauro Carvalho Chehab { /* 0xcf */ 424cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_ENA,0x00 425cb7a01acSMauro Carvalho Chehab }, 426cb7a01acSMauro Carvalho Chehab { /* 0xd0 */ 427cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_INI,0x00 428cb7a01acSMauro Carvalho Chehab }, 429cb7a01acSMauro Carvalho Chehab { /* 0xfc */ 430cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_MODE_REG,0x7f 431cb7a01acSMauro Carvalho Chehab }, 432cb7a01acSMauro Carvalho Chehab { /* end of data */ 433cb7a01acSMauro Carvalho Chehab 0xff,0xff 434cb7a01acSMauro Carvalho Chehab } 435cb7a01acSMauro Carvalho Chehab }; 436cb7a01acSMauro Carvalho Chehab 437cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 438cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_enable[] = { 439cb7a01acSMauro Carvalho Chehab { 440cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN, 2 441cb7a01acSMauro Carvalho Chehab },{ /* Automatic offset and AGC enabled */ 442cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 443cb7a01acSMauro Carvalho Chehab },{ /* Activate YCrCb output 0x9 or 0xd ? */ 444cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL, 0x6f 445cb7a01acSMauro Carvalho Chehab },{ /* Activates video std autodetection for all standards */ 446cb7a01acSMauro Carvalho Chehab TVP5150_AUTOSW_MSK, 0x0 447cb7a01acSMauro Carvalho Chehab },{ /* Default format: 0x47. For 4:2:2: 0x40 */ 448cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 449cb7a01acSMauro Carvalho Chehab },{ 450cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 451cb7a01acSMauro Carvalho Chehab },{ 452cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x54 453cb7a01acSMauro Carvalho Chehab },{ /* Non documented, but initialized on WinTV USB2 */ 454cb7a01acSMauro Carvalho Chehab 0x27, 0x20 455cb7a01acSMauro Carvalho Chehab },{ 456cb7a01acSMauro Carvalho Chehab 0xff,0xff 457cb7a01acSMauro Carvalho Chehab } 458cb7a01acSMauro Carvalho Chehab }; 459cb7a01acSMauro Carvalho Chehab 460cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type { 461cb7a01acSMauro Carvalho Chehab unsigned int vbi_type; 462cb7a01acSMauro Carvalho Chehab unsigned int ini_line; 463cb7a01acSMauro Carvalho Chehab unsigned int end_line; 464cb7a01acSMauro Carvalho Chehab unsigned int by_field :1; 465cb7a01acSMauro Carvalho Chehab }; 466cb7a01acSMauro Carvalho Chehab 467cb7a01acSMauro Carvalho Chehab struct i2c_vbi_ram_value { 468cb7a01acSMauro Carvalho Chehab u16 reg; 469cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type type; 470cb7a01acSMauro Carvalho Chehab unsigned char values[16]; 471cb7a01acSMauro Carvalho Chehab }; 472cb7a01acSMauro Carvalho Chehab 473cb7a01acSMauro Carvalho Chehab /* This struct have the values for each supported VBI Standard 474cb7a01acSMauro Carvalho Chehab * by 475cb7a01acSMauro Carvalho Chehab tvp5150_vbi_types should follow the same order as vbi_ram_default 476cb7a01acSMauro Carvalho Chehab * value 0 means rom position 0x10, value 1 means rom position 0x30 477cb7a01acSMauro Carvalho Chehab * and so on. There are 16 possible locations from 0 to 15. 478cb7a01acSMauro Carvalho Chehab */ 479cb7a01acSMauro Carvalho Chehab 480cb7a01acSMauro Carvalho Chehab static struct i2c_vbi_ram_value vbi_ram_default[] = 481cb7a01acSMauro Carvalho Chehab { 482cb7a01acSMauro Carvalho Chehab /* FIXME: Current api doesn't handle all VBI types, those not 483cb7a01acSMauro Carvalho Chehab yet supported are placed under #if 0 */ 484cb7a01acSMauro Carvalho Chehab #if 0 485cb7a01acSMauro Carvalho Chehab {0x010, /* Teletext, SECAM, WST System A */ 486cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, 487cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 488cb7a01acSMauro Carvalho Chehab 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } 489cb7a01acSMauro Carvalho Chehab }, 490cb7a01acSMauro Carvalho Chehab #endif 491cb7a01acSMauro Carvalho Chehab {0x030, /* Teletext, PAL, WST System B */ 492cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_B,6,22,1}, 493cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 494cb7a01acSMauro Carvalho Chehab 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } 495cb7a01acSMauro Carvalho Chehab }, 496cb7a01acSMauro Carvalho Chehab #if 0 497cb7a01acSMauro Carvalho Chehab {0x050, /* Teletext, PAL, WST System C */ 498cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, 499cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 500cb7a01acSMauro Carvalho Chehab 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 501cb7a01acSMauro Carvalho Chehab }, 502cb7a01acSMauro Carvalho Chehab {0x070, /* Teletext, NTSC, WST System B */ 503cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, 504cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, 505cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 506cb7a01acSMauro Carvalho Chehab }, 507cb7a01acSMauro Carvalho Chehab {0x090, /* Tetetext, NTSC NABTS System C */ 508cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, 509cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 510cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } 511cb7a01acSMauro Carvalho Chehab }, 512cb7a01acSMauro Carvalho Chehab {0x0b0, /* Teletext, NTSC-J, NABTS System D */ 513cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, 514cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, 515cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 516cb7a01acSMauro Carvalho Chehab }, 517cb7a01acSMauro Carvalho Chehab {0x0d0, /* Closed Caption, PAL/SECAM */ 518cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_625,22,22,1}, 519cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 520cb7a01acSMauro Carvalho Chehab 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 521cb7a01acSMauro Carvalho Chehab }, 522cb7a01acSMauro Carvalho Chehab #endif 523cb7a01acSMauro Carvalho Chehab {0x0f0, /* Closed Caption, NTSC */ 524cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_525,21,21,1}, 525cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 526cb7a01acSMauro Carvalho Chehab 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 527cb7a01acSMauro Carvalho Chehab }, 528cb7a01acSMauro Carvalho Chehab {0x110, /* Wide Screen Signal, PAL/SECAM */ 529cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_625,23,23,1}, 530cb7a01acSMauro Carvalho Chehab { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 531cb7a01acSMauro Carvalho Chehab 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } 532cb7a01acSMauro Carvalho Chehab }, 533cb7a01acSMauro Carvalho Chehab #if 0 534cb7a01acSMauro Carvalho Chehab {0x130, /* Wide Screen Signal, NTSC C */ 535cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_525,20,20,1}, 536cb7a01acSMauro Carvalho Chehab { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, 537cb7a01acSMauro Carvalho Chehab 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } 538cb7a01acSMauro Carvalho Chehab }, 539cb7a01acSMauro Carvalho Chehab {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ 540cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_625,6,22,0}, 541cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 542cb7a01acSMauro Carvalho Chehab 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 543cb7a01acSMauro Carvalho Chehab }, 544cb7a01acSMauro Carvalho Chehab {0x170, /* Vertical Interval Timecode (VITC), NTSC */ 545cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_525,10,20,0}, 546cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 547cb7a01acSMauro Carvalho Chehab 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 548cb7a01acSMauro Carvalho Chehab }, 549cb7a01acSMauro Carvalho Chehab #endif 550cb7a01acSMauro Carvalho Chehab {0x190, /* Video Program System (VPS), PAL */ 551cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_VPS,16,16,0}, 552cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, 553cb7a01acSMauro Carvalho Chehab 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } 554cb7a01acSMauro Carvalho Chehab }, 555cb7a01acSMauro Carvalho Chehab /* 0x1d0 User programmable */ 556cb7a01acSMauro Carvalho Chehab 557cb7a01acSMauro Carvalho Chehab /* End of struct */ 558cb7a01acSMauro Carvalho Chehab { (u16)-1 } 559cb7a01acSMauro Carvalho Chehab }; 560cb7a01acSMauro Carvalho Chehab 561cb7a01acSMauro Carvalho Chehab static int tvp5150_write_inittab(struct v4l2_subdev *sd, 562cb7a01acSMauro Carvalho Chehab const struct i2c_reg_value *regs) 563cb7a01acSMauro Carvalho Chehab { 564cb7a01acSMauro Carvalho Chehab while (regs->reg != 0xff) { 565cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, regs->reg, regs->value); 566cb7a01acSMauro Carvalho Chehab regs++; 567cb7a01acSMauro Carvalho Chehab } 568cb7a01acSMauro Carvalho Chehab return 0; 569cb7a01acSMauro Carvalho Chehab } 570cb7a01acSMauro Carvalho Chehab 571cb7a01acSMauro Carvalho Chehab static int tvp5150_vdp_init(struct v4l2_subdev *sd, 572cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs) 573cb7a01acSMauro Carvalho Chehab { 574cb7a01acSMauro Carvalho Chehab unsigned int i; 575cb7a01acSMauro Carvalho Chehab 576cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 577cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); 578cb7a01acSMauro Carvalho Chehab 579cb7a01acSMauro Carvalho Chehab /* Before programming, Line mode should be at 0xff */ 580cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 581cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, i, 0xff); 582cb7a01acSMauro Carvalho Chehab 583cb7a01acSMauro Carvalho Chehab /* Load Ram Table */ 584cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1) { 585cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); 586cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); 587cb7a01acSMauro Carvalho Chehab 588cb7a01acSMauro Carvalho Chehab for (i = 0; i < 16; i++) 589cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]); 590cb7a01acSMauro Carvalho Chehab 591cb7a01acSMauro Carvalho Chehab regs++; 592cb7a01acSMauro Carvalho Chehab } 593cb7a01acSMauro Carvalho Chehab return 0; 594cb7a01acSMauro Carvalho Chehab } 595cb7a01acSMauro Carvalho Chehab 596cb7a01acSMauro Carvalho Chehab /* Fills VBI capabilities based on i2c_vbi_ram_value struct */ 597cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, 598cb7a01acSMauro Carvalho Chehab struct v4l2_sliced_vbi_cap *cap) 599cb7a01acSMauro Carvalho Chehab { 600cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = vbi_ram_default; 601cb7a01acSMauro Carvalho Chehab int line; 602cb7a01acSMauro Carvalho Chehab 603cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n"); 604cb7a01acSMauro Carvalho Chehab memset(cap, 0, sizeof *cap); 605cb7a01acSMauro Carvalho Chehab 606cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1 ) { 607cb7a01acSMauro Carvalho Chehab for (line=regs->type.ini_line;line<=regs->type.end_line;line++) { 608cb7a01acSMauro Carvalho Chehab cap->service_lines[0][line] |= regs->type.vbi_type; 609cb7a01acSMauro Carvalho Chehab } 610cb7a01acSMauro Carvalho Chehab cap->service_set |= regs->type.vbi_type; 611cb7a01acSMauro Carvalho Chehab 612cb7a01acSMauro Carvalho Chehab regs++; 613cb7a01acSMauro Carvalho Chehab } 614cb7a01acSMauro Carvalho Chehab return 0; 615cb7a01acSMauro Carvalho Chehab } 616cb7a01acSMauro Carvalho Chehab 617cb7a01acSMauro Carvalho Chehab /* Set vbi processing 618cb7a01acSMauro Carvalho Chehab * type - one of tvp5150_vbi_types 619cb7a01acSMauro Carvalho Chehab * line - line to gather data 620cb7a01acSMauro Carvalho Chehab * fields: bit 0 field1, bit 1, field2 621cb7a01acSMauro Carvalho Chehab * flags (default=0xf0) is a bitmask, were set means: 622cb7a01acSMauro Carvalho Chehab * bit 7: enable filtering null bytes on CC 623cb7a01acSMauro Carvalho Chehab * bit 6: send data also to FIFO 624cb7a01acSMauro Carvalho Chehab * bit 5: don't allow data with errors on FIFO 625cb7a01acSMauro Carvalho Chehab * bit 4: enable ECC when possible 626cb7a01acSMauro Carvalho Chehab * pix_align = pix alignment: 627cb7a01acSMauro Carvalho Chehab * LSB = field1 628cb7a01acSMauro Carvalho Chehab * MSB = field2 629cb7a01acSMauro Carvalho Chehab */ 630cb7a01acSMauro Carvalho Chehab static int tvp5150_set_vbi(struct v4l2_subdev *sd, 631cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs, 632cb7a01acSMauro Carvalho Chehab unsigned int type,u8 flags, int line, 633cb7a01acSMauro Carvalho Chehab const int fields) 634cb7a01acSMauro Carvalho Chehab { 635cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 636cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 637cb7a01acSMauro Carvalho Chehab u8 reg; 638cb7a01acSMauro Carvalho Chehab int pos=0; 639cb7a01acSMauro Carvalho Chehab 640cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 641cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); 642cb7a01acSMauro Carvalho Chehab return 0; 643cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 644cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 645cb7a01acSMauro Carvalho Chehab line += 3; 646cb7a01acSMauro Carvalho Chehab } 647cb7a01acSMauro Carvalho Chehab 648cb7a01acSMauro Carvalho Chehab if (line<6||line>27) 649cb7a01acSMauro Carvalho Chehab return 0; 650cb7a01acSMauro Carvalho Chehab 651cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1 ) { 652cb7a01acSMauro Carvalho Chehab if ((type & regs->type.vbi_type) && 653cb7a01acSMauro Carvalho Chehab (line>=regs->type.ini_line) && 654cb7a01acSMauro Carvalho Chehab (line<=regs->type.end_line)) { 655cb7a01acSMauro Carvalho Chehab type=regs->type.vbi_type; 656cb7a01acSMauro Carvalho Chehab break; 657cb7a01acSMauro Carvalho Chehab } 658cb7a01acSMauro Carvalho Chehab 659cb7a01acSMauro Carvalho Chehab regs++; 660cb7a01acSMauro Carvalho Chehab pos++; 661cb7a01acSMauro Carvalho Chehab } 662cb7a01acSMauro Carvalho Chehab if (regs->reg == (u16)-1) 663cb7a01acSMauro Carvalho Chehab return 0; 664cb7a01acSMauro Carvalho Chehab 665cb7a01acSMauro Carvalho Chehab type=pos | (flags & 0xf0); 666cb7a01acSMauro Carvalho Chehab reg=((line-6)<<1)+TVP5150_LINE_MODE_INI; 667cb7a01acSMauro Carvalho Chehab 668cb7a01acSMauro Carvalho Chehab if (fields&1) { 669cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg, type); 670cb7a01acSMauro Carvalho Chehab } 671cb7a01acSMauro Carvalho Chehab 672cb7a01acSMauro Carvalho Chehab if (fields&2) { 673cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg+1, type); 674cb7a01acSMauro Carvalho Chehab } 675cb7a01acSMauro Carvalho Chehab 676cb7a01acSMauro Carvalho Chehab return type; 677cb7a01acSMauro Carvalho Chehab } 678cb7a01acSMauro Carvalho Chehab 679cb7a01acSMauro Carvalho Chehab static int tvp5150_get_vbi(struct v4l2_subdev *sd, 680cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs, int line) 681cb7a01acSMauro Carvalho Chehab { 682cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 683cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 684cb7a01acSMauro Carvalho Chehab u8 reg; 685cb7a01acSMauro Carvalho Chehab int pos, type = 0; 686cb7a01acSMauro Carvalho Chehab int i, ret = 0; 687cb7a01acSMauro Carvalho Chehab 688cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 689cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); 690cb7a01acSMauro Carvalho Chehab return 0; 691cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 692cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 693cb7a01acSMauro Carvalho Chehab line += 3; 694cb7a01acSMauro Carvalho Chehab } 695cb7a01acSMauro Carvalho Chehab 696cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 697cb7a01acSMauro Carvalho Chehab return 0; 698cb7a01acSMauro Carvalho Chehab 699cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 700cb7a01acSMauro Carvalho Chehab 701cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 1; i++) { 702cb7a01acSMauro Carvalho Chehab ret = tvp5150_read(sd, reg + i); 703cb7a01acSMauro Carvalho Chehab if (ret < 0) { 704cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", 705cb7a01acSMauro Carvalho Chehab __func__, ret); 706cb7a01acSMauro Carvalho Chehab return 0; 707cb7a01acSMauro Carvalho Chehab } 708cb7a01acSMauro Carvalho Chehab pos = ret & 0x0f; 709cb7a01acSMauro Carvalho Chehab if (pos < 0x0f) 710cb7a01acSMauro Carvalho Chehab type |= regs[pos].type.vbi_type; 711cb7a01acSMauro Carvalho Chehab } 712cb7a01acSMauro Carvalho Chehab 713cb7a01acSMauro Carvalho Chehab return type; 714cb7a01acSMauro Carvalho Chehab } 715cb7a01acSMauro Carvalho Chehab 716cb7a01acSMauro Carvalho Chehab static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) 717cb7a01acSMauro Carvalho Chehab { 718cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 719cb7a01acSMauro Carvalho Chehab int fmt = 0; 720cb7a01acSMauro Carvalho Chehab 721cb7a01acSMauro Carvalho Chehab decoder->norm = std; 722cb7a01acSMauro Carvalho Chehab 723cb7a01acSMauro Carvalho Chehab /* First tests should be against specific std */ 724cb7a01acSMauro Carvalho Chehab 72526811ae0SHans Verkuil if (std == V4L2_STD_NTSC_443) { 726cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_4_43_BIT; 72726811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_M) { 728cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_M_BIT; 72926811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) { 730cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_COMBINATION_N_BIT; 731cb7a01acSMauro Carvalho Chehab } else { 732cb7a01acSMauro Carvalho Chehab /* Then, test against generic ones */ 733cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 734cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_MJ_BIT; 735cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_PAL) 736cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_BDGHIN_BIT; 737cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_SECAM) 738cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_SECAM_BIT; 739cb7a01acSMauro Carvalho Chehab } 740cb7a01acSMauro Carvalho Chehab 741cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt); 742cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VIDEO_STD, fmt); 743cb7a01acSMauro Carvalho Chehab return 0; 744cb7a01acSMauro Carvalho Chehab } 745cb7a01acSMauro Carvalho Chehab 746cb7a01acSMauro Carvalho Chehab static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 747cb7a01acSMauro Carvalho Chehab { 748cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 749cb7a01acSMauro Carvalho Chehab 750cb7a01acSMauro Carvalho Chehab if (decoder->norm == std) 751cb7a01acSMauro Carvalho Chehab return 0; 752cb7a01acSMauro Carvalho Chehab 753cb7a01acSMauro Carvalho Chehab /* Change cropping height limits */ 754cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 755cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_525_60; 756cb7a01acSMauro Carvalho Chehab else 757cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_OTHERS; 758cb7a01acSMauro Carvalho Chehab 759cb7a01acSMauro Carvalho Chehab 760cb7a01acSMauro Carvalho Chehab return tvp5150_set_std(sd, std); 761cb7a01acSMauro Carvalho Chehab } 762cb7a01acSMauro Carvalho Chehab 763cb7a01acSMauro Carvalho Chehab static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) 764cb7a01acSMauro Carvalho Chehab { 765cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 766cb7a01acSMauro Carvalho Chehab 767cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to its default values */ 768cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_default); 769cb7a01acSMauro Carvalho Chehab 770cb7a01acSMauro Carvalho Chehab /* Initializes VDP registers */ 771cb7a01acSMauro Carvalho Chehab tvp5150_vdp_init(sd, vbi_ram_default); 772cb7a01acSMauro Carvalho Chehab 773cb7a01acSMauro Carvalho Chehab /* Selects decoder input */ 774cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 775cb7a01acSMauro Carvalho Chehab 776cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to stream enabled values */ 777cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_enable); 778cb7a01acSMauro Carvalho Chehab 779cb7a01acSMauro Carvalho Chehab /* Initialize image preferences */ 780cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&decoder->hdl); 781cb7a01acSMauro Carvalho Chehab 782cb7a01acSMauro Carvalho Chehab tvp5150_set_std(sd, decoder->norm); 783a2e5f1b3SJavier Martinez Canillas 784a2e5f1b3SJavier Martinez Canillas if (decoder->mbus_type == V4L2_MBUS_PARALLEL) 785a2e5f1b3SJavier Martinez Canillas tvp5150_write(sd, TVP5150_DATA_RATE_SEL, 0x40); 786a2e5f1b3SJavier Martinez Canillas 787cb7a01acSMauro Carvalho Chehab return 0; 788cb7a01acSMauro Carvalho Chehab }; 789cb7a01acSMauro Carvalho Chehab 790cb7a01acSMauro Carvalho Chehab static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) 791cb7a01acSMauro Carvalho Chehab { 792cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_sd(ctrl); 793cb7a01acSMauro Carvalho Chehab 794cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 795cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 796cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val); 797cb7a01acSMauro Carvalho Chehab return 0; 798cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 799cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val); 800cb7a01acSMauro Carvalho Chehab return 0; 801cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 802cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val); 803cb7a01acSMauro Carvalho Chehab return 0; 804cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 805cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val); 806cb7a01acSMauro Carvalho Chehab return 0; 807cb7a01acSMauro Carvalho Chehab } 808cb7a01acSMauro Carvalho Chehab return -EINVAL; 809cb7a01acSMauro Carvalho Chehab } 810cb7a01acSMauro Carvalho Chehab 811cb7a01acSMauro Carvalho Chehab static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) 812cb7a01acSMauro Carvalho Chehab { 813cb7a01acSMauro Carvalho Chehab int val = tvp5150_read(sd, TVP5150_STATUS_REG_5); 814cb7a01acSMauro Carvalho Chehab 815cb7a01acSMauro Carvalho Chehab switch (val & 0x0F) { 816cb7a01acSMauro Carvalho Chehab case 0x01: 817cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC; 818cb7a01acSMauro Carvalho Chehab case 0x03: 819cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL; 820cb7a01acSMauro Carvalho Chehab case 0x05: 821cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M; 822cb7a01acSMauro Carvalho Chehab case 0x07: 823cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc; 824cb7a01acSMauro Carvalho Chehab case 0x09: 825cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443; 826cb7a01acSMauro Carvalho Chehab case 0xb: 827cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 828cb7a01acSMauro Carvalho Chehab default: 829cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN; 830cb7a01acSMauro Carvalho Chehab } 831cb7a01acSMauro Carvalho Chehab } 832cb7a01acSMauro Carvalho Chehab 833da298c6dSHans Verkuil static int tvp5150_fill_fmt(struct v4l2_subdev *sd, 834da298c6dSHans Verkuil struct v4l2_subdev_pad_config *cfg, 835da298c6dSHans Verkuil struct v4l2_subdev_format *format) 836cb7a01acSMauro Carvalho Chehab { 837da298c6dSHans Verkuil struct v4l2_mbus_framefmt *f; 838cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 839cb7a01acSMauro Carvalho Chehab 840da298c6dSHans Verkuil if (!format || format->pad) 841cb7a01acSMauro Carvalho Chehab return -EINVAL; 842cb7a01acSMauro Carvalho Chehab 843da298c6dSHans Verkuil f = &format->format; 844da298c6dSHans Verkuil 845cb7a01acSMauro Carvalho Chehab tvp5150_reset(sd, 0); 846cb7a01acSMauro Carvalho Chehab 847cb7a01acSMauro Carvalho Chehab f->width = decoder->rect.width; 8484f57d27bSLaurent Pinchart f->height = decoder->rect.height / 2; 849cb7a01acSMauro Carvalho Chehab 850f5fe58fdSBoris BREZILLON f->code = MEDIA_BUS_FMT_UYVY8_2X8; 8514f57d27bSLaurent Pinchart f->field = V4L2_FIELD_ALTERNATE; 852cb7a01acSMauro Carvalho Chehab f->colorspace = V4L2_COLORSPACE_SMPTE170M; 853cb7a01acSMauro Carvalho Chehab 854cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width, 855cb7a01acSMauro Carvalho Chehab f->height); 856cb7a01acSMauro Carvalho Chehab return 0; 857cb7a01acSMauro Carvalho Chehab } 858cb7a01acSMauro Carvalho Chehab 8594f996594SHans Verkuil static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) 860cb7a01acSMauro Carvalho Chehab { 861cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect = a->c; 862cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 863cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 864f90580caSRicardo Ribalda unsigned int hmax; 865cb7a01acSMauro Carvalho Chehab 866cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", 867cb7a01acSMauro Carvalho Chehab __func__, rect.left, rect.top, rect.width, rect.height); 868cb7a01acSMauro Carvalho Chehab 869cb7a01acSMauro Carvalho Chehab if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 870cb7a01acSMauro Carvalho Chehab return -EINVAL; 871cb7a01acSMauro Carvalho Chehab 872cb7a01acSMauro Carvalho Chehab /* tvp5150 has some special limits */ 873cb7a01acSMauro Carvalho Chehab rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); 874f90580caSRicardo Ribalda rect.width = clamp_t(unsigned int, rect.width, 875cb7a01acSMauro Carvalho Chehab TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, 876cb7a01acSMauro Carvalho Chehab TVP5150_H_MAX - rect.left); 877cb7a01acSMauro Carvalho Chehab rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); 878cb7a01acSMauro Carvalho Chehab 879cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 880cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 881cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 882cb7a01acSMauro Carvalho Chehab else 883cb7a01acSMauro Carvalho Chehab std = decoder->norm; 884cb7a01acSMauro Carvalho Chehab 885cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 886cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_525_60; 887cb7a01acSMauro Carvalho Chehab else 888cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_OTHERS; 889cb7a01acSMauro Carvalho Chehab 890f90580caSRicardo Ribalda rect.height = clamp_t(unsigned int, rect.height, 891cb7a01acSMauro Carvalho Chehab hmax - TVP5150_MAX_CROP_TOP - rect.top, 892cb7a01acSMauro Carvalho Chehab hmax - rect.top); 893cb7a01acSMauro Carvalho Chehab 894cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); 895cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 896cb7a01acSMauro Carvalho Chehab rect.top + rect.height - hmax); 897cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB, 898cb7a01acSMauro Carvalho Chehab rect.left >> TVP5150_CROP_SHIFT); 899cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB, 900cb7a01acSMauro Carvalho Chehab rect.left | (1 << TVP5150_CROP_SHIFT)); 901cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB, 902cb7a01acSMauro Carvalho Chehab (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> 903cb7a01acSMauro Carvalho Chehab TVP5150_CROP_SHIFT); 904cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB, 905cb7a01acSMauro Carvalho Chehab rect.left + rect.width - TVP5150_MAX_CROP_LEFT); 906cb7a01acSMauro Carvalho Chehab 907cb7a01acSMauro Carvalho Chehab decoder->rect = rect; 908cb7a01acSMauro Carvalho Chehab 909cb7a01acSMauro Carvalho Chehab return 0; 910cb7a01acSMauro Carvalho Chehab } 911cb7a01acSMauro Carvalho Chehab 912cb7a01acSMauro Carvalho Chehab static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 913cb7a01acSMauro Carvalho Chehab { 91412bd10c7SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 915cb7a01acSMauro Carvalho Chehab 916cb7a01acSMauro Carvalho Chehab a->c = decoder->rect; 917cb7a01acSMauro Carvalho Chehab a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 918cb7a01acSMauro Carvalho Chehab 919cb7a01acSMauro Carvalho Chehab return 0; 920cb7a01acSMauro Carvalho Chehab } 921cb7a01acSMauro Carvalho Chehab 922cb7a01acSMauro Carvalho Chehab static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) 923cb7a01acSMauro Carvalho Chehab { 92412bd10c7SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 925cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 926cb7a01acSMauro Carvalho Chehab 927cb7a01acSMauro Carvalho Chehab if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 928cb7a01acSMauro Carvalho Chehab return -EINVAL; 929cb7a01acSMauro Carvalho Chehab 930cb7a01acSMauro Carvalho Chehab a->bounds.left = 0; 931cb7a01acSMauro Carvalho Chehab a->bounds.top = 0; 932cb7a01acSMauro Carvalho Chehab a->bounds.width = TVP5150_H_MAX; 933cb7a01acSMauro Carvalho Chehab 934cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 935cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 936cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 937cb7a01acSMauro Carvalho Chehab else 938cb7a01acSMauro Carvalho Chehab std = decoder->norm; 939cb7a01acSMauro Carvalho Chehab 940cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 941cb7a01acSMauro Carvalho Chehab a->bounds.height = TVP5150_V_MAX_525_60; 942cb7a01acSMauro Carvalho Chehab else 943cb7a01acSMauro Carvalho Chehab a->bounds.height = TVP5150_V_MAX_OTHERS; 944cb7a01acSMauro Carvalho Chehab 945cb7a01acSMauro Carvalho Chehab a->defrect = a->bounds; 946cb7a01acSMauro Carvalho Chehab a->pixelaspect.numerator = 1; 947cb7a01acSMauro Carvalho Chehab a->pixelaspect.denominator = 1; 948cb7a01acSMauro Carvalho Chehab 949cb7a01acSMauro Carvalho Chehab return 0; 950cb7a01acSMauro Carvalho Chehab } 951cb7a01acSMauro Carvalho Chehab 952dd3a46bbSLaurent Pinchart static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, 953dd3a46bbSLaurent Pinchart struct v4l2_mbus_config *cfg) 954dd3a46bbSLaurent Pinchart { 955a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 956a2e5f1b3SJavier Martinez Canillas 957a2e5f1b3SJavier Martinez Canillas cfg->type = decoder->mbus_type; 958dd3a46bbSLaurent Pinchart cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING 959dd3a46bbSLaurent Pinchart | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; 960dd3a46bbSLaurent Pinchart 961dd3a46bbSLaurent Pinchart return 0; 962dd3a46bbSLaurent Pinchart } 963dd3a46bbSLaurent Pinchart 964cb7a01acSMauro Carvalho Chehab /**************************************************************************** 965e545ac87SLaurent Pinchart V4L2 subdev pad ops 966e545ac87SLaurent Pinchart ****************************************************************************/ 967e545ac87SLaurent Pinchart static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, 968e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 969e545ac87SLaurent Pinchart struct v4l2_subdev_mbus_code_enum *code) 970e545ac87SLaurent Pinchart { 971e545ac87SLaurent Pinchart if (code->pad || code->index) 972e545ac87SLaurent Pinchart return -EINVAL; 973e545ac87SLaurent Pinchart 974e545ac87SLaurent Pinchart code->code = MEDIA_BUS_FMT_UYVY8_2X8; 975e545ac87SLaurent Pinchart return 0; 976e545ac87SLaurent Pinchart } 977e545ac87SLaurent Pinchart 978e545ac87SLaurent Pinchart static int tvp5150_enum_frame_size(struct v4l2_subdev *sd, 979e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 980e545ac87SLaurent Pinchart struct v4l2_subdev_frame_size_enum *fse) 981e545ac87SLaurent Pinchart { 982e545ac87SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 983e545ac87SLaurent Pinchart 984e545ac87SLaurent Pinchart if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_UYVY8_2X8) 985e545ac87SLaurent Pinchart return -EINVAL; 986e545ac87SLaurent Pinchart 987e545ac87SLaurent Pinchart fse->code = MEDIA_BUS_FMT_UYVY8_2X8; 988e545ac87SLaurent Pinchart fse->min_width = decoder->rect.width; 989e545ac87SLaurent Pinchart fse->max_width = decoder->rect.width; 990e545ac87SLaurent Pinchart fse->min_height = decoder->rect.height / 2; 991e545ac87SLaurent Pinchart fse->max_height = decoder->rect.height / 2; 992e545ac87SLaurent Pinchart 993e545ac87SLaurent Pinchart return 0; 994e545ac87SLaurent Pinchart } 995e545ac87SLaurent Pinchart 996e545ac87SLaurent Pinchart /**************************************************************************** 997cb7a01acSMauro Carvalho Chehab I2C Command 998cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 999cb7a01acSMauro Carvalho Chehab 1000460b6c08SLaurent Pinchart static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) 1001460b6c08SLaurent Pinchart { 1002a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1003841502d7SMauro Carvalho Chehab /* Output format: 8-bit ITU-R BT.656 with embedded syncs */ 1004841502d7SMauro Carvalho Chehab int val = 0x09; 1005a2e5f1b3SJavier Martinez Canillas 1006a2e5f1b3SJavier Martinez Canillas /* Output format: 8-bit 4:2:2 YUV with discrete sync */ 1007841502d7SMauro Carvalho Chehab if (decoder->mbus_type == V4L2_MBUS_PARALLEL) 1008841502d7SMauro Carvalho Chehab val = 0x0d; 1009a2e5f1b3SJavier Martinez Canillas 1010460b6c08SLaurent Pinchart /* Initializes TVP5150 to its default values */ 1011460b6c08SLaurent Pinchart /* # set PCLK (27MHz) */ 1012460b6c08SLaurent Pinchart tvp5150_write(sd, TVP5150_CONF_SHARED_PIN, 0x00); 1013460b6c08SLaurent Pinchart 1014460b6c08SLaurent Pinchart if (enable) 1015841502d7SMauro Carvalho Chehab tvp5150_write(sd, TVP5150_MISC_CTL, val); 1016460b6c08SLaurent Pinchart else 1017460b6c08SLaurent Pinchart tvp5150_write(sd, TVP5150_MISC_CTL, 0x00); 1018460b6c08SLaurent Pinchart 1019460b6c08SLaurent Pinchart return 0; 1020460b6c08SLaurent Pinchart } 1021460b6c08SLaurent Pinchart 1022cb7a01acSMauro Carvalho Chehab static int tvp5150_s_routing(struct v4l2_subdev *sd, 1023cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 1024cb7a01acSMauro Carvalho Chehab { 1025cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1026cb7a01acSMauro Carvalho Chehab 1027cb7a01acSMauro Carvalho Chehab decoder->input = input; 1028cb7a01acSMauro Carvalho Chehab decoder->output = output; 1029cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 1030cb7a01acSMauro Carvalho Chehab return 0; 1031cb7a01acSMauro Carvalho Chehab } 1032cb7a01acSMauro Carvalho Chehab 1033cb7a01acSMauro Carvalho Chehab static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) 1034cb7a01acSMauro Carvalho Chehab { 1035cb7a01acSMauro Carvalho Chehab /* this is for capturing 36 raw vbi lines 1036cb7a01acSMauro Carvalho Chehab if there's a way to cut off the beginning 2 vbi lines 1037cb7a01acSMauro Carvalho Chehab with the tvp5150 then the vbi line count could be lowered 1038cb7a01acSMauro Carvalho Chehab to 17 lines/field again, although I couldn't find a register 1039cb7a01acSMauro Carvalho Chehab which could do that cropping */ 1040cb7a01acSMauro Carvalho Chehab if (fmt->sample_format == V4L2_PIX_FMT_GREY) 1041cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70); 1042cb7a01acSMauro Carvalho Chehab if (fmt->count[0] == 18 && fmt->count[1] == 18) { 1043cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00); 1044cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01); 1045cb7a01acSMauro Carvalho Chehab } 1046cb7a01acSMauro Carvalho Chehab return 0; 1047cb7a01acSMauro Carvalho Chehab } 1048cb7a01acSMauro Carvalho Chehab 1049cb7a01acSMauro Carvalho Chehab static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1050cb7a01acSMauro Carvalho Chehab { 1051cb7a01acSMauro Carvalho Chehab int i; 1052cb7a01acSMauro Carvalho Chehab 1053cb7a01acSMauro Carvalho Chehab if (svbi->service_set != 0) { 1054cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1055cb7a01acSMauro Carvalho Chehab svbi->service_lines[1][i] = 0; 1056cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 1057cb7a01acSMauro Carvalho Chehab tvp5150_set_vbi(sd, vbi_ram_default, 1058cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i], 0xf0, i, 3); 1059cb7a01acSMauro Carvalho Chehab } 1060cb7a01acSMauro Carvalho Chehab /* Enables FIFO */ 1061cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1); 1062cb7a01acSMauro Carvalho Chehab } else { 1063cb7a01acSMauro Carvalho Chehab /* Disables FIFO*/ 1064cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0); 1065cb7a01acSMauro Carvalho Chehab 1066cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 1067cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); 1068cb7a01acSMauro Carvalho Chehab 1069cb7a01acSMauro Carvalho Chehab /* Disable Line modes */ 1070cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 1071cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, i, 0xff); 1072cb7a01acSMauro Carvalho Chehab } 1073cb7a01acSMauro Carvalho Chehab return 0; 1074cb7a01acSMauro Carvalho Chehab } 1075cb7a01acSMauro Carvalho Chehab 1076cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1077cb7a01acSMauro Carvalho Chehab { 1078cb7a01acSMauro Carvalho Chehab int i, mask = 0; 1079cb7a01acSMauro Carvalho Chehab 108030634e8eSHans Verkuil memset(svbi->service_lines, 0, sizeof(svbi->service_lines)); 1081cb7a01acSMauro Carvalho Chehab 1082cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1083cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 1084cb7a01acSMauro Carvalho Chehab tvp5150_get_vbi(sd, vbi_ram_default, i); 1085cb7a01acSMauro Carvalho Chehab mask |= svbi->service_lines[0][i]; 1086cb7a01acSMauro Carvalho Chehab } 1087cb7a01acSMauro Carvalho Chehab svbi->service_set = mask; 1088cb7a01acSMauro Carvalho Chehab return 0; 1089cb7a01acSMauro Carvalho Chehab } 1090cb7a01acSMauro Carvalho Chehab 1091cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1092cb7a01acSMauro Carvalho Chehab static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 1093cb7a01acSMauro Carvalho Chehab { 1094cb7a01acSMauro Carvalho Chehab int res; 1095cb7a01acSMauro Carvalho Chehab 1096cb7a01acSMauro Carvalho Chehab res = tvp5150_read(sd, reg->reg & 0xff); 1097cb7a01acSMauro Carvalho Chehab if (res < 0) { 1098cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", __func__, res); 1099cb7a01acSMauro Carvalho Chehab return res; 1100cb7a01acSMauro Carvalho Chehab } 1101cb7a01acSMauro Carvalho Chehab 1102cb7a01acSMauro Carvalho Chehab reg->val = res; 1103cb7a01acSMauro Carvalho Chehab reg->size = 1; 1104cb7a01acSMauro Carvalho Chehab return 0; 1105cb7a01acSMauro Carvalho Chehab } 1106cb7a01acSMauro Carvalho Chehab 1107977ba3b1SHans Verkuil static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 1108cb7a01acSMauro Carvalho Chehab { 1109cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); 1110cb7a01acSMauro Carvalho Chehab return 0; 1111cb7a01acSMauro Carvalho Chehab } 1112cb7a01acSMauro Carvalho Chehab #endif 1113cb7a01acSMauro Carvalho Chehab 1114cb7a01acSMauro Carvalho Chehab static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) 1115cb7a01acSMauro Carvalho Chehab { 1116cb7a01acSMauro Carvalho Chehab int status = tvp5150_read(sd, 0x88); 1117cb7a01acSMauro Carvalho Chehab 1118cb7a01acSMauro Carvalho Chehab vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0; 1119cb7a01acSMauro Carvalho Chehab return 0; 1120cb7a01acSMauro Carvalho Chehab } 1121cb7a01acSMauro Carvalho Chehab 1122cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1123cb7a01acSMauro Carvalho Chehab 1124cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { 1125cb7a01acSMauro Carvalho Chehab .s_ctrl = tvp5150_s_ctrl, 1126cb7a01acSMauro Carvalho Chehab }; 1127cb7a01acSMauro Carvalho Chehab 1128cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tvp5150_core_ops = { 1129cb7a01acSMauro Carvalho Chehab .log_status = tvp5150_log_status, 1130cb7a01acSMauro Carvalho Chehab .reset = tvp5150_reset, 1131cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1132cb7a01acSMauro Carvalho Chehab .g_register = tvp5150_g_register, 1133cb7a01acSMauro Carvalho Chehab .s_register = tvp5150_s_register, 1134cb7a01acSMauro Carvalho Chehab #endif 1135cb7a01acSMauro Carvalho Chehab }; 1136cb7a01acSMauro Carvalho Chehab 1137cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { 1138cb7a01acSMauro Carvalho Chehab .g_tuner = tvp5150_g_tuner, 1139cb7a01acSMauro Carvalho Chehab }; 1140cb7a01acSMauro Carvalho Chehab 1141cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tvp5150_video_ops = { 11428774bed9SLaurent Pinchart .s_std = tvp5150_s_std, 1143460b6c08SLaurent Pinchart .s_stream = tvp5150_s_stream, 1144cb7a01acSMauro Carvalho Chehab .s_routing = tvp5150_s_routing, 1145cb7a01acSMauro Carvalho Chehab .s_crop = tvp5150_s_crop, 1146cb7a01acSMauro Carvalho Chehab .g_crop = tvp5150_g_crop, 1147cb7a01acSMauro Carvalho Chehab .cropcap = tvp5150_cropcap, 1148dd3a46bbSLaurent Pinchart .g_mbus_config = tvp5150_g_mbus_config, 1149cb7a01acSMauro Carvalho Chehab }; 1150cb7a01acSMauro Carvalho Chehab 1151cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { 1152cb7a01acSMauro Carvalho Chehab .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap, 1153cb7a01acSMauro Carvalho Chehab .g_sliced_fmt = tvp5150_g_sliced_fmt, 1154cb7a01acSMauro Carvalho Chehab .s_sliced_fmt = tvp5150_s_sliced_fmt, 1155cb7a01acSMauro Carvalho Chehab .s_raw_fmt = tvp5150_s_raw_fmt, 1156cb7a01acSMauro Carvalho Chehab }; 1157cb7a01acSMauro Carvalho Chehab 1158ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { 1159ebcff5fcSHans Verkuil .enum_mbus_code = tvp5150_enum_mbus_code, 1160e545ac87SLaurent Pinchart .enum_frame_size = tvp5150_enum_frame_size, 1161da298c6dSHans Verkuil .set_fmt = tvp5150_fill_fmt, 1162da298c6dSHans Verkuil .get_fmt = tvp5150_fill_fmt, 1163ebcff5fcSHans Verkuil }; 1164ebcff5fcSHans Verkuil 1165cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvp5150_ops = { 1166cb7a01acSMauro Carvalho Chehab .core = &tvp5150_core_ops, 1167cb7a01acSMauro Carvalho Chehab .tuner = &tvp5150_tuner_ops, 1168cb7a01acSMauro Carvalho Chehab .video = &tvp5150_video_ops, 1169cb7a01acSMauro Carvalho Chehab .vbi = &tvp5150_vbi_ops, 1170ebcff5fcSHans Verkuil .pad = &tvp5150_pad_ops, 1171cb7a01acSMauro Carvalho Chehab }; 1172cb7a01acSMauro Carvalho Chehab 1173cb7a01acSMauro Carvalho Chehab 1174cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1175cb7a01acSMauro Carvalho Chehab I2C Client & Driver 1176cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1177cb7a01acSMauro Carvalho Chehab 11787871597aSLaurent Pinchart static int tvp5150_detect_version(struct tvp5150 *core) 11797871597aSLaurent Pinchart { 11807871597aSLaurent Pinchart struct v4l2_subdev *sd = &core->sd; 11817871597aSLaurent Pinchart struct i2c_client *c = v4l2_get_subdevdata(sd); 11827871597aSLaurent Pinchart unsigned int i; 11837871597aSLaurent Pinchart u16 dev_id; 11847871597aSLaurent Pinchart u16 rom_ver; 11857871597aSLaurent Pinchart u8 regs[4]; 11867871597aSLaurent Pinchart int res; 11877871597aSLaurent Pinchart 11887871597aSLaurent Pinchart /* 11897871597aSLaurent Pinchart * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID, 11907871597aSLaurent Pinchart * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 11917871597aSLaurent Pinchart */ 11927871597aSLaurent Pinchart for (i = 0; i < 4; i++) { 11937871597aSLaurent Pinchart res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i); 11947871597aSLaurent Pinchart if (res < 0) 11957871597aSLaurent Pinchart return res; 11967871597aSLaurent Pinchart regs[i] = res; 11977871597aSLaurent Pinchart } 11987871597aSLaurent Pinchart 11997871597aSLaurent Pinchart dev_id = (regs[0] << 8) | regs[1]; 12007871597aSLaurent Pinchart rom_ver = (regs[2] << 8) | regs[3]; 12017871597aSLaurent Pinchart 12027871597aSLaurent Pinchart v4l2_info(sd, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n", 12037871597aSLaurent Pinchart dev_id, regs[2], regs[3], c->addr << 1, c->adapter->name); 12047871597aSLaurent Pinchart 12057871597aSLaurent Pinchart if (dev_id == 0x5150 && rom_ver == 0x0321) { /* TVP51510A */ 12067871597aSLaurent Pinchart v4l2_info(sd, "tvp5150a detected.\n"); 12077871597aSLaurent Pinchart } else if (dev_id == 0x5150 && rom_ver == 0x0400) { /* TVP5150AM1 */ 12087871597aSLaurent Pinchart v4l2_info(sd, "tvp5150am1 detected.\n"); 12097871597aSLaurent Pinchart 12107871597aSLaurent Pinchart /* ITU-T BT.656.4 timing */ 12117871597aSLaurent Pinchart tvp5150_write(sd, TVP5150_REV_SELECT, 0); 121205676b3eSLaurent Pinchart } else if (dev_id == 0x5151 && rom_ver == 0x0100) { /* TVP5151 */ 121305676b3eSLaurent Pinchart v4l2_info(sd, "tvp5151 detected.\n"); 12147871597aSLaurent Pinchart } else { 12157871597aSLaurent Pinchart v4l2_info(sd, "*** unknown tvp%04x chip detected.\n", dev_id); 12167871597aSLaurent Pinchart } 12177871597aSLaurent Pinchart 12187871597aSLaurent Pinchart return 0; 12197871597aSLaurent Pinchart } 12207871597aSLaurent Pinchart 122109aa2609SJavier Martinez Canillas static int tvp5150_init(struct i2c_client *c) 122209aa2609SJavier Martinez Canillas { 122309aa2609SJavier Martinez Canillas struct gpio_desc *pdn_gpio; 122409aa2609SJavier Martinez Canillas struct gpio_desc *reset_gpio; 122509aa2609SJavier Martinez Canillas 122609aa2609SJavier Martinez Canillas pdn_gpio = devm_gpiod_get_optional(&c->dev, "pdn", GPIOD_OUT_HIGH); 122709aa2609SJavier Martinez Canillas if (IS_ERR(pdn_gpio)) 122809aa2609SJavier Martinez Canillas return PTR_ERR(pdn_gpio); 122909aa2609SJavier Martinez Canillas 123009aa2609SJavier Martinez Canillas if (pdn_gpio) { 123109aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(pdn_gpio, 0); 123209aa2609SJavier Martinez Canillas /* Delay time between power supplies active and reset */ 123309aa2609SJavier Martinez Canillas msleep(20); 123409aa2609SJavier Martinez Canillas } 123509aa2609SJavier Martinez Canillas 123609aa2609SJavier Martinez Canillas reset_gpio = devm_gpiod_get_optional(&c->dev, "reset", GPIOD_OUT_HIGH); 123709aa2609SJavier Martinez Canillas if (IS_ERR(reset_gpio)) 123809aa2609SJavier Martinez Canillas return PTR_ERR(reset_gpio); 123909aa2609SJavier Martinez Canillas 124009aa2609SJavier Martinez Canillas if (reset_gpio) { 124109aa2609SJavier Martinez Canillas /* RESETB pulse duration */ 124209aa2609SJavier Martinez Canillas ndelay(500); 124309aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(reset_gpio, 0); 124409aa2609SJavier Martinez Canillas /* Delay time between end of reset to I2C active */ 124509aa2609SJavier Martinez Canillas usleep_range(200, 250); 124609aa2609SJavier Martinez Canillas } 124709aa2609SJavier Martinez Canillas 124809aa2609SJavier Martinez Canillas return 0; 124909aa2609SJavier Martinez Canillas } 125009aa2609SJavier Martinez Canillas 1251a2e5f1b3SJavier Martinez Canillas static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) 1252a2e5f1b3SJavier Martinez Canillas { 1253a2e5f1b3SJavier Martinez Canillas struct v4l2_of_endpoint bus_cfg; 1254a2e5f1b3SJavier Martinez Canillas struct device_node *ep; 1255a2e5f1b3SJavier Martinez Canillas unsigned int flags; 1256a2e5f1b3SJavier Martinez Canillas int ret = 0; 1257a2e5f1b3SJavier Martinez Canillas 1258a2e5f1b3SJavier Martinez Canillas ep = of_graph_get_next_endpoint(np, NULL); 1259a2e5f1b3SJavier Martinez Canillas if (!ep) 1260a2e5f1b3SJavier Martinez Canillas return -EINVAL; 1261a2e5f1b3SJavier Martinez Canillas 1262a2e5f1b3SJavier Martinez Canillas ret = v4l2_of_parse_endpoint(ep, &bus_cfg); 1263a2e5f1b3SJavier Martinez Canillas if (ret) 1264a2e5f1b3SJavier Martinez Canillas goto err; 1265a2e5f1b3SJavier Martinez Canillas 1266a2e5f1b3SJavier Martinez Canillas flags = bus_cfg.bus.parallel.flags; 1267a2e5f1b3SJavier Martinez Canillas 1268a2e5f1b3SJavier Martinez Canillas if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL && 1269a2e5f1b3SJavier Martinez Canillas !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH && 1270a2e5f1b3SJavier Martinez Canillas flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH && 1271a2e5f1b3SJavier Martinez Canillas flags & V4L2_MBUS_FIELD_EVEN_LOW)) 1272a2e5f1b3SJavier Martinez Canillas return -EINVAL; 1273a2e5f1b3SJavier Martinez Canillas 1274a2e5f1b3SJavier Martinez Canillas decoder->mbus_type = bus_cfg.bus_type; 1275a2e5f1b3SJavier Martinez Canillas 1276a2e5f1b3SJavier Martinez Canillas err: 1277a2e5f1b3SJavier Martinez Canillas of_node_put(ep); 1278a2e5f1b3SJavier Martinez Canillas return ret; 1279a2e5f1b3SJavier Martinez Canillas } 1280a2e5f1b3SJavier Martinez Canillas 1281cb7a01acSMauro Carvalho Chehab static int tvp5150_probe(struct i2c_client *c, 1282cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1283cb7a01acSMauro Carvalho Chehab { 1284cb7a01acSMauro Carvalho Chehab struct tvp5150 *core; 1285cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 1286a2e5f1b3SJavier Martinez Canillas struct device_node *np = c->dev.of_node; 12877871597aSLaurent Pinchart int res; 1288cb7a01acSMauro Carvalho Chehab 1289cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1290cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(c->adapter, 1291cb7a01acSMauro Carvalho Chehab I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 1292cb7a01acSMauro Carvalho Chehab return -EIO; 1293cb7a01acSMauro Carvalho Chehab 129409aa2609SJavier Martinez Canillas res = tvp5150_init(c); 129509aa2609SJavier Martinez Canillas if (res) 129609aa2609SJavier Martinez Canillas return res; 129709aa2609SJavier Martinez Canillas 1298c02b211dSLaurent Pinchart core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL); 1299c02b211dSLaurent Pinchart if (!core) 1300cb7a01acSMauro Carvalho Chehab return -ENOMEM; 1301a2e5f1b3SJavier Martinez Canillas 1302cb7a01acSMauro Carvalho Chehab sd = &core->sd; 1303a2e5f1b3SJavier Martinez Canillas 1304a2e5f1b3SJavier Martinez Canillas if (IS_ENABLED(CONFIG_OF) && np) { 1305a2e5f1b3SJavier Martinez Canillas res = tvp5150_parse_dt(core, np); 1306a2e5f1b3SJavier Martinez Canillas if (res) { 1307a2e5f1b3SJavier Martinez Canillas v4l2_err(sd, "DT parsing error: %d\n", res); 1308a2e5f1b3SJavier Martinez Canillas return res; 1309a2e5f1b3SJavier Martinez Canillas } 1310a2e5f1b3SJavier Martinez Canillas } else { 1311a2e5f1b3SJavier Martinez Canillas /* Default to BT.656 embedded sync */ 1312a2e5f1b3SJavier Martinez Canillas core->mbus_type = V4L2_MBUS_BT656; 1313a2e5f1b3SJavier Martinez Canillas } 1314a2e5f1b3SJavier Martinez Canillas 1315cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); 1316e545ac87SLaurent Pinchart sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1317e545ac87SLaurent Pinchart 1318e545ac87SLaurent Pinchart #if defined(CONFIG_MEDIA_CONTROLLER) 131955606310SMauro Carvalho Chehab core->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; 132055606310SMauro Carvalho Chehab core->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; 132155606310SMauro Carvalho Chehab core->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; 1322f92c70adSMauro Carvalho Chehab 1323f92c70adSMauro Carvalho Chehab sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 1324f92c70adSMauro Carvalho Chehab 132555606310SMauro Carvalho Chehab res = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, core->pads); 1326e545ac87SLaurent Pinchart if (res < 0) 1327e545ac87SLaurent Pinchart return res; 1328e545ac87SLaurent Pinchart #endif 1329cb7a01acSMauro Carvalho Chehab 13307871597aSLaurent Pinchart res = tvp5150_detect_version(core); 1331cb7a01acSMauro Carvalho Chehab if (res < 0) 1332c02b211dSLaurent Pinchart return res; 1333cb7a01acSMauro Carvalho Chehab 1334cb7a01acSMauro Carvalho Chehab core->norm = V4L2_STD_ALL; /* Default is autodetect */ 1335cb7a01acSMauro Carvalho Chehab core->input = TVP5150_COMPOSITE1; 1336cb7a01acSMauro Carvalho Chehab core->enable = 1; 1337cb7a01acSMauro Carvalho Chehab 1338b1950b8dSLaurent Pinchart v4l2_ctrl_handler_init(&core->hdl, 5); 1339cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1340cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 1341cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1342cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 255, 1, 128); 1343cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1344cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, 0, 255, 1, 128); 1345cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1346cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, -128, 127, 1, 0); 1347b1950b8dSLaurent Pinchart v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1348b1950b8dSLaurent Pinchart V4L2_CID_PIXEL_RATE, 27000000, 1349b1950b8dSLaurent Pinchart 27000000, 1, 27000000); 1350cb7a01acSMauro Carvalho Chehab sd->ctrl_handler = &core->hdl; 1351cb7a01acSMauro Carvalho Chehab if (core->hdl.error) { 1352cb7a01acSMauro Carvalho Chehab res = core->hdl.error; 1353c7d97499SJavier Martinez Canillas goto err; 1354cb7a01acSMauro Carvalho Chehab } 1355cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&core->hdl); 1356cb7a01acSMauro Carvalho Chehab 1357cb7a01acSMauro Carvalho Chehab /* Default is no cropping */ 1358cb7a01acSMauro Carvalho Chehab core->rect.top = 0; 1359cb7a01acSMauro Carvalho Chehab if (tvp5150_read_std(sd) & V4L2_STD_525_60) 1360cb7a01acSMauro Carvalho Chehab core->rect.height = TVP5150_V_MAX_525_60; 1361cb7a01acSMauro Carvalho Chehab else 1362cb7a01acSMauro Carvalho Chehab core->rect.height = TVP5150_V_MAX_OTHERS; 1363cb7a01acSMauro Carvalho Chehab core->rect.left = 0; 1364cb7a01acSMauro Carvalho Chehab core->rect.width = TVP5150_H_MAX; 1365cb7a01acSMauro Carvalho Chehab 1366c7d97499SJavier Martinez Canillas res = v4l2_async_register_subdev(sd); 1367c7d97499SJavier Martinez Canillas if (res < 0) 1368c7d97499SJavier Martinez Canillas goto err; 1369c7d97499SJavier Martinez Canillas 1370cb7a01acSMauro Carvalho Chehab if (debug > 1) 1371cb7a01acSMauro Carvalho Chehab tvp5150_log_status(sd); 1372cb7a01acSMauro Carvalho Chehab return 0; 1373c7d97499SJavier Martinez Canillas 1374c7d97499SJavier Martinez Canillas err: 1375c7d97499SJavier Martinez Canillas v4l2_ctrl_handler_free(&core->hdl); 1376c7d97499SJavier Martinez Canillas return res; 1377cb7a01acSMauro Carvalho Chehab } 1378cb7a01acSMauro Carvalho Chehab 1379cb7a01acSMauro Carvalho Chehab static int tvp5150_remove(struct i2c_client *c) 1380cb7a01acSMauro Carvalho Chehab { 1381cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(c); 1382cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1383cb7a01acSMauro Carvalho Chehab 1384cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, 1385cb7a01acSMauro Carvalho Chehab "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", 1386cb7a01acSMauro Carvalho Chehab c->addr << 1); 1387cb7a01acSMauro Carvalho Chehab 1388c7d97499SJavier Martinez Canillas v4l2_async_unregister_subdev(sd); 1389cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&decoder->hdl); 1390cb7a01acSMauro Carvalho Chehab return 0; 1391cb7a01acSMauro Carvalho Chehab } 1392cb7a01acSMauro Carvalho Chehab 1393cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1394cb7a01acSMauro Carvalho Chehab 1395cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvp5150_id[] = { 1396cb7a01acSMauro Carvalho Chehab { "tvp5150", 0 }, 1397cb7a01acSMauro Carvalho Chehab { } 1398cb7a01acSMauro Carvalho Chehab }; 1399cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvp5150_id); 1400cb7a01acSMauro Carvalho Chehab 14017ef930a7SEduard Gavin #if IS_ENABLED(CONFIG_OF) 14027ef930a7SEduard Gavin static const struct of_device_id tvp5150_of_match[] = { 14037ef930a7SEduard Gavin { .compatible = "ti,tvp5150", }, 14047ef930a7SEduard Gavin { /* sentinel */ }, 14057ef930a7SEduard Gavin }; 14067ef930a7SEduard Gavin MODULE_DEVICE_TABLE(of, tvp5150_of_match); 14077ef930a7SEduard Gavin #endif 14087ef930a7SEduard Gavin 1409cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvp5150_driver = { 1410cb7a01acSMauro Carvalho Chehab .driver = { 14117ef930a7SEduard Gavin .of_match_table = of_match_ptr(tvp5150_of_match), 1412cb7a01acSMauro Carvalho Chehab .name = "tvp5150", 1413cb7a01acSMauro Carvalho Chehab }, 1414cb7a01acSMauro Carvalho Chehab .probe = tvp5150_probe, 1415cb7a01acSMauro Carvalho Chehab .remove = tvp5150_remove, 1416cb7a01acSMauro Carvalho Chehab .id_table = tvp5150_id, 1417cb7a01acSMauro Carvalho Chehab }; 1418cb7a01acSMauro Carvalho Chehab 1419cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvp5150_driver); 1420