1cb7a01acSMauro Carvalho Chehab /* 2c43875f6SMauro Carvalho Chehab * tvp5150 - Texas Instruments TVP5150A/AM1 and TVP5151 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 8b802fb99SJavier Martinez Canillas #include <dt-bindings/media/tvp5150.h> 9cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 10cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 11cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 12cb7a01acSMauro Carvalho Chehab #include <linux/delay.h> 1309aa2609SJavier Martinez Canillas #include <linux/gpio/consumer.h> 14cb7a01acSMauro Carvalho Chehab #include <linux/module.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> 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 30c43875f6SMauro Carvalho Chehab MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 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]; 43f7b4b54eSJavier Martinez Canillas struct media_entity input_ent[TVP5150_INPUT_NUM]; 44f7b4b54eSJavier Martinez Canillas struct media_pad input_pad[TVP5150_INPUT_NUM]; 4555606310SMauro Carvalho Chehab #endif 46cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler hdl; 47cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect; 48cb7a01acSMauro Carvalho Chehab 49cb7a01acSMauro Carvalho Chehab v4l2_std_id norm; /* Current set standard */ 50cb7a01acSMauro Carvalho Chehab u32 input; 51cb7a01acSMauro Carvalho Chehab u32 output; 52cb7a01acSMauro Carvalho Chehab int enable; 53a2e5f1b3SJavier Martinez Canillas 5482275133SJavier Martinez Canillas u16 dev_id; 5582275133SJavier Martinez Canillas u16 rom_ver; 5682275133SJavier Martinez Canillas 57a2e5f1b3SJavier Martinez Canillas enum v4l2_mbus_type mbus_type; 58cb7a01acSMauro Carvalho Chehab }; 59cb7a01acSMauro Carvalho Chehab 60cb7a01acSMauro Carvalho Chehab static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) 61cb7a01acSMauro Carvalho Chehab { 62cb7a01acSMauro Carvalho Chehab return container_of(sd, struct tvp5150, sd); 63cb7a01acSMauro Carvalho Chehab } 64cb7a01acSMauro Carvalho Chehab 65cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 66cb7a01acSMauro Carvalho Chehab { 67cb7a01acSMauro Carvalho Chehab return &container_of(ctrl->handler, struct tvp5150, hdl)->sd; 68cb7a01acSMauro Carvalho Chehab } 69cb7a01acSMauro Carvalho Chehab 70cb7a01acSMauro Carvalho Chehab static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) 71cb7a01acSMauro Carvalho Chehab { 72cb7a01acSMauro Carvalho Chehab struct i2c_client *c = v4l2_get_subdevdata(sd); 73cb7a01acSMauro Carvalho Chehab int rc; 74cb7a01acSMauro Carvalho Chehab 75e35ce2e4SLaurent Pinchart rc = i2c_smbus_read_byte_data(c, addr); 76e35ce2e4SLaurent Pinchart if (rc < 0) { 77e35ce2e4SLaurent Pinchart v4l2_err(sd, "i2c i/o error: rc == %d\n", rc); 78e35ce2e4SLaurent Pinchart return rc; 79cb7a01acSMauro Carvalho Chehab } 80cb7a01acSMauro Carvalho Chehab 81e35ce2e4SLaurent Pinchart v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, rc); 82cb7a01acSMauro Carvalho Chehab 83e35ce2e4SLaurent Pinchart return rc; 84cb7a01acSMauro Carvalho Chehab } 85cb7a01acSMauro Carvalho Chehab 86cacdd6a4SJavier Martinez Canillas static int tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, 87cb7a01acSMauro Carvalho Chehab unsigned char value) 88cb7a01acSMauro Carvalho Chehab { 89cb7a01acSMauro Carvalho Chehab struct i2c_client *c = v4l2_get_subdevdata(sd); 90cb7a01acSMauro Carvalho Chehab int rc; 91cb7a01acSMauro Carvalho Chehab 92e35ce2e4SLaurent Pinchart v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value); 93e35ce2e4SLaurent Pinchart rc = i2c_smbus_write_byte_data(c, addr, value); 94e35ce2e4SLaurent Pinchart if (rc < 0) 95cacdd6a4SJavier Martinez Canillas v4l2_err(sd, "i2c i/o error: rc == %d\n", rc); 96cacdd6a4SJavier Martinez Canillas 97cacdd6a4SJavier Martinez Canillas return rc; 98cb7a01acSMauro Carvalho Chehab } 99cb7a01acSMauro Carvalho Chehab 100cb7a01acSMauro Carvalho Chehab static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, 101cb7a01acSMauro Carvalho Chehab const u8 end, int max_line) 102cb7a01acSMauro Carvalho Chehab { 103cb7a01acSMauro Carvalho Chehab int i = 0; 104cb7a01acSMauro Carvalho Chehab 105cb7a01acSMauro Carvalho Chehab while (init != (u8)(end + 1)) { 106cb7a01acSMauro Carvalho Chehab if ((i % max_line) == 0) { 107cb7a01acSMauro Carvalho Chehab if (i > 0) 108cb7a01acSMauro Carvalho Chehab printk("\n"); 109cb7a01acSMauro Carvalho Chehab printk("tvp5150: %s reg 0x%02x = ", s, init); 110cb7a01acSMauro Carvalho Chehab } 111cb7a01acSMauro Carvalho Chehab printk("%02x ", tvp5150_read(sd, init)); 112cb7a01acSMauro Carvalho Chehab 113cb7a01acSMauro Carvalho Chehab init++; 114cb7a01acSMauro Carvalho Chehab i++; 115cb7a01acSMauro Carvalho Chehab } 116cb7a01acSMauro Carvalho Chehab printk("\n"); 117cb7a01acSMauro Carvalho Chehab } 118cb7a01acSMauro Carvalho Chehab 119cb7a01acSMauro Carvalho Chehab static int tvp5150_log_status(struct v4l2_subdev *sd) 120cb7a01acSMauro Carvalho Chehab { 121cb7a01acSMauro Carvalho Chehab printk("tvp5150: Video input source selection #1 = 0x%02x\n", 122cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); 123cb7a01acSMauro Carvalho Chehab printk("tvp5150: Analog channel controls = 0x%02x\n", 124cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); 125cb7a01acSMauro Carvalho Chehab printk("tvp5150: Operation mode controls = 0x%02x\n", 126cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_OP_MODE_CTL)); 127cb7a01acSMauro Carvalho Chehab printk("tvp5150: Miscellaneous controls = 0x%02x\n", 128cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MISC_CTL)); 129cb7a01acSMauro Carvalho Chehab printk("tvp5150: Autoswitch mask= 0x%02x\n", 130cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_AUTOSW_MSK)); 131cb7a01acSMauro Carvalho Chehab printk("tvp5150: Color killer threshold control = 0x%02x\n", 132cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); 133cb7a01acSMauro Carvalho Chehab printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", 134cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), 135cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), 136cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); 137cb7a01acSMauro Carvalho Chehab printk("tvp5150: Brightness control = 0x%02x\n", 138cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_BRIGHT_CTL)); 139cb7a01acSMauro Carvalho Chehab printk("tvp5150: Color saturation control = 0x%02x\n", 140cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_SATURATION_CTL)); 141cb7a01acSMauro Carvalho Chehab printk("tvp5150: Hue control = 0x%02x\n", 142cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HUE_CTL)); 143cb7a01acSMauro Carvalho Chehab printk("tvp5150: Contrast control = 0x%02x\n", 144cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONTRAST_CTL)); 145cb7a01acSMauro Carvalho Chehab printk("tvp5150: Outputs and data rates select = 0x%02x\n", 146cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); 147cb7a01acSMauro Carvalho Chehab printk("tvp5150: Configuration shared pins = 0x%02x\n", 148cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); 149cb7a01acSMauro Carvalho Chehab printk("tvp5150: Active video cropping start = 0x%02x%02x\n", 150cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), 151cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); 152cb7a01acSMauro Carvalho Chehab printk("tvp5150: Active video cropping stop = 0x%02x%02x\n", 153cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), 154cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); 155cb7a01acSMauro Carvalho Chehab printk("tvp5150: Genlock/RTC = 0x%02x\n", 156cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_GENLOCK)); 157cb7a01acSMauro Carvalho Chehab printk("tvp5150: Horizontal sync start = 0x%02x\n", 158cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); 159cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical blanking start = 0x%02x\n", 160cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); 161cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical blanking stop = 0x%02x\n", 162cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); 163cb7a01acSMauro Carvalho Chehab printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", 164cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), 165cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); 166cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt reset register B = 0x%02x\n", 167cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); 168cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt enable register B = 0x%02x\n", 169cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); 170cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt configuration register B = 0x%02x\n", 171cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); 172cb7a01acSMauro Carvalho Chehab printk("tvp5150: Video standard = 0x%02x\n", 173cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VIDEO_STD)); 174cb7a01acSMauro Carvalho Chehab printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", 175cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CB_GAIN_FACT), 176cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); 177cb7a01acSMauro Carvalho Chehab printk("tvp5150: Macrovision on counter = 0x%02x\n", 178cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); 179cb7a01acSMauro Carvalho Chehab printk("tvp5150: Macrovision off counter = 0x%02x\n", 180cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); 181cb7a01acSMauro Carvalho Chehab printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", 182cb7a01acSMauro Carvalho Chehab (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); 183cb7a01acSMauro Carvalho Chehab printk("tvp5150: Device ID = %02x%02x\n", 184cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MSB_DEV_ID), 185cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LSB_DEV_ID)); 186cb7a01acSMauro Carvalho Chehab printk("tvp5150: ROM version = (hex) %02x.%02x\n", 187cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), 188cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); 189cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical line count = 0x%02x%02x\n", 190cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), 191cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); 192cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt status register B = 0x%02x\n", 193cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); 194cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt active register B = 0x%02x\n", 195cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); 196cb7a01acSMauro Carvalho Chehab printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", 197cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_1), 198cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_2), 199cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_3), 200cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_4), 201cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_5)); 202cb7a01acSMauro Carvalho Chehab 203cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, 204cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL1_END, 8); 205cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, 206cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL2_END, 8); 207cb7a01acSMauro Carvalho Chehab 208cb7a01acSMauro Carvalho Chehab printk("tvp5150: Teletext filter enable = 0x%02x\n", 209cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); 210cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt status register A = 0x%02x\n", 211cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); 212cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt enable register A = 0x%02x\n", 213cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); 214cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt configuration = 0x%02x\n", 215cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_CONF)); 216cb7a01acSMauro Carvalho Chehab printk("tvp5150: VDP status register = 0x%02x\n", 217cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); 218cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO word count = 0x%02x\n", 219cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); 220cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO interrupt threshold = 0x%02x\n", 221cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); 222cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO reset = 0x%02x\n", 223cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_RESET)); 224cb7a01acSMauro Carvalho Chehab printk("tvp5150: Line number interrupt = 0x%02x\n", 225cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); 226cb7a01acSMauro Carvalho Chehab printk("tvp5150: Pixel alignment register = 0x%02x%02x\n", 227cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), 228cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); 229cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO output control = 0x%02x\n", 230cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); 231cb7a01acSMauro Carvalho Chehab printk("tvp5150: Full field enable = 0x%02x\n", 232cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); 233cb7a01acSMauro Carvalho Chehab printk("tvp5150: Full field mode register = 0x%02x\n", 234cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); 235cb7a01acSMauro Carvalho Chehab 236cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI, 237cb7a01acSMauro Carvalho Chehab TVP5150_CC_DATA_END, 8); 238cb7a01acSMauro Carvalho Chehab 239cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "WSS data", TVP5150_WSS_DATA_INI, 240cb7a01acSMauro Carvalho Chehab TVP5150_WSS_DATA_END, 8); 241cb7a01acSMauro Carvalho Chehab 242cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VPS data", TVP5150_VPS_DATA_INI, 243cb7a01acSMauro Carvalho Chehab TVP5150_VPS_DATA_END, 8); 244cb7a01acSMauro Carvalho Chehab 245cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VITC data", TVP5150_VITC_DATA_INI, 246cb7a01acSMauro Carvalho Chehab TVP5150_VITC_DATA_END, 10); 247cb7a01acSMauro Carvalho Chehab 248cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Line mode", TVP5150_LINE_MODE_INI, 249cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_END, 8); 250cb7a01acSMauro Carvalho Chehab return 0; 251cb7a01acSMauro Carvalho Chehab } 252cb7a01acSMauro Carvalho Chehab 253cb7a01acSMauro Carvalho Chehab /**************************************************************************** 254cb7a01acSMauro Carvalho Chehab Basic functions 255cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 256cb7a01acSMauro Carvalho Chehab 257cb7a01acSMauro Carvalho Chehab static inline void tvp5150_selmux(struct v4l2_subdev *sd) 258cb7a01acSMauro Carvalho Chehab { 259cb7a01acSMauro Carvalho Chehab int opmode = 0; 260cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 261cb7a01acSMauro Carvalho Chehab int input = 0; 262cb7a01acSMauro Carvalho Chehab int val; 263cb7a01acSMauro Carvalho Chehab 264c43875f6SMauro Carvalho Chehab /* Only tvp5150am1 and tvp5151 have signal generator support */ 265c43875f6SMauro Carvalho Chehab if ((decoder->dev_id == 0x5150 && decoder->rom_ver == 0x0400) || 266c43875f6SMauro Carvalho Chehab (decoder->dev_id == 0x5151 && decoder->rom_ver == 0x0100)) { 267c43875f6SMauro Carvalho Chehab if (!decoder->enable) 268cb7a01acSMauro Carvalho Chehab input = 8; 269c43875f6SMauro Carvalho Chehab } 270cb7a01acSMauro Carvalho Chehab 271cb7a01acSMauro Carvalho Chehab switch (decoder->input) { 272cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE1: 273cb7a01acSMauro Carvalho Chehab input |= 2; 274cb7a01acSMauro Carvalho Chehab /* fall through */ 275cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE0: 276cb7a01acSMauro Carvalho Chehab break; 277cb7a01acSMauro Carvalho Chehab case TVP5150_SVIDEO: 278cb7a01acSMauro Carvalho Chehab default: 279cb7a01acSMauro Carvalho Chehab input |= 1; 280cb7a01acSMauro Carvalho Chehab break; 281cb7a01acSMauro Carvalho Chehab } 282cb7a01acSMauro Carvalho Chehab 283cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i " 284cb7a01acSMauro Carvalho Chehab "=> tvp5150 input=%i, opmode=%i\n", 285cb7a01acSMauro Carvalho Chehab decoder->input, decoder->output, 286cb7a01acSMauro Carvalho Chehab input, opmode); 287cb7a01acSMauro Carvalho Chehab 288cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode); 289cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input); 290cb7a01acSMauro Carvalho Chehab 291cb7a01acSMauro Carvalho Chehab /* Svideo should enable YCrCb output and disable GPCL output 292cb7a01acSMauro Carvalho Chehab * For Composite and TV, it should be the reverse 293cb7a01acSMauro Carvalho Chehab */ 294cb7a01acSMauro Carvalho Chehab val = tvp5150_read(sd, TVP5150_MISC_CTL); 295cb7a01acSMauro Carvalho Chehab if (val < 0) { 296cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", __func__, val); 297cb7a01acSMauro Carvalho Chehab return; 298cb7a01acSMauro Carvalho Chehab } 299cb7a01acSMauro Carvalho Chehab 300cb7a01acSMauro Carvalho Chehab if (decoder->input == TVP5150_SVIDEO) 301cb7a01acSMauro Carvalho Chehab val = (val & ~0x40) | 0x10; 302cb7a01acSMauro Carvalho Chehab else 303cb7a01acSMauro Carvalho Chehab val = (val & ~0x10) | 0x40; 304cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_MISC_CTL, val); 305cb7a01acSMauro Carvalho Chehab }; 306cb7a01acSMauro Carvalho Chehab 307cb7a01acSMauro Carvalho Chehab struct i2c_reg_value { 308cb7a01acSMauro Carvalho Chehab unsigned char reg; 309cb7a01acSMauro Carvalho Chehab unsigned char value; 310cb7a01acSMauro Carvalho Chehab }; 311cb7a01acSMauro Carvalho Chehab 312cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 313cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_default[] = { 314cb7a01acSMauro Carvalho Chehab { /* 0x00 */ 315cb7a01acSMauro Carvalho Chehab TVP5150_VD_IN_SRC_SEL_1,0x00 316cb7a01acSMauro Carvalho Chehab }, 317cb7a01acSMauro Carvalho Chehab { /* 0x01 */ 318cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL,0x15 319cb7a01acSMauro Carvalho Chehab }, 320cb7a01acSMauro Carvalho Chehab { /* 0x02 */ 321cb7a01acSMauro Carvalho Chehab TVP5150_OP_MODE_CTL,0x00 322cb7a01acSMauro Carvalho Chehab }, 323cb7a01acSMauro Carvalho Chehab { /* 0x03 */ 324cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL,0x01 325cb7a01acSMauro Carvalho Chehab }, 326cb7a01acSMauro Carvalho Chehab { /* 0x06 */ 327cb7a01acSMauro Carvalho Chehab TVP5150_COLOR_KIL_THSH_CTL,0x10 328cb7a01acSMauro Carvalho Chehab }, 329cb7a01acSMauro Carvalho Chehab { /* 0x07 */ 330cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_1,0x60 331cb7a01acSMauro Carvalho Chehab }, 332cb7a01acSMauro Carvalho Chehab { /* 0x08 */ 333cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_2,0x00 334cb7a01acSMauro Carvalho Chehab }, 335cb7a01acSMauro Carvalho Chehab { /* 0x09 */ 336cb7a01acSMauro Carvalho Chehab TVP5150_BRIGHT_CTL,0x80 337cb7a01acSMauro Carvalho Chehab }, 338cb7a01acSMauro Carvalho Chehab { /* 0x0a */ 339cb7a01acSMauro Carvalho Chehab TVP5150_SATURATION_CTL,0x80 340cb7a01acSMauro Carvalho Chehab }, 341cb7a01acSMauro Carvalho Chehab { /* 0x0b */ 342cb7a01acSMauro Carvalho Chehab TVP5150_HUE_CTL,0x00 343cb7a01acSMauro Carvalho Chehab }, 344cb7a01acSMauro Carvalho Chehab { /* 0x0c */ 345cb7a01acSMauro Carvalho Chehab TVP5150_CONTRAST_CTL,0x80 346cb7a01acSMauro Carvalho Chehab }, 347cb7a01acSMauro Carvalho Chehab { /* 0x0d */ 348cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL,0x47 349cb7a01acSMauro Carvalho Chehab }, 350cb7a01acSMauro Carvalho Chehab { /* 0x0e */ 351cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_3,0x00 352cb7a01acSMauro Carvalho Chehab }, 353cb7a01acSMauro Carvalho Chehab { /* 0x0f */ 354cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN,0x08 355cb7a01acSMauro Carvalho Chehab }, 356cb7a01acSMauro Carvalho Chehab { /* 0x11 */ 357cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_MSB,0x00 358cb7a01acSMauro Carvalho Chehab }, 359cb7a01acSMauro Carvalho Chehab { /* 0x12 */ 360cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_LSB,0x00 361cb7a01acSMauro Carvalho Chehab }, 362cb7a01acSMauro Carvalho Chehab { /* 0x13 */ 363cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_MSB,0x00 364cb7a01acSMauro Carvalho Chehab }, 365cb7a01acSMauro Carvalho Chehab { /* 0x14 */ 366cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_LSB,0x00 367cb7a01acSMauro Carvalho Chehab }, 368cb7a01acSMauro Carvalho Chehab { /* 0x15 */ 369cb7a01acSMauro Carvalho Chehab TVP5150_GENLOCK,0x01 370cb7a01acSMauro Carvalho Chehab }, 371cb7a01acSMauro Carvalho Chehab { /* 0x16 */ 372cb7a01acSMauro Carvalho Chehab TVP5150_HORIZ_SYNC_START,0x80 373cb7a01acSMauro Carvalho Chehab }, 374cb7a01acSMauro Carvalho Chehab { /* 0x18 */ 375cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_START,0x00 376cb7a01acSMauro Carvalho Chehab }, 377cb7a01acSMauro Carvalho Chehab { /* 0x19 */ 378cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_STOP,0x00 379cb7a01acSMauro Carvalho Chehab }, 380cb7a01acSMauro Carvalho Chehab { /* 0x1a */ 381cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1,0x0c 382cb7a01acSMauro Carvalho Chehab }, 383cb7a01acSMauro Carvalho Chehab { /* 0x1b */ 384cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2,0x14 385cb7a01acSMauro Carvalho Chehab }, 386cb7a01acSMauro Carvalho Chehab { /* 0x1c */ 387cb7a01acSMauro Carvalho Chehab TVP5150_INT_RESET_REG_B,0x00 388cb7a01acSMauro Carvalho Chehab }, 389cb7a01acSMauro Carvalho Chehab { /* 0x1d */ 390cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_B,0x00 391cb7a01acSMauro Carvalho Chehab }, 392cb7a01acSMauro Carvalho Chehab { /* 0x1e */ 393cb7a01acSMauro Carvalho Chehab TVP5150_INTT_CONFIG_REG_B,0x00 394cb7a01acSMauro Carvalho Chehab }, 395cb7a01acSMauro Carvalho Chehab { /* 0x28 */ 396cb7a01acSMauro Carvalho Chehab TVP5150_VIDEO_STD,0x00 397cb7a01acSMauro Carvalho Chehab }, 398cb7a01acSMauro Carvalho Chehab { /* 0x2e */ 399cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_ON_CTR,0x0f 400cb7a01acSMauro Carvalho Chehab }, 401cb7a01acSMauro Carvalho Chehab { /* 0x2f */ 402cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_OFF_CTR,0x01 403cb7a01acSMauro Carvalho Chehab }, 404cb7a01acSMauro Carvalho Chehab { /* 0xbb */ 405cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL_ENA,0x00 406cb7a01acSMauro Carvalho Chehab }, 407cb7a01acSMauro Carvalho Chehab { /* 0xc0 */ 408cb7a01acSMauro Carvalho Chehab TVP5150_INT_STATUS_REG_A,0x00 409cb7a01acSMauro Carvalho Chehab }, 410cb7a01acSMauro Carvalho Chehab { /* 0xc1 */ 411cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_A,0x00 412cb7a01acSMauro Carvalho Chehab }, 413cb7a01acSMauro Carvalho Chehab { /* 0xc2 */ 414cb7a01acSMauro Carvalho Chehab TVP5150_INT_CONF,0x04 415cb7a01acSMauro Carvalho Chehab }, 416cb7a01acSMauro Carvalho Chehab { /* 0xc8 */ 417cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_INT_THRESHOLD,0x80 418cb7a01acSMauro Carvalho Chehab }, 419cb7a01acSMauro Carvalho Chehab { /* 0xc9 */ 420cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_RESET,0x00 421cb7a01acSMauro Carvalho Chehab }, 422cb7a01acSMauro Carvalho Chehab { /* 0xca */ 423cb7a01acSMauro Carvalho Chehab TVP5150_LINE_NUMBER_INT,0x00 424cb7a01acSMauro Carvalho Chehab }, 425cb7a01acSMauro Carvalho Chehab { /* 0xcb */ 426cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_LOW,0x4e 427cb7a01acSMauro Carvalho Chehab }, 428cb7a01acSMauro Carvalho Chehab { /* 0xcc */ 429cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_HIGH,0x00 430cb7a01acSMauro Carvalho Chehab }, 431cb7a01acSMauro Carvalho Chehab { /* 0xcd */ 432cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_OUT_CTRL,0x01 433cb7a01acSMauro Carvalho Chehab }, 434cb7a01acSMauro Carvalho Chehab { /* 0xcf */ 435cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_ENA,0x00 436cb7a01acSMauro Carvalho Chehab }, 437cb7a01acSMauro Carvalho Chehab { /* 0xd0 */ 438cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_INI,0x00 439cb7a01acSMauro Carvalho Chehab }, 440cb7a01acSMauro Carvalho Chehab { /* 0xfc */ 441cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_MODE_REG,0x7f 442cb7a01acSMauro Carvalho Chehab }, 443cb7a01acSMauro Carvalho Chehab { /* end of data */ 444cb7a01acSMauro Carvalho Chehab 0xff,0xff 445cb7a01acSMauro Carvalho Chehab } 446cb7a01acSMauro Carvalho Chehab }; 447cb7a01acSMauro Carvalho Chehab 448cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 449cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_enable[] = { 450cb7a01acSMauro Carvalho Chehab { 451cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN, 2 452cb7a01acSMauro Carvalho Chehab },{ /* Automatic offset and AGC enabled */ 453cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 454cb7a01acSMauro Carvalho Chehab },{ /* Activate YCrCb output 0x9 or 0xd ? */ 455cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL, 0x6f 456cb7a01acSMauro Carvalho Chehab },{ /* Activates video std autodetection for all standards */ 457cb7a01acSMauro Carvalho Chehab TVP5150_AUTOSW_MSK, 0x0 458cb7a01acSMauro Carvalho Chehab },{ /* Default format: 0x47. For 4:2:2: 0x40 */ 459cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 460cb7a01acSMauro Carvalho Chehab },{ 461cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 462cb7a01acSMauro Carvalho Chehab },{ 463cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x54 464cb7a01acSMauro Carvalho Chehab },{ /* Non documented, but initialized on WinTV USB2 */ 465cb7a01acSMauro Carvalho Chehab 0x27, 0x20 466cb7a01acSMauro Carvalho Chehab },{ 467cb7a01acSMauro Carvalho Chehab 0xff,0xff 468cb7a01acSMauro Carvalho Chehab } 469cb7a01acSMauro Carvalho Chehab }; 470cb7a01acSMauro Carvalho Chehab 471cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type { 472cb7a01acSMauro Carvalho Chehab unsigned int vbi_type; 473cb7a01acSMauro Carvalho Chehab unsigned int ini_line; 474cb7a01acSMauro Carvalho Chehab unsigned int end_line; 475cb7a01acSMauro Carvalho Chehab unsigned int by_field :1; 476cb7a01acSMauro Carvalho Chehab }; 477cb7a01acSMauro Carvalho Chehab 478cb7a01acSMauro Carvalho Chehab struct i2c_vbi_ram_value { 479cb7a01acSMauro Carvalho Chehab u16 reg; 480cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type type; 481cb7a01acSMauro Carvalho Chehab unsigned char values[16]; 482cb7a01acSMauro Carvalho Chehab }; 483cb7a01acSMauro Carvalho Chehab 484cb7a01acSMauro Carvalho Chehab /* This struct have the values for each supported VBI Standard 485cb7a01acSMauro Carvalho Chehab * by 486cb7a01acSMauro Carvalho Chehab tvp5150_vbi_types should follow the same order as vbi_ram_default 487cb7a01acSMauro Carvalho Chehab * value 0 means rom position 0x10, value 1 means rom position 0x30 488cb7a01acSMauro Carvalho Chehab * and so on. There are 16 possible locations from 0 to 15. 489cb7a01acSMauro Carvalho Chehab */ 490cb7a01acSMauro Carvalho Chehab 491cb7a01acSMauro Carvalho Chehab static struct i2c_vbi_ram_value vbi_ram_default[] = 492cb7a01acSMauro Carvalho Chehab { 493cb7a01acSMauro Carvalho Chehab /* FIXME: Current api doesn't handle all VBI types, those not 494cb7a01acSMauro Carvalho Chehab yet supported are placed under #if 0 */ 495cb7a01acSMauro Carvalho Chehab #if 0 496cb7a01acSMauro Carvalho Chehab {0x010, /* Teletext, SECAM, WST System A */ 497cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, 498cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 499cb7a01acSMauro Carvalho Chehab 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } 500cb7a01acSMauro Carvalho Chehab }, 501cb7a01acSMauro Carvalho Chehab #endif 502cb7a01acSMauro Carvalho Chehab {0x030, /* Teletext, PAL, WST System B */ 503cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_B,6,22,1}, 504cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 505cb7a01acSMauro Carvalho Chehab 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } 506cb7a01acSMauro Carvalho Chehab }, 507cb7a01acSMauro Carvalho Chehab #if 0 508cb7a01acSMauro Carvalho Chehab {0x050, /* Teletext, PAL, WST System C */ 509cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, 510cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 511cb7a01acSMauro Carvalho Chehab 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 512cb7a01acSMauro Carvalho Chehab }, 513cb7a01acSMauro Carvalho Chehab {0x070, /* Teletext, NTSC, WST System B */ 514cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, 515cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, 516cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 517cb7a01acSMauro Carvalho Chehab }, 518cb7a01acSMauro Carvalho Chehab {0x090, /* Tetetext, NTSC NABTS System C */ 519cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, 520cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 521cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } 522cb7a01acSMauro Carvalho Chehab }, 523cb7a01acSMauro Carvalho Chehab {0x0b0, /* Teletext, NTSC-J, NABTS System D */ 524cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, 525cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, 526cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 527cb7a01acSMauro Carvalho Chehab }, 528cb7a01acSMauro Carvalho Chehab {0x0d0, /* Closed Caption, PAL/SECAM */ 529cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_625,22,22,1}, 530cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 531cb7a01acSMauro Carvalho Chehab 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 532cb7a01acSMauro Carvalho Chehab }, 533cb7a01acSMauro Carvalho Chehab #endif 534cb7a01acSMauro Carvalho Chehab {0x0f0, /* Closed Caption, NTSC */ 535cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_525,21,21,1}, 536cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 537cb7a01acSMauro Carvalho Chehab 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 538cb7a01acSMauro Carvalho Chehab }, 539cb7a01acSMauro Carvalho Chehab {0x110, /* Wide Screen Signal, PAL/SECAM */ 540cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_625,23,23,1}, 541cb7a01acSMauro Carvalho Chehab { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 542cb7a01acSMauro Carvalho Chehab 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } 543cb7a01acSMauro Carvalho Chehab }, 544cb7a01acSMauro Carvalho Chehab #if 0 545cb7a01acSMauro Carvalho Chehab {0x130, /* Wide Screen Signal, NTSC C */ 546cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_525,20,20,1}, 547cb7a01acSMauro Carvalho Chehab { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, 548cb7a01acSMauro Carvalho Chehab 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } 549cb7a01acSMauro Carvalho Chehab }, 550cb7a01acSMauro Carvalho Chehab {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ 551cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_625,6,22,0}, 552cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 553cb7a01acSMauro Carvalho Chehab 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 554cb7a01acSMauro Carvalho Chehab }, 555cb7a01acSMauro Carvalho Chehab {0x170, /* Vertical Interval Timecode (VITC), NTSC */ 556cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_525,10,20,0}, 557cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 558cb7a01acSMauro Carvalho Chehab 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 559cb7a01acSMauro Carvalho Chehab }, 560cb7a01acSMauro Carvalho Chehab #endif 561cb7a01acSMauro Carvalho Chehab {0x190, /* Video Program System (VPS), PAL */ 562cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_VPS,16,16,0}, 563cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, 564cb7a01acSMauro Carvalho Chehab 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } 565cb7a01acSMauro Carvalho Chehab }, 566cb7a01acSMauro Carvalho Chehab /* 0x1d0 User programmable */ 567cb7a01acSMauro Carvalho Chehab 568cb7a01acSMauro Carvalho Chehab /* End of struct */ 569cb7a01acSMauro Carvalho Chehab { (u16)-1 } 570cb7a01acSMauro Carvalho Chehab }; 571cb7a01acSMauro Carvalho Chehab 572cb7a01acSMauro Carvalho Chehab static int tvp5150_write_inittab(struct v4l2_subdev *sd, 573cb7a01acSMauro Carvalho Chehab const struct i2c_reg_value *regs) 574cb7a01acSMauro Carvalho Chehab { 575cb7a01acSMauro Carvalho Chehab while (regs->reg != 0xff) { 576cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, regs->reg, regs->value); 577cb7a01acSMauro Carvalho Chehab regs++; 578cb7a01acSMauro Carvalho Chehab } 579cb7a01acSMauro Carvalho Chehab return 0; 580cb7a01acSMauro Carvalho Chehab } 581cb7a01acSMauro Carvalho Chehab 582cb7a01acSMauro Carvalho Chehab static int tvp5150_vdp_init(struct v4l2_subdev *sd, 583cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs) 584cb7a01acSMauro Carvalho Chehab { 585cb7a01acSMauro Carvalho Chehab unsigned int i; 586cb7a01acSMauro Carvalho Chehab 587cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 588cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); 589cb7a01acSMauro Carvalho Chehab 590cb7a01acSMauro Carvalho Chehab /* Before programming, Line mode should be at 0xff */ 591cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 592cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, i, 0xff); 593cb7a01acSMauro Carvalho Chehab 594cb7a01acSMauro Carvalho Chehab /* Load Ram Table */ 595cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1) { 596cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); 597cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); 598cb7a01acSMauro Carvalho Chehab 599cb7a01acSMauro Carvalho Chehab for (i = 0; i < 16; i++) 600cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]); 601cb7a01acSMauro Carvalho Chehab 602cb7a01acSMauro Carvalho Chehab regs++; 603cb7a01acSMauro Carvalho Chehab } 604cb7a01acSMauro Carvalho Chehab return 0; 605cb7a01acSMauro Carvalho Chehab } 606cb7a01acSMauro Carvalho Chehab 607cb7a01acSMauro Carvalho Chehab /* Fills VBI capabilities based on i2c_vbi_ram_value struct */ 608cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, 609cb7a01acSMauro Carvalho Chehab struct v4l2_sliced_vbi_cap *cap) 610cb7a01acSMauro Carvalho Chehab { 611cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = vbi_ram_default; 612cb7a01acSMauro Carvalho Chehab int line; 613cb7a01acSMauro Carvalho Chehab 614cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n"); 615cb7a01acSMauro Carvalho Chehab memset(cap, 0, sizeof *cap); 616cb7a01acSMauro Carvalho Chehab 617cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1 ) { 618cb7a01acSMauro Carvalho Chehab for (line=regs->type.ini_line;line<=regs->type.end_line;line++) { 619cb7a01acSMauro Carvalho Chehab cap->service_lines[0][line] |= regs->type.vbi_type; 620cb7a01acSMauro Carvalho Chehab } 621cb7a01acSMauro Carvalho Chehab cap->service_set |= regs->type.vbi_type; 622cb7a01acSMauro Carvalho Chehab 623cb7a01acSMauro Carvalho Chehab regs++; 624cb7a01acSMauro Carvalho Chehab } 625cb7a01acSMauro Carvalho Chehab return 0; 626cb7a01acSMauro Carvalho Chehab } 627cb7a01acSMauro Carvalho Chehab 628cb7a01acSMauro Carvalho Chehab /* Set vbi processing 629cb7a01acSMauro Carvalho Chehab * type - one of tvp5150_vbi_types 630cb7a01acSMauro Carvalho Chehab * line - line to gather data 631cb7a01acSMauro Carvalho Chehab * fields: bit 0 field1, bit 1, field2 632cb7a01acSMauro Carvalho Chehab * flags (default=0xf0) is a bitmask, were set means: 633cb7a01acSMauro Carvalho Chehab * bit 7: enable filtering null bytes on CC 634cb7a01acSMauro Carvalho Chehab * bit 6: send data also to FIFO 635cb7a01acSMauro Carvalho Chehab * bit 5: don't allow data with errors on FIFO 636cb7a01acSMauro Carvalho Chehab * bit 4: enable ECC when possible 637cb7a01acSMauro Carvalho Chehab * pix_align = pix alignment: 638cb7a01acSMauro Carvalho Chehab * LSB = field1 639cb7a01acSMauro Carvalho Chehab * MSB = field2 640cb7a01acSMauro Carvalho Chehab */ 641cb7a01acSMauro Carvalho Chehab static int tvp5150_set_vbi(struct v4l2_subdev *sd, 642cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs, 643cb7a01acSMauro Carvalho Chehab unsigned int type,u8 flags, int line, 644cb7a01acSMauro Carvalho Chehab const int fields) 645cb7a01acSMauro Carvalho Chehab { 646cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 647cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 648cb7a01acSMauro Carvalho Chehab u8 reg; 649cb7a01acSMauro Carvalho Chehab int pos=0; 650cb7a01acSMauro Carvalho Chehab 651cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 652cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); 653cb7a01acSMauro Carvalho Chehab return 0; 654cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 655cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 656cb7a01acSMauro Carvalho Chehab line += 3; 657cb7a01acSMauro Carvalho Chehab } 658cb7a01acSMauro Carvalho Chehab 659cb7a01acSMauro Carvalho Chehab if (line<6||line>27) 660cb7a01acSMauro Carvalho Chehab return 0; 661cb7a01acSMauro Carvalho Chehab 662cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1 ) { 663cb7a01acSMauro Carvalho Chehab if ((type & regs->type.vbi_type) && 664cb7a01acSMauro Carvalho Chehab (line>=regs->type.ini_line) && 665cb7a01acSMauro Carvalho Chehab (line<=regs->type.end_line)) { 666cb7a01acSMauro Carvalho Chehab type=regs->type.vbi_type; 667cb7a01acSMauro Carvalho Chehab break; 668cb7a01acSMauro Carvalho Chehab } 669cb7a01acSMauro Carvalho Chehab 670cb7a01acSMauro Carvalho Chehab regs++; 671cb7a01acSMauro Carvalho Chehab pos++; 672cb7a01acSMauro Carvalho Chehab } 673cb7a01acSMauro Carvalho Chehab if (regs->reg == (u16)-1) 674cb7a01acSMauro Carvalho Chehab return 0; 675cb7a01acSMauro Carvalho Chehab 676cb7a01acSMauro Carvalho Chehab type=pos | (flags & 0xf0); 677cb7a01acSMauro Carvalho Chehab reg=((line-6)<<1)+TVP5150_LINE_MODE_INI; 678cb7a01acSMauro Carvalho Chehab 679cb7a01acSMauro Carvalho Chehab if (fields&1) { 680cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg, type); 681cb7a01acSMauro Carvalho Chehab } 682cb7a01acSMauro Carvalho Chehab 683cb7a01acSMauro Carvalho Chehab if (fields&2) { 684cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg+1, type); 685cb7a01acSMauro Carvalho Chehab } 686cb7a01acSMauro Carvalho Chehab 687cb7a01acSMauro Carvalho Chehab return type; 688cb7a01acSMauro Carvalho Chehab } 689cb7a01acSMauro Carvalho Chehab 690cb7a01acSMauro Carvalho Chehab static int tvp5150_get_vbi(struct v4l2_subdev *sd, 691cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs, int line) 692cb7a01acSMauro Carvalho Chehab { 693cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 694cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 695cb7a01acSMauro Carvalho Chehab u8 reg; 696cb7a01acSMauro Carvalho Chehab int pos, type = 0; 697cb7a01acSMauro Carvalho Chehab int i, ret = 0; 698cb7a01acSMauro Carvalho Chehab 699cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 700cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); 701cb7a01acSMauro Carvalho Chehab return 0; 702cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 703cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 704cb7a01acSMauro Carvalho Chehab line += 3; 705cb7a01acSMauro Carvalho Chehab } 706cb7a01acSMauro Carvalho Chehab 707cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 708cb7a01acSMauro Carvalho Chehab return 0; 709cb7a01acSMauro Carvalho Chehab 710cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 711cb7a01acSMauro Carvalho Chehab 712cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 1; i++) { 713cb7a01acSMauro Carvalho Chehab ret = tvp5150_read(sd, reg + i); 714cb7a01acSMauro Carvalho Chehab if (ret < 0) { 715cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", 716cb7a01acSMauro Carvalho Chehab __func__, ret); 717cb7a01acSMauro Carvalho Chehab return 0; 718cb7a01acSMauro Carvalho Chehab } 719cb7a01acSMauro Carvalho Chehab pos = ret & 0x0f; 720cb7a01acSMauro Carvalho Chehab if (pos < 0x0f) 721cb7a01acSMauro Carvalho Chehab type |= regs[pos].type.vbi_type; 722cb7a01acSMauro Carvalho Chehab } 723cb7a01acSMauro Carvalho Chehab 724cb7a01acSMauro Carvalho Chehab return type; 725cb7a01acSMauro Carvalho Chehab } 726cb7a01acSMauro Carvalho Chehab 727cb7a01acSMauro Carvalho Chehab static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) 728cb7a01acSMauro Carvalho Chehab { 729cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 730cb7a01acSMauro Carvalho Chehab int fmt = 0; 731cb7a01acSMauro Carvalho Chehab 732cb7a01acSMauro Carvalho Chehab decoder->norm = std; 733cb7a01acSMauro Carvalho Chehab 734cb7a01acSMauro Carvalho Chehab /* First tests should be against specific std */ 735cb7a01acSMauro Carvalho Chehab 73626811ae0SHans Verkuil if (std == V4L2_STD_NTSC_443) { 737cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_4_43_BIT; 73826811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_M) { 739cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_M_BIT; 74026811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) { 741cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_COMBINATION_N_BIT; 742cb7a01acSMauro Carvalho Chehab } else { 743cb7a01acSMauro Carvalho Chehab /* Then, test against generic ones */ 744cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 745cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_MJ_BIT; 746cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_PAL) 747cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_BDGHIN_BIT; 748cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_SECAM) 749cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_SECAM_BIT; 750cb7a01acSMauro Carvalho Chehab } 751cb7a01acSMauro Carvalho Chehab 752cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt); 753cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VIDEO_STD, fmt); 754cb7a01acSMauro Carvalho Chehab return 0; 755cb7a01acSMauro Carvalho Chehab } 756cb7a01acSMauro Carvalho Chehab 757cb7a01acSMauro Carvalho Chehab static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 758cb7a01acSMauro Carvalho Chehab { 759cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 760cb7a01acSMauro Carvalho Chehab 761cb7a01acSMauro Carvalho Chehab if (decoder->norm == std) 762cb7a01acSMauro Carvalho Chehab return 0; 763cb7a01acSMauro Carvalho Chehab 764cb7a01acSMauro Carvalho Chehab /* Change cropping height limits */ 765cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 766cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_525_60; 767cb7a01acSMauro Carvalho Chehab else 768cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_OTHERS; 769cb7a01acSMauro Carvalho Chehab 770cb7a01acSMauro Carvalho Chehab 771cb7a01acSMauro Carvalho Chehab return tvp5150_set_std(sd, std); 772cb7a01acSMauro Carvalho Chehab } 773cb7a01acSMauro Carvalho Chehab 774cb7a01acSMauro Carvalho Chehab static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) 775cb7a01acSMauro Carvalho Chehab { 776cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 777cb7a01acSMauro Carvalho Chehab 778cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to its default values */ 779cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_default); 780cb7a01acSMauro Carvalho Chehab 781cb7a01acSMauro Carvalho Chehab /* Initializes VDP registers */ 782cb7a01acSMauro Carvalho Chehab tvp5150_vdp_init(sd, vbi_ram_default); 783cb7a01acSMauro Carvalho Chehab 784cb7a01acSMauro Carvalho Chehab /* Selects decoder input */ 785cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 786cb7a01acSMauro Carvalho Chehab 787cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to stream enabled values */ 788cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_enable); 789cb7a01acSMauro Carvalho Chehab 790cb7a01acSMauro Carvalho Chehab /* Initialize image preferences */ 791cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&decoder->hdl); 792cb7a01acSMauro Carvalho Chehab 793cb7a01acSMauro Carvalho Chehab tvp5150_set_std(sd, decoder->norm); 794a2e5f1b3SJavier Martinez Canillas 795a2e5f1b3SJavier Martinez Canillas if (decoder->mbus_type == V4L2_MBUS_PARALLEL) 796a2e5f1b3SJavier Martinez Canillas tvp5150_write(sd, TVP5150_DATA_RATE_SEL, 0x40); 797a2e5f1b3SJavier Martinez Canillas 798cb7a01acSMauro Carvalho Chehab return 0; 799cb7a01acSMauro Carvalho Chehab }; 800cb7a01acSMauro Carvalho Chehab 801cb7a01acSMauro Carvalho Chehab static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) 802cb7a01acSMauro Carvalho Chehab { 803cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_sd(ctrl); 804c43875f6SMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 805cb7a01acSMauro Carvalho Chehab 806cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 807cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 808cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val); 809cb7a01acSMauro Carvalho Chehab return 0; 810cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 811cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val); 812cb7a01acSMauro Carvalho Chehab return 0; 813cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 814cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val); 815cb7a01acSMauro Carvalho Chehab return 0; 816cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 817cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val); 818c43875f6SMauro Carvalho Chehab case V4L2_CID_TEST_PATTERN: 819c43875f6SMauro Carvalho Chehab decoder->enable = ctrl->val ? false : true; 820c43875f6SMauro Carvalho Chehab tvp5150_selmux(sd); 821cb7a01acSMauro Carvalho Chehab return 0; 822cb7a01acSMauro Carvalho Chehab } 823cb7a01acSMauro Carvalho Chehab return -EINVAL; 824cb7a01acSMauro Carvalho Chehab } 825cb7a01acSMauro Carvalho Chehab 826cb7a01acSMauro Carvalho Chehab static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) 827cb7a01acSMauro Carvalho Chehab { 828cb7a01acSMauro Carvalho Chehab int val = tvp5150_read(sd, TVP5150_STATUS_REG_5); 829cb7a01acSMauro Carvalho Chehab 830cb7a01acSMauro Carvalho Chehab switch (val & 0x0F) { 831cb7a01acSMauro Carvalho Chehab case 0x01: 832cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC; 833cb7a01acSMauro Carvalho Chehab case 0x03: 834cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL; 835cb7a01acSMauro Carvalho Chehab case 0x05: 836cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M; 837cb7a01acSMauro Carvalho Chehab case 0x07: 838cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc; 839cb7a01acSMauro Carvalho Chehab case 0x09: 840cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443; 841cb7a01acSMauro Carvalho Chehab case 0xb: 842cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 843cb7a01acSMauro Carvalho Chehab default: 844cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN; 845cb7a01acSMauro Carvalho Chehab } 846cb7a01acSMauro Carvalho Chehab } 847cb7a01acSMauro Carvalho Chehab 848da298c6dSHans Verkuil static int tvp5150_fill_fmt(struct v4l2_subdev *sd, 849da298c6dSHans Verkuil struct v4l2_subdev_pad_config *cfg, 850da298c6dSHans Verkuil struct v4l2_subdev_format *format) 851cb7a01acSMauro Carvalho Chehab { 852da298c6dSHans Verkuil struct v4l2_mbus_framefmt *f; 853cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 854cb7a01acSMauro Carvalho Chehab 855da298c6dSHans Verkuil if (!format || format->pad) 856cb7a01acSMauro Carvalho Chehab return -EINVAL; 857cb7a01acSMauro Carvalho Chehab 858da298c6dSHans Verkuil f = &format->format; 859da298c6dSHans Verkuil 860cb7a01acSMauro Carvalho Chehab tvp5150_reset(sd, 0); 861cb7a01acSMauro Carvalho Chehab 862cb7a01acSMauro Carvalho Chehab f->width = decoder->rect.width; 8634f57d27bSLaurent Pinchart f->height = decoder->rect.height / 2; 864cb7a01acSMauro Carvalho Chehab 865f5fe58fdSBoris BREZILLON f->code = MEDIA_BUS_FMT_UYVY8_2X8; 8664f57d27bSLaurent Pinchart f->field = V4L2_FIELD_ALTERNATE; 867cb7a01acSMauro Carvalho Chehab f->colorspace = V4L2_COLORSPACE_SMPTE170M; 868cb7a01acSMauro Carvalho Chehab 869cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width, 870cb7a01acSMauro Carvalho Chehab f->height); 871cb7a01acSMauro Carvalho Chehab return 0; 872cb7a01acSMauro Carvalho Chehab } 873cb7a01acSMauro Carvalho Chehab 8744f996594SHans Verkuil static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) 875cb7a01acSMauro Carvalho Chehab { 876cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect = a->c; 877cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 878cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 879f90580caSRicardo Ribalda unsigned int hmax; 880cb7a01acSMauro Carvalho Chehab 881cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", 882cb7a01acSMauro Carvalho Chehab __func__, rect.left, rect.top, rect.width, rect.height); 883cb7a01acSMauro Carvalho Chehab 884cb7a01acSMauro Carvalho Chehab if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 885cb7a01acSMauro Carvalho Chehab return -EINVAL; 886cb7a01acSMauro Carvalho Chehab 887cb7a01acSMauro Carvalho Chehab /* tvp5150 has some special limits */ 888cb7a01acSMauro Carvalho Chehab rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); 889f90580caSRicardo Ribalda rect.width = clamp_t(unsigned int, rect.width, 890cb7a01acSMauro Carvalho Chehab TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, 891cb7a01acSMauro Carvalho Chehab TVP5150_H_MAX - rect.left); 892cb7a01acSMauro Carvalho Chehab rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); 893cb7a01acSMauro Carvalho Chehab 894cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 895cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 896cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 897cb7a01acSMauro Carvalho Chehab else 898cb7a01acSMauro Carvalho Chehab std = decoder->norm; 899cb7a01acSMauro Carvalho Chehab 900cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 901cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_525_60; 902cb7a01acSMauro Carvalho Chehab else 903cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_OTHERS; 904cb7a01acSMauro Carvalho Chehab 905f90580caSRicardo Ribalda rect.height = clamp_t(unsigned int, rect.height, 906cb7a01acSMauro Carvalho Chehab hmax - TVP5150_MAX_CROP_TOP - rect.top, 907cb7a01acSMauro Carvalho Chehab hmax - rect.top); 908cb7a01acSMauro Carvalho Chehab 909cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); 910cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 911cb7a01acSMauro Carvalho Chehab rect.top + rect.height - hmax); 912cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB, 913cb7a01acSMauro Carvalho Chehab rect.left >> TVP5150_CROP_SHIFT); 914cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB, 915cb7a01acSMauro Carvalho Chehab rect.left | (1 << TVP5150_CROP_SHIFT)); 916cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB, 917cb7a01acSMauro Carvalho Chehab (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> 918cb7a01acSMauro Carvalho Chehab TVP5150_CROP_SHIFT); 919cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB, 920cb7a01acSMauro Carvalho Chehab rect.left + rect.width - TVP5150_MAX_CROP_LEFT); 921cb7a01acSMauro Carvalho Chehab 922cb7a01acSMauro Carvalho Chehab decoder->rect = rect; 923cb7a01acSMauro Carvalho Chehab 924cb7a01acSMauro Carvalho Chehab return 0; 925cb7a01acSMauro Carvalho Chehab } 926cb7a01acSMauro Carvalho Chehab 927cb7a01acSMauro Carvalho Chehab static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 928cb7a01acSMauro Carvalho Chehab { 92912bd10c7SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 930cb7a01acSMauro Carvalho Chehab 931cb7a01acSMauro Carvalho Chehab a->c = decoder->rect; 932cb7a01acSMauro Carvalho Chehab a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 933cb7a01acSMauro Carvalho Chehab 934cb7a01acSMauro Carvalho Chehab return 0; 935cb7a01acSMauro Carvalho Chehab } 936cb7a01acSMauro Carvalho Chehab 937cb7a01acSMauro Carvalho Chehab static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) 938cb7a01acSMauro Carvalho Chehab { 93912bd10c7SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 940cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 941cb7a01acSMauro Carvalho Chehab 942cb7a01acSMauro Carvalho Chehab if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 943cb7a01acSMauro Carvalho Chehab return -EINVAL; 944cb7a01acSMauro Carvalho Chehab 945cb7a01acSMauro Carvalho Chehab a->bounds.left = 0; 946cb7a01acSMauro Carvalho Chehab a->bounds.top = 0; 947cb7a01acSMauro Carvalho Chehab a->bounds.width = TVP5150_H_MAX; 948cb7a01acSMauro Carvalho Chehab 949cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 950cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 951cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 952cb7a01acSMauro Carvalho Chehab else 953cb7a01acSMauro Carvalho Chehab std = decoder->norm; 954cb7a01acSMauro Carvalho Chehab 955cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 956cb7a01acSMauro Carvalho Chehab a->bounds.height = TVP5150_V_MAX_525_60; 957cb7a01acSMauro Carvalho Chehab else 958cb7a01acSMauro Carvalho Chehab a->bounds.height = TVP5150_V_MAX_OTHERS; 959cb7a01acSMauro Carvalho Chehab 960cb7a01acSMauro Carvalho Chehab a->defrect = a->bounds; 961cb7a01acSMauro Carvalho Chehab a->pixelaspect.numerator = 1; 962cb7a01acSMauro Carvalho Chehab a->pixelaspect.denominator = 1; 963cb7a01acSMauro Carvalho Chehab 964cb7a01acSMauro Carvalho Chehab return 0; 965cb7a01acSMauro Carvalho Chehab } 966cb7a01acSMauro Carvalho Chehab 967dd3a46bbSLaurent Pinchart static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, 968dd3a46bbSLaurent Pinchart struct v4l2_mbus_config *cfg) 969dd3a46bbSLaurent Pinchart { 970a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 971a2e5f1b3SJavier Martinez Canillas 972a2e5f1b3SJavier Martinez Canillas cfg->type = decoder->mbus_type; 973dd3a46bbSLaurent Pinchart cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING 974dd3a46bbSLaurent Pinchart | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; 975dd3a46bbSLaurent Pinchart 976dd3a46bbSLaurent Pinchart return 0; 977dd3a46bbSLaurent Pinchart } 978dd3a46bbSLaurent Pinchart 979cb7a01acSMauro Carvalho Chehab /**************************************************************************** 980e545ac87SLaurent Pinchart V4L2 subdev pad ops 981e545ac87SLaurent Pinchart ****************************************************************************/ 982e545ac87SLaurent Pinchart static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, 983e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 984e545ac87SLaurent Pinchart struct v4l2_subdev_mbus_code_enum *code) 985e545ac87SLaurent Pinchart { 986e545ac87SLaurent Pinchart if (code->pad || code->index) 987e545ac87SLaurent Pinchart return -EINVAL; 988e545ac87SLaurent Pinchart 989e545ac87SLaurent Pinchart code->code = MEDIA_BUS_FMT_UYVY8_2X8; 990e545ac87SLaurent Pinchart return 0; 991e545ac87SLaurent Pinchart } 992e545ac87SLaurent Pinchart 993e545ac87SLaurent Pinchart static int tvp5150_enum_frame_size(struct v4l2_subdev *sd, 994e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 995e545ac87SLaurent Pinchart struct v4l2_subdev_frame_size_enum *fse) 996e545ac87SLaurent Pinchart { 997e545ac87SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 998e545ac87SLaurent Pinchart 999e545ac87SLaurent Pinchart if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_UYVY8_2X8) 1000e545ac87SLaurent Pinchart return -EINVAL; 1001e545ac87SLaurent Pinchart 1002e545ac87SLaurent Pinchart fse->code = MEDIA_BUS_FMT_UYVY8_2X8; 1003e545ac87SLaurent Pinchart fse->min_width = decoder->rect.width; 1004e545ac87SLaurent Pinchart fse->max_width = decoder->rect.width; 1005e545ac87SLaurent Pinchart fse->min_height = decoder->rect.height / 2; 1006e545ac87SLaurent Pinchart fse->max_height = decoder->rect.height / 2; 1007e545ac87SLaurent Pinchart 1008e545ac87SLaurent Pinchart return 0; 1009e545ac87SLaurent Pinchart } 1010e545ac87SLaurent Pinchart 1011e545ac87SLaurent Pinchart /**************************************************************************** 1012f7b4b54eSJavier Martinez Canillas Media entity ops 1013f7b4b54eSJavier Martinez Canillas ****************************************************************************/ 1014f7b4b54eSJavier Martinez Canillas 1015f7b4b54eSJavier Martinez Canillas static int tvp5150_link_setup(struct media_entity *entity, 1016f7b4b54eSJavier Martinez Canillas const struct media_pad *local, 1017f7b4b54eSJavier Martinez Canillas const struct media_pad *remote, u32 flags) 1018f7b4b54eSJavier Martinez Canillas { 1019f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1020f7b4b54eSJavier Martinez Canillas struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 1021f7b4b54eSJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1022f7b4b54eSJavier Martinez Canillas int i; 1023f7b4b54eSJavier Martinez Canillas 1024f7b4b54eSJavier Martinez Canillas for (i = 0; i < TVP5150_INPUT_NUM; i++) { 1025f7b4b54eSJavier Martinez Canillas if (remote->entity == &decoder->input_ent[i]) 1026f7b4b54eSJavier Martinez Canillas break; 1027f7b4b54eSJavier Martinez Canillas } 1028f7b4b54eSJavier Martinez Canillas 1029f7b4b54eSJavier Martinez Canillas /* Do nothing for entities that are not input connectors */ 1030f7b4b54eSJavier Martinez Canillas if (i == TVP5150_INPUT_NUM) 1031f7b4b54eSJavier Martinez Canillas return 0; 1032f7b4b54eSJavier Martinez Canillas 1033f7b4b54eSJavier Martinez Canillas decoder->input = i; 1034f7b4b54eSJavier Martinez Canillas 1035f7b4b54eSJavier Martinez Canillas tvp5150_selmux(sd); 1036f7b4b54eSJavier Martinez Canillas #endif 1037f7b4b54eSJavier Martinez Canillas 1038f7b4b54eSJavier Martinez Canillas return 0; 1039f7b4b54eSJavier Martinez Canillas } 1040f7b4b54eSJavier Martinez Canillas 1041f7b4b54eSJavier Martinez Canillas static const struct media_entity_operations tvp5150_sd_media_ops = { 1042f7b4b54eSJavier Martinez Canillas .link_setup = tvp5150_link_setup, 1043f7b4b54eSJavier Martinez Canillas }; 1044f7b4b54eSJavier Martinez Canillas 1045f7b4b54eSJavier Martinez Canillas /**************************************************************************** 1046cb7a01acSMauro Carvalho Chehab I2C Command 1047cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1048cb7a01acSMauro Carvalho Chehab 1049460b6c08SLaurent Pinchart static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) 1050460b6c08SLaurent Pinchart { 1051a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1052841502d7SMauro Carvalho Chehab /* Output format: 8-bit ITU-R BT.656 with embedded syncs */ 1053841502d7SMauro Carvalho Chehab int val = 0x09; 1054a2e5f1b3SJavier Martinez Canillas 1055a2e5f1b3SJavier Martinez Canillas /* Output format: 8-bit 4:2:2 YUV with discrete sync */ 1056841502d7SMauro Carvalho Chehab if (decoder->mbus_type == V4L2_MBUS_PARALLEL) 1057841502d7SMauro Carvalho Chehab val = 0x0d; 1058a2e5f1b3SJavier Martinez Canillas 1059460b6c08SLaurent Pinchart /* Initializes TVP5150 to its default values */ 1060460b6c08SLaurent Pinchart /* # set PCLK (27MHz) */ 1061460b6c08SLaurent Pinchart tvp5150_write(sd, TVP5150_CONF_SHARED_PIN, 0x00); 1062460b6c08SLaurent Pinchart 1063460b6c08SLaurent Pinchart if (enable) 1064841502d7SMauro Carvalho Chehab tvp5150_write(sd, TVP5150_MISC_CTL, val); 1065460b6c08SLaurent Pinchart else 1066460b6c08SLaurent Pinchart tvp5150_write(sd, TVP5150_MISC_CTL, 0x00); 1067460b6c08SLaurent Pinchart 1068460b6c08SLaurent Pinchart return 0; 1069460b6c08SLaurent Pinchart } 1070460b6c08SLaurent Pinchart 1071cb7a01acSMauro Carvalho Chehab static int tvp5150_s_routing(struct v4l2_subdev *sd, 1072cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 1073cb7a01acSMauro Carvalho Chehab { 1074cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1075cb7a01acSMauro Carvalho Chehab 1076cb7a01acSMauro Carvalho Chehab decoder->input = input; 1077cb7a01acSMauro Carvalho Chehab decoder->output = output; 1078c43875f6SMauro Carvalho Chehab 1079c43875f6SMauro Carvalho Chehab if (output == TVP5150_BLACK_SCREEN) 1080c43875f6SMauro Carvalho Chehab decoder->enable = false; 1081c43875f6SMauro Carvalho Chehab else 1082c43875f6SMauro Carvalho Chehab decoder->enable = true; 1083c43875f6SMauro Carvalho Chehab 1084cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 1085cb7a01acSMauro Carvalho Chehab return 0; 1086cb7a01acSMauro Carvalho Chehab } 1087cb7a01acSMauro Carvalho Chehab 1088cb7a01acSMauro Carvalho Chehab static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) 1089cb7a01acSMauro Carvalho Chehab { 1090cb7a01acSMauro Carvalho Chehab /* this is for capturing 36 raw vbi lines 1091cb7a01acSMauro Carvalho Chehab if there's a way to cut off the beginning 2 vbi lines 1092cb7a01acSMauro Carvalho Chehab with the tvp5150 then the vbi line count could be lowered 1093cb7a01acSMauro Carvalho Chehab to 17 lines/field again, although I couldn't find a register 1094cb7a01acSMauro Carvalho Chehab which could do that cropping */ 1095cb7a01acSMauro Carvalho Chehab if (fmt->sample_format == V4L2_PIX_FMT_GREY) 1096cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70); 1097cb7a01acSMauro Carvalho Chehab if (fmt->count[0] == 18 && fmt->count[1] == 18) { 1098cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00); 1099cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01); 1100cb7a01acSMauro Carvalho Chehab } 1101cb7a01acSMauro Carvalho Chehab return 0; 1102cb7a01acSMauro Carvalho Chehab } 1103cb7a01acSMauro Carvalho Chehab 1104cb7a01acSMauro Carvalho Chehab static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1105cb7a01acSMauro Carvalho Chehab { 1106cb7a01acSMauro Carvalho Chehab int i; 1107cb7a01acSMauro Carvalho Chehab 1108cb7a01acSMauro Carvalho Chehab if (svbi->service_set != 0) { 1109cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1110cb7a01acSMauro Carvalho Chehab svbi->service_lines[1][i] = 0; 1111cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 1112cb7a01acSMauro Carvalho Chehab tvp5150_set_vbi(sd, vbi_ram_default, 1113cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i], 0xf0, i, 3); 1114cb7a01acSMauro Carvalho Chehab } 1115cb7a01acSMauro Carvalho Chehab /* Enables FIFO */ 1116cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1); 1117cb7a01acSMauro Carvalho Chehab } else { 1118cb7a01acSMauro Carvalho Chehab /* Disables FIFO*/ 1119cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0); 1120cb7a01acSMauro Carvalho Chehab 1121cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 1122cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); 1123cb7a01acSMauro Carvalho Chehab 1124cb7a01acSMauro Carvalho Chehab /* Disable Line modes */ 1125cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 1126cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, i, 0xff); 1127cb7a01acSMauro Carvalho Chehab } 1128cb7a01acSMauro Carvalho Chehab return 0; 1129cb7a01acSMauro Carvalho Chehab } 1130cb7a01acSMauro Carvalho Chehab 1131cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1132cb7a01acSMauro Carvalho Chehab { 1133cb7a01acSMauro Carvalho Chehab int i, mask = 0; 1134cb7a01acSMauro Carvalho Chehab 113530634e8eSHans Verkuil memset(svbi->service_lines, 0, sizeof(svbi->service_lines)); 1136cb7a01acSMauro Carvalho Chehab 1137cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1138cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 1139cb7a01acSMauro Carvalho Chehab tvp5150_get_vbi(sd, vbi_ram_default, i); 1140cb7a01acSMauro Carvalho Chehab mask |= svbi->service_lines[0][i]; 1141cb7a01acSMauro Carvalho Chehab } 1142cb7a01acSMauro Carvalho Chehab svbi->service_set = mask; 1143cb7a01acSMauro Carvalho Chehab return 0; 1144cb7a01acSMauro Carvalho Chehab } 1145cb7a01acSMauro Carvalho Chehab 1146cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1147cb7a01acSMauro Carvalho Chehab static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 1148cb7a01acSMauro Carvalho Chehab { 1149cb7a01acSMauro Carvalho Chehab int res; 1150cb7a01acSMauro Carvalho Chehab 1151cb7a01acSMauro Carvalho Chehab res = tvp5150_read(sd, reg->reg & 0xff); 1152cb7a01acSMauro Carvalho Chehab if (res < 0) { 1153cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", __func__, res); 1154cb7a01acSMauro Carvalho Chehab return res; 1155cb7a01acSMauro Carvalho Chehab } 1156cb7a01acSMauro Carvalho Chehab 1157cb7a01acSMauro Carvalho Chehab reg->val = res; 1158cb7a01acSMauro Carvalho Chehab reg->size = 1; 1159cb7a01acSMauro Carvalho Chehab return 0; 1160cb7a01acSMauro Carvalho Chehab } 1161cb7a01acSMauro Carvalho Chehab 1162977ba3b1SHans Verkuil static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 1163cb7a01acSMauro Carvalho Chehab { 1164cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); 1165cb7a01acSMauro Carvalho Chehab return 0; 1166cb7a01acSMauro Carvalho Chehab } 1167cb7a01acSMauro Carvalho Chehab #endif 1168cb7a01acSMauro Carvalho Chehab 1169cb7a01acSMauro Carvalho Chehab static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) 1170cb7a01acSMauro Carvalho Chehab { 1171cb7a01acSMauro Carvalho Chehab int status = tvp5150_read(sd, 0x88); 1172cb7a01acSMauro Carvalho Chehab 1173cb7a01acSMauro Carvalho Chehab vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0; 1174cb7a01acSMauro Carvalho Chehab return 0; 1175cb7a01acSMauro Carvalho Chehab } 1176cb7a01acSMauro Carvalho Chehab 1177f7b4b54eSJavier Martinez Canillas static int tvp5150_registered_async(struct v4l2_subdev *sd) 1178f7b4b54eSJavier Martinez Canillas { 1179f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1180f7b4b54eSJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1181f7b4b54eSJavier Martinez Canillas int ret = 0; 1182f7b4b54eSJavier Martinez Canillas int i; 1183f7b4b54eSJavier Martinez Canillas 1184f7b4b54eSJavier Martinez Canillas for (i = 0; i < TVP5150_INPUT_NUM; i++) { 1185f7b4b54eSJavier Martinez Canillas struct media_entity *input = &decoder->input_ent[i]; 1186f7b4b54eSJavier Martinez Canillas struct media_pad *pad = &decoder->input_pad[i]; 1187f7b4b54eSJavier Martinez Canillas 1188f7b4b54eSJavier Martinez Canillas if (!input->name) 1189f7b4b54eSJavier Martinez Canillas continue; 1190f7b4b54eSJavier Martinez Canillas 1191f7b4b54eSJavier Martinez Canillas decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE; 1192f7b4b54eSJavier Martinez Canillas 1193f7b4b54eSJavier Martinez Canillas ret = media_entity_pads_init(input, 1, pad); 1194f7b4b54eSJavier Martinez Canillas if (ret < 0) 1195f7b4b54eSJavier Martinez Canillas return ret; 1196f7b4b54eSJavier Martinez Canillas 1197f7b4b54eSJavier Martinez Canillas ret = media_device_register_entity(sd->v4l2_dev->mdev, input); 1198f7b4b54eSJavier Martinez Canillas if (ret < 0) 1199f7b4b54eSJavier Martinez Canillas return ret; 1200f7b4b54eSJavier Martinez Canillas 1201f7b4b54eSJavier Martinez Canillas ret = media_create_pad_link(input, 0, &sd->entity, 1202f7b4b54eSJavier Martinez Canillas DEMOD_PAD_IF_INPUT, 0); 1203f7b4b54eSJavier Martinez Canillas if (ret < 0) { 1204f7b4b54eSJavier Martinez Canillas media_device_unregister_entity(input); 1205f7b4b54eSJavier Martinez Canillas return ret; 1206f7b4b54eSJavier Martinez Canillas } 1207f7b4b54eSJavier Martinez Canillas } 1208f7b4b54eSJavier Martinez Canillas #endif 1209f7b4b54eSJavier Martinez Canillas 1210f7b4b54eSJavier Martinez Canillas return 0; 1211f7b4b54eSJavier Martinez Canillas } 1212f7b4b54eSJavier Martinez Canillas 1213cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1214cb7a01acSMauro Carvalho Chehab 1215cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { 1216cb7a01acSMauro Carvalho Chehab .s_ctrl = tvp5150_s_ctrl, 1217cb7a01acSMauro Carvalho Chehab }; 1218cb7a01acSMauro Carvalho Chehab 1219cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tvp5150_core_ops = { 1220cb7a01acSMauro Carvalho Chehab .log_status = tvp5150_log_status, 1221cb7a01acSMauro Carvalho Chehab .reset = tvp5150_reset, 1222cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1223cb7a01acSMauro Carvalho Chehab .g_register = tvp5150_g_register, 1224cb7a01acSMauro Carvalho Chehab .s_register = tvp5150_s_register, 1225cb7a01acSMauro Carvalho Chehab #endif 1226f7b4b54eSJavier Martinez Canillas .registered_async = tvp5150_registered_async, 1227cb7a01acSMauro Carvalho Chehab }; 1228cb7a01acSMauro Carvalho Chehab 1229cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { 1230cb7a01acSMauro Carvalho Chehab .g_tuner = tvp5150_g_tuner, 1231cb7a01acSMauro Carvalho Chehab }; 1232cb7a01acSMauro Carvalho Chehab 1233cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tvp5150_video_ops = { 12348774bed9SLaurent Pinchart .s_std = tvp5150_s_std, 1235460b6c08SLaurent Pinchart .s_stream = tvp5150_s_stream, 1236cb7a01acSMauro Carvalho Chehab .s_routing = tvp5150_s_routing, 1237cb7a01acSMauro Carvalho Chehab .s_crop = tvp5150_s_crop, 1238cb7a01acSMauro Carvalho Chehab .g_crop = tvp5150_g_crop, 1239cb7a01acSMauro Carvalho Chehab .cropcap = tvp5150_cropcap, 1240dd3a46bbSLaurent Pinchart .g_mbus_config = tvp5150_g_mbus_config, 1241cb7a01acSMauro Carvalho Chehab }; 1242cb7a01acSMauro Carvalho Chehab 1243cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { 1244cb7a01acSMauro Carvalho Chehab .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap, 1245cb7a01acSMauro Carvalho Chehab .g_sliced_fmt = tvp5150_g_sliced_fmt, 1246cb7a01acSMauro Carvalho Chehab .s_sliced_fmt = tvp5150_s_sliced_fmt, 1247cb7a01acSMauro Carvalho Chehab .s_raw_fmt = tvp5150_s_raw_fmt, 1248cb7a01acSMauro Carvalho Chehab }; 1249cb7a01acSMauro Carvalho Chehab 1250ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { 1251ebcff5fcSHans Verkuil .enum_mbus_code = tvp5150_enum_mbus_code, 1252e545ac87SLaurent Pinchart .enum_frame_size = tvp5150_enum_frame_size, 1253da298c6dSHans Verkuil .set_fmt = tvp5150_fill_fmt, 1254da298c6dSHans Verkuil .get_fmt = tvp5150_fill_fmt, 1255ebcff5fcSHans Verkuil }; 1256ebcff5fcSHans Verkuil 1257cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvp5150_ops = { 1258cb7a01acSMauro Carvalho Chehab .core = &tvp5150_core_ops, 1259cb7a01acSMauro Carvalho Chehab .tuner = &tvp5150_tuner_ops, 1260cb7a01acSMauro Carvalho Chehab .video = &tvp5150_video_ops, 1261cb7a01acSMauro Carvalho Chehab .vbi = &tvp5150_vbi_ops, 1262ebcff5fcSHans Verkuil .pad = &tvp5150_pad_ops, 1263cb7a01acSMauro Carvalho Chehab }; 1264cb7a01acSMauro Carvalho Chehab 1265cb7a01acSMauro Carvalho Chehab 1266cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1267cb7a01acSMauro Carvalho Chehab I2C Client & Driver 1268cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1269cb7a01acSMauro Carvalho Chehab 12707871597aSLaurent Pinchart static int tvp5150_detect_version(struct tvp5150 *core) 12717871597aSLaurent Pinchart { 12727871597aSLaurent Pinchart struct v4l2_subdev *sd = &core->sd; 12737871597aSLaurent Pinchart struct i2c_client *c = v4l2_get_subdevdata(sd); 12747871597aSLaurent Pinchart unsigned int i; 12757871597aSLaurent Pinchart u8 regs[4]; 12767871597aSLaurent Pinchart int res; 12777871597aSLaurent Pinchart 12787871597aSLaurent Pinchart /* 12797871597aSLaurent Pinchart * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID, 12807871597aSLaurent Pinchart * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 12817871597aSLaurent Pinchart */ 12827871597aSLaurent Pinchart for (i = 0; i < 4; i++) { 12837871597aSLaurent Pinchart res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i); 12847871597aSLaurent Pinchart if (res < 0) 12857871597aSLaurent Pinchart return res; 12867871597aSLaurent Pinchart regs[i] = res; 12877871597aSLaurent Pinchart } 12887871597aSLaurent Pinchart 128982275133SJavier Martinez Canillas core->dev_id = (regs[0] << 8) | regs[1]; 129082275133SJavier Martinez Canillas core->rom_ver = (regs[2] << 8) | regs[3]; 12917871597aSLaurent Pinchart 12927871597aSLaurent Pinchart v4l2_info(sd, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n", 129382275133SJavier Martinez Canillas core->dev_id, regs[2], regs[3], c->addr << 1, 129482275133SJavier Martinez Canillas c->adapter->name); 12957871597aSLaurent Pinchart 129682275133SJavier Martinez Canillas if (core->dev_id == 0x5150 && core->rom_ver == 0x0321) { 12977871597aSLaurent Pinchart v4l2_info(sd, "tvp5150a detected.\n"); 129882275133SJavier Martinez Canillas } else if (core->dev_id == 0x5150 && core->rom_ver == 0x0400) { 12997871597aSLaurent Pinchart v4l2_info(sd, "tvp5150am1 detected.\n"); 13007871597aSLaurent Pinchart 13017871597aSLaurent Pinchart /* ITU-T BT.656.4 timing */ 13027871597aSLaurent Pinchart tvp5150_write(sd, TVP5150_REV_SELECT, 0); 130382275133SJavier Martinez Canillas } else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) { 130405676b3eSLaurent Pinchart v4l2_info(sd, "tvp5151 detected.\n"); 13057871597aSLaurent Pinchart } else { 130682275133SJavier Martinez Canillas v4l2_info(sd, "*** unknown tvp%04x chip detected.\n", 130782275133SJavier Martinez Canillas core->dev_id); 13087871597aSLaurent Pinchart } 13097871597aSLaurent Pinchart 13107871597aSLaurent Pinchart return 0; 13117871597aSLaurent Pinchart } 13127871597aSLaurent Pinchart 131309aa2609SJavier Martinez Canillas static int tvp5150_init(struct i2c_client *c) 131409aa2609SJavier Martinez Canillas { 131509aa2609SJavier Martinez Canillas struct gpio_desc *pdn_gpio; 131609aa2609SJavier Martinez Canillas struct gpio_desc *reset_gpio; 131709aa2609SJavier Martinez Canillas 131809aa2609SJavier Martinez Canillas pdn_gpio = devm_gpiod_get_optional(&c->dev, "pdn", GPIOD_OUT_HIGH); 131909aa2609SJavier Martinez Canillas if (IS_ERR(pdn_gpio)) 132009aa2609SJavier Martinez Canillas return PTR_ERR(pdn_gpio); 132109aa2609SJavier Martinez Canillas 132209aa2609SJavier Martinez Canillas if (pdn_gpio) { 132309aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(pdn_gpio, 0); 132409aa2609SJavier Martinez Canillas /* Delay time between power supplies active and reset */ 132509aa2609SJavier Martinez Canillas msleep(20); 132609aa2609SJavier Martinez Canillas } 132709aa2609SJavier Martinez Canillas 132809aa2609SJavier Martinez Canillas reset_gpio = devm_gpiod_get_optional(&c->dev, "reset", GPIOD_OUT_HIGH); 132909aa2609SJavier Martinez Canillas if (IS_ERR(reset_gpio)) 133009aa2609SJavier Martinez Canillas return PTR_ERR(reset_gpio); 133109aa2609SJavier Martinez Canillas 133209aa2609SJavier Martinez Canillas if (reset_gpio) { 133309aa2609SJavier Martinez Canillas /* RESETB pulse duration */ 133409aa2609SJavier Martinez Canillas ndelay(500); 133509aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(reset_gpio, 0); 133609aa2609SJavier Martinez Canillas /* Delay time between end of reset to I2C active */ 133709aa2609SJavier Martinez Canillas usleep_range(200, 250); 133809aa2609SJavier Martinez Canillas } 133909aa2609SJavier Martinez Canillas 134009aa2609SJavier Martinez Canillas return 0; 134109aa2609SJavier Martinez Canillas } 134209aa2609SJavier Martinez Canillas 1343a2e5f1b3SJavier Martinez Canillas static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) 1344a2e5f1b3SJavier Martinez Canillas { 1345a2e5f1b3SJavier Martinez Canillas struct v4l2_of_endpoint bus_cfg; 1346a2e5f1b3SJavier Martinez Canillas struct device_node *ep; 1347f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1348f7b4b54eSJavier Martinez Canillas struct device_node *connectors, *child; 1349f7b4b54eSJavier Martinez Canillas struct media_entity *input; 1350f7b4b54eSJavier Martinez Canillas const char *name; 1351f7b4b54eSJavier Martinez Canillas u32 input_type; 1352f7b4b54eSJavier Martinez Canillas #endif 1353a2e5f1b3SJavier Martinez Canillas unsigned int flags; 1354a2e5f1b3SJavier Martinez Canillas int ret = 0; 1355a2e5f1b3SJavier Martinez Canillas 1356a2e5f1b3SJavier Martinez Canillas ep = of_graph_get_next_endpoint(np, NULL); 1357a2e5f1b3SJavier Martinez Canillas if (!ep) 1358a2e5f1b3SJavier Martinez Canillas return -EINVAL; 1359a2e5f1b3SJavier Martinez Canillas 1360a2e5f1b3SJavier Martinez Canillas ret = v4l2_of_parse_endpoint(ep, &bus_cfg); 1361a2e5f1b3SJavier Martinez Canillas if (ret) 1362a2e5f1b3SJavier Martinez Canillas goto err; 1363a2e5f1b3SJavier Martinez Canillas 1364a2e5f1b3SJavier Martinez Canillas flags = bus_cfg.bus.parallel.flags; 1365a2e5f1b3SJavier Martinez Canillas 1366a2e5f1b3SJavier Martinez Canillas if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL && 1367a2e5f1b3SJavier Martinez Canillas !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH && 1368a2e5f1b3SJavier Martinez Canillas flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH && 13692bd5e437SJavier Martinez Canillas flags & V4L2_MBUS_FIELD_EVEN_LOW)) { 13702bd5e437SJavier Martinez Canillas ret = -EINVAL; 13712bd5e437SJavier Martinez Canillas goto err; 13722bd5e437SJavier Martinez Canillas } 1373a2e5f1b3SJavier Martinez Canillas 1374a2e5f1b3SJavier Martinez Canillas decoder->mbus_type = bus_cfg.bus_type; 1375a2e5f1b3SJavier Martinez Canillas 1376f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1377f7b4b54eSJavier Martinez Canillas connectors = of_get_child_by_name(np, "connectors"); 1378f7b4b54eSJavier Martinez Canillas 1379f7b4b54eSJavier Martinez Canillas if (!connectors) 1380f7b4b54eSJavier Martinez Canillas goto err; 1381f7b4b54eSJavier Martinez Canillas 1382f7b4b54eSJavier Martinez Canillas for_each_available_child_of_node(connectors, child) { 1383f7b4b54eSJavier Martinez Canillas ret = of_property_read_u32(child, "input", &input_type); 1384f7b4b54eSJavier Martinez Canillas if (ret) { 1385f7b4b54eSJavier Martinez Canillas v4l2_err(&decoder->sd, 1386f7b4b54eSJavier Martinez Canillas "missing type property in node %s\n", 1387f7b4b54eSJavier Martinez Canillas child->name); 1388f7b4b54eSJavier Martinez Canillas goto err_connector; 1389f7b4b54eSJavier Martinez Canillas } 1390f7b4b54eSJavier Martinez Canillas 139160ad7689SMauro Carvalho Chehab if (input_type >= TVP5150_INPUT_NUM) { 1392f7b4b54eSJavier Martinez Canillas ret = -EINVAL; 1393f7b4b54eSJavier Martinez Canillas goto err_connector; 1394f7b4b54eSJavier Martinez Canillas } 1395f7b4b54eSJavier Martinez Canillas 1396f7b4b54eSJavier Martinez Canillas input = &decoder->input_ent[input_type]; 1397f7b4b54eSJavier Martinez Canillas 1398f7b4b54eSJavier Martinez Canillas /* Each input connector can only be defined once */ 1399f7b4b54eSJavier Martinez Canillas if (input->name) { 1400f7b4b54eSJavier Martinez Canillas v4l2_err(&decoder->sd, 1401f7b4b54eSJavier Martinez Canillas "input %s with same type already exists\n", 1402f7b4b54eSJavier Martinez Canillas input->name); 1403f7b4b54eSJavier Martinez Canillas ret = -EINVAL; 1404f7b4b54eSJavier Martinez Canillas goto err_connector; 1405f7b4b54eSJavier Martinez Canillas } 1406f7b4b54eSJavier Martinez Canillas 1407f7b4b54eSJavier Martinez Canillas switch (input_type) { 1408f7b4b54eSJavier Martinez Canillas case TVP5150_COMPOSITE0: 1409f7b4b54eSJavier Martinez Canillas case TVP5150_COMPOSITE1: 1410f7b4b54eSJavier Martinez Canillas input->function = MEDIA_ENT_F_CONN_COMPOSITE; 1411f7b4b54eSJavier Martinez Canillas break; 1412f7b4b54eSJavier Martinez Canillas case TVP5150_SVIDEO: 1413f7b4b54eSJavier Martinez Canillas input->function = MEDIA_ENT_F_CONN_SVIDEO; 1414f7b4b54eSJavier Martinez Canillas break; 1415f7b4b54eSJavier Martinez Canillas } 1416f7b4b54eSJavier Martinez Canillas 1417f7b4b54eSJavier Martinez Canillas input->flags = MEDIA_ENT_FL_CONNECTOR; 1418f7b4b54eSJavier Martinez Canillas 1419f7b4b54eSJavier Martinez Canillas ret = of_property_read_string(child, "label", &name); 1420f7b4b54eSJavier Martinez Canillas if (ret < 0) { 1421f7b4b54eSJavier Martinez Canillas v4l2_err(&decoder->sd, 1422f7b4b54eSJavier Martinez Canillas "missing label property in node %s\n", 1423f7b4b54eSJavier Martinez Canillas child->name); 1424f7b4b54eSJavier Martinez Canillas goto err_connector; 1425f7b4b54eSJavier Martinez Canillas } 1426f7b4b54eSJavier Martinez Canillas 1427f7b4b54eSJavier Martinez Canillas input->name = name; 1428f7b4b54eSJavier Martinez Canillas } 1429f7b4b54eSJavier Martinez Canillas 1430f7b4b54eSJavier Martinez Canillas err_connector: 1431f7b4b54eSJavier Martinez Canillas of_node_put(connectors); 1432f7b4b54eSJavier Martinez Canillas #endif 1433a2e5f1b3SJavier Martinez Canillas err: 1434a2e5f1b3SJavier Martinez Canillas of_node_put(ep); 1435a2e5f1b3SJavier Martinez Canillas return ret; 1436a2e5f1b3SJavier Martinez Canillas } 1437a2e5f1b3SJavier Martinez Canillas 1438c43875f6SMauro Carvalho Chehab static const char * const tvp5150_test_patterns[2] = { 1439c43875f6SMauro Carvalho Chehab "Disabled", 1440c43875f6SMauro Carvalho Chehab "Black screen" 1441c43875f6SMauro Carvalho Chehab }; 1442c43875f6SMauro Carvalho Chehab 1443cb7a01acSMauro Carvalho Chehab static int tvp5150_probe(struct i2c_client *c, 1444cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1445cb7a01acSMauro Carvalho Chehab { 1446cb7a01acSMauro Carvalho Chehab struct tvp5150 *core; 1447cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 1448a2e5f1b3SJavier Martinez Canillas struct device_node *np = c->dev.of_node; 14497871597aSLaurent Pinchart int res; 1450cb7a01acSMauro Carvalho Chehab 1451cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1452cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(c->adapter, 1453cb7a01acSMauro Carvalho Chehab I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 1454cb7a01acSMauro Carvalho Chehab return -EIO; 1455cb7a01acSMauro Carvalho Chehab 145609aa2609SJavier Martinez Canillas res = tvp5150_init(c); 145709aa2609SJavier Martinez Canillas if (res) 145809aa2609SJavier Martinez Canillas return res; 145909aa2609SJavier Martinez Canillas 1460c02b211dSLaurent Pinchart core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL); 1461c02b211dSLaurent Pinchart if (!core) 1462cb7a01acSMauro Carvalho Chehab return -ENOMEM; 1463a2e5f1b3SJavier Martinez Canillas 1464cb7a01acSMauro Carvalho Chehab sd = &core->sd; 1465a2e5f1b3SJavier Martinez Canillas 1466a2e5f1b3SJavier Martinez Canillas if (IS_ENABLED(CONFIG_OF) && np) { 1467a2e5f1b3SJavier Martinez Canillas res = tvp5150_parse_dt(core, np); 1468a2e5f1b3SJavier Martinez Canillas if (res) { 1469a2e5f1b3SJavier Martinez Canillas v4l2_err(sd, "DT parsing error: %d\n", res); 1470a2e5f1b3SJavier Martinez Canillas return res; 1471a2e5f1b3SJavier Martinez Canillas } 1472a2e5f1b3SJavier Martinez Canillas } else { 1473a2e5f1b3SJavier Martinez Canillas /* Default to BT.656 embedded sync */ 1474a2e5f1b3SJavier Martinez Canillas core->mbus_type = V4L2_MBUS_BT656; 1475a2e5f1b3SJavier Martinez Canillas } 1476a2e5f1b3SJavier Martinez Canillas 1477cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); 1478e545ac87SLaurent Pinchart sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1479e545ac87SLaurent Pinchart 1480e545ac87SLaurent Pinchart #if defined(CONFIG_MEDIA_CONTROLLER) 148155606310SMauro Carvalho Chehab core->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; 148255606310SMauro Carvalho Chehab core->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; 148355606310SMauro Carvalho Chehab core->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; 1484f92c70adSMauro Carvalho Chehab 1485f92c70adSMauro Carvalho Chehab sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 1486f92c70adSMauro Carvalho Chehab 148755606310SMauro Carvalho Chehab res = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, core->pads); 1488e545ac87SLaurent Pinchart if (res < 0) 1489e545ac87SLaurent Pinchart return res; 1490f7b4b54eSJavier Martinez Canillas 1491f7b4b54eSJavier Martinez Canillas sd->entity.ops = &tvp5150_sd_media_ops; 1492e545ac87SLaurent Pinchart #endif 1493cb7a01acSMauro Carvalho Chehab 14947871597aSLaurent Pinchart res = tvp5150_detect_version(core); 1495cb7a01acSMauro Carvalho Chehab if (res < 0) 1496c02b211dSLaurent Pinchart return res; 1497cb7a01acSMauro Carvalho Chehab 1498cb7a01acSMauro Carvalho Chehab core->norm = V4L2_STD_ALL; /* Default is autodetect */ 1499cb7a01acSMauro Carvalho Chehab core->input = TVP5150_COMPOSITE1; 1500c43875f6SMauro Carvalho Chehab core->enable = true; 1501cb7a01acSMauro Carvalho Chehab 1502b1950b8dSLaurent Pinchart v4l2_ctrl_handler_init(&core->hdl, 5); 1503cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1504cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 1505cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1506cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 255, 1, 128); 1507cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1508cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, 0, 255, 1, 128); 1509cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1510cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, -128, 127, 1, 0); 1511b1950b8dSLaurent Pinchart v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1512b1950b8dSLaurent Pinchart V4L2_CID_PIXEL_RATE, 27000000, 1513b1950b8dSLaurent Pinchart 27000000, 1, 27000000); 1514c43875f6SMauro Carvalho Chehab v4l2_ctrl_new_std_menu_items(&core->hdl, &tvp5150_ctrl_ops, 1515c43875f6SMauro Carvalho Chehab V4L2_CID_TEST_PATTERN, 1516c43875f6SMauro Carvalho Chehab ARRAY_SIZE(tvp5150_test_patterns), 1517c43875f6SMauro Carvalho Chehab 0, 0, tvp5150_test_patterns); 1518cb7a01acSMauro Carvalho Chehab sd->ctrl_handler = &core->hdl; 1519cb7a01acSMauro Carvalho Chehab if (core->hdl.error) { 1520cb7a01acSMauro Carvalho Chehab res = core->hdl.error; 1521c7d97499SJavier Martinez Canillas goto err; 1522cb7a01acSMauro Carvalho Chehab } 1523cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&core->hdl); 1524cb7a01acSMauro Carvalho Chehab 1525cb7a01acSMauro Carvalho Chehab /* Default is no cropping */ 1526cb7a01acSMauro Carvalho Chehab core->rect.top = 0; 1527cb7a01acSMauro Carvalho Chehab if (tvp5150_read_std(sd) & V4L2_STD_525_60) 1528cb7a01acSMauro Carvalho Chehab core->rect.height = TVP5150_V_MAX_525_60; 1529cb7a01acSMauro Carvalho Chehab else 1530cb7a01acSMauro Carvalho Chehab core->rect.height = TVP5150_V_MAX_OTHERS; 1531cb7a01acSMauro Carvalho Chehab core->rect.left = 0; 1532cb7a01acSMauro Carvalho Chehab core->rect.width = TVP5150_H_MAX; 1533cb7a01acSMauro Carvalho Chehab 1534c7d97499SJavier Martinez Canillas res = v4l2_async_register_subdev(sd); 1535c7d97499SJavier Martinez Canillas if (res < 0) 1536c7d97499SJavier Martinez Canillas goto err; 1537c7d97499SJavier Martinez Canillas 1538cb7a01acSMauro Carvalho Chehab if (debug > 1) 1539cb7a01acSMauro Carvalho Chehab tvp5150_log_status(sd); 1540cb7a01acSMauro Carvalho Chehab return 0; 1541c7d97499SJavier Martinez Canillas 1542c7d97499SJavier Martinez Canillas err: 1543c7d97499SJavier Martinez Canillas v4l2_ctrl_handler_free(&core->hdl); 1544c7d97499SJavier Martinez Canillas return res; 1545cb7a01acSMauro Carvalho Chehab } 1546cb7a01acSMauro Carvalho Chehab 1547cb7a01acSMauro Carvalho Chehab static int tvp5150_remove(struct i2c_client *c) 1548cb7a01acSMauro Carvalho Chehab { 1549cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(c); 1550cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1551cb7a01acSMauro Carvalho Chehab 1552cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, 1553cb7a01acSMauro Carvalho Chehab "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", 1554cb7a01acSMauro Carvalho Chehab c->addr << 1); 1555cb7a01acSMauro Carvalho Chehab 1556c7d97499SJavier Martinez Canillas v4l2_async_unregister_subdev(sd); 1557cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&decoder->hdl); 1558cb7a01acSMauro Carvalho Chehab return 0; 1559cb7a01acSMauro Carvalho Chehab } 1560cb7a01acSMauro Carvalho Chehab 1561cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1562cb7a01acSMauro Carvalho Chehab 1563cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvp5150_id[] = { 1564cb7a01acSMauro Carvalho Chehab { "tvp5150", 0 }, 1565cb7a01acSMauro Carvalho Chehab { } 1566cb7a01acSMauro Carvalho Chehab }; 1567cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvp5150_id); 1568cb7a01acSMauro Carvalho Chehab 15697ef930a7SEduard Gavin #if IS_ENABLED(CONFIG_OF) 15707ef930a7SEduard Gavin static const struct of_device_id tvp5150_of_match[] = { 15717ef930a7SEduard Gavin { .compatible = "ti,tvp5150", }, 15727ef930a7SEduard Gavin { /* sentinel */ }, 15737ef930a7SEduard Gavin }; 15747ef930a7SEduard Gavin MODULE_DEVICE_TABLE(of, tvp5150_of_match); 15757ef930a7SEduard Gavin #endif 15767ef930a7SEduard Gavin 1577cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvp5150_driver = { 1578cb7a01acSMauro Carvalho Chehab .driver = { 15797ef930a7SEduard Gavin .of_match_table = of_match_ptr(tvp5150_of_match), 1580cb7a01acSMauro Carvalho Chehab .name = "tvp5150", 1581cb7a01acSMauro Carvalho Chehab }, 1582cb7a01acSMauro Carvalho Chehab .probe = tvp5150_probe, 1583cb7a01acSMauro Carvalho Chehab .remove = tvp5150_remove, 1584cb7a01acSMauro Carvalho Chehab .id_table = tvp5150_id, 1585cb7a01acSMauro Carvalho Chehab }; 1586cb7a01acSMauro Carvalho Chehab 1587cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvp5150_driver); 1588