1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver 3cb7a01acSMauro Carvalho Chehab * 4cb7a01acSMauro Carvalho Chehab * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org) 5cb7a01acSMauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License v2 6cb7a01acSMauro Carvalho Chehab */ 7cb7a01acSMauro Carvalho Chehab 8cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 9cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 10cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 11cb7a01acSMauro Carvalho Chehab #include <linux/delay.h> 12cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 13c7d97499SJavier Martinez Canillas #include <media/v4l2-async.h> 14cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 15b5dcee22SMauro Carvalho Chehab #include <media/i2c/tvp5150.h> 16cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 17cb7a01acSMauro Carvalho Chehab 18cb7a01acSMauro Carvalho Chehab #include "tvp5150_reg.h" 19cb7a01acSMauro Carvalho Chehab 20785a3de1SPhilipp Zabel #define TVP5150_H_MAX 720U 21785a3de1SPhilipp Zabel #define TVP5150_V_MAX_525_60 480U 22785a3de1SPhilipp Zabel #define TVP5150_V_MAX_OTHERS 576U 23cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_LEFT 511 24cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_TOP 127 25cb7a01acSMauro Carvalho Chehab #define TVP5150_CROP_SHIFT 2 26cb7a01acSMauro Carvalho Chehab 27cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); 28cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab"); 29cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 30cb7a01acSMauro Carvalho Chehab 31cb7a01acSMauro Carvalho Chehab 32cb7a01acSMauro Carvalho Chehab static int debug; 332a0489d3SPhilipp Zabel module_param(debug, int, 0644); 34cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-2)"); 35cb7a01acSMauro Carvalho Chehab 36cb7a01acSMauro Carvalho Chehab struct tvp5150 { 37cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 38cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler hdl; 39cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect; 40cb7a01acSMauro Carvalho Chehab 41cb7a01acSMauro Carvalho Chehab v4l2_std_id norm; /* Current set standard */ 42cb7a01acSMauro Carvalho Chehab u32 input; 43cb7a01acSMauro Carvalho Chehab u32 output; 44cb7a01acSMauro Carvalho Chehab int enable; 45cb7a01acSMauro Carvalho Chehab }; 46cb7a01acSMauro Carvalho Chehab 47cb7a01acSMauro Carvalho Chehab static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) 48cb7a01acSMauro Carvalho Chehab { 49cb7a01acSMauro Carvalho Chehab return container_of(sd, struct tvp5150, sd); 50cb7a01acSMauro Carvalho Chehab } 51cb7a01acSMauro Carvalho Chehab 52cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 53cb7a01acSMauro Carvalho Chehab { 54cb7a01acSMauro Carvalho Chehab return &container_of(ctrl->handler, struct tvp5150, hdl)->sd; 55cb7a01acSMauro Carvalho Chehab } 56cb7a01acSMauro Carvalho Chehab 57cb7a01acSMauro Carvalho Chehab static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) 58cb7a01acSMauro Carvalho Chehab { 59cb7a01acSMauro Carvalho Chehab struct i2c_client *c = v4l2_get_subdevdata(sd); 60cb7a01acSMauro Carvalho Chehab int rc; 61cb7a01acSMauro Carvalho Chehab 62e35ce2e4SLaurent Pinchart rc = i2c_smbus_read_byte_data(c, addr); 63e35ce2e4SLaurent Pinchart if (rc < 0) { 64e35ce2e4SLaurent Pinchart v4l2_err(sd, "i2c i/o error: rc == %d\n", rc); 65e35ce2e4SLaurent Pinchart return rc; 66cb7a01acSMauro Carvalho Chehab } 67cb7a01acSMauro Carvalho Chehab 68e35ce2e4SLaurent Pinchart v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, rc); 69cb7a01acSMauro Carvalho Chehab 70e35ce2e4SLaurent Pinchart return rc; 71cb7a01acSMauro Carvalho Chehab } 72cb7a01acSMauro Carvalho Chehab 73cb7a01acSMauro Carvalho Chehab static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, 74cb7a01acSMauro Carvalho Chehab unsigned char value) 75cb7a01acSMauro Carvalho Chehab { 76cb7a01acSMauro Carvalho Chehab struct i2c_client *c = v4l2_get_subdevdata(sd); 77cb7a01acSMauro Carvalho Chehab int rc; 78cb7a01acSMauro Carvalho Chehab 79e35ce2e4SLaurent Pinchart v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value); 80e35ce2e4SLaurent Pinchart rc = i2c_smbus_write_byte_data(c, addr, value); 81e35ce2e4SLaurent Pinchart if (rc < 0) 82e35ce2e4SLaurent Pinchart v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d\n", rc); 83cb7a01acSMauro Carvalho Chehab } 84cb7a01acSMauro Carvalho Chehab 85cb7a01acSMauro Carvalho Chehab static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, 86cb7a01acSMauro Carvalho Chehab const u8 end, int max_line) 87cb7a01acSMauro Carvalho Chehab { 88cb7a01acSMauro Carvalho Chehab int i = 0; 89cb7a01acSMauro Carvalho Chehab 90cb7a01acSMauro Carvalho Chehab while (init != (u8)(end + 1)) { 91cb7a01acSMauro Carvalho Chehab if ((i % max_line) == 0) { 92cb7a01acSMauro Carvalho Chehab if (i > 0) 93cb7a01acSMauro Carvalho Chehab printk("\n"); 94cb7a01acSMauro Carvalho Chehab printk("tvp5150: %s reg 0x%02x = ", s, init); 95cb7a01acSMauro Carvalho Chehab } 96cb7a01acSMauro Carvalho Chehab printk("%02x ", tvp5150_read(sd, init)); 97cb7a01acSMauro Carvalho Chehab 98cb7a01acSMauro Carvalho Chehab init++; 99cb7a01acSMauro Carvalho Chehab i++; 100cb7a01acSMauro Carvalho Chehab } 101cb7a01acSMauro Carvalho Chehab printk("\n"); 102cb7a01acSMauro Carvalho Chehab } 103cb7a01acSMauro Carvalho Chehab 104cb7a01acSMauro Carvalho Chehab static int tvp5150_log_status(struct v4l2_subdev *sd) 105cb7a01acSMauro Carvalho Chehab { 106cb7a01acSMauro Carvalho Chehab printk("tvp5150: Video input source selection #1 = 0x%02x\n", 107cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); 108cb7a01acSMauro Carvalho Chehab printk("tvp5150: Analog channel controls = 0x%02x\n", 109cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); 110cb7a01acSMauro Carvalho Chehab printk("tvp5150: Operation mode controls = 0x%02x\n", 111cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_OP_MODE_CTL)); 112cb7a01acSMauro Carvalho Chehab printk("tvp5150: Miscellaneous controls = 0x%02x\n", 113cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MISC_CTL)); 114cb7a01acSMauro Carvalho Chehab printk("tvp5150: Autoswitch mask= 0x%02x\n", 115cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_AUTOSW_MSK)); 116cb7a01acSMauro Carvalho Chehab printk("tvp5150: Color killer threshold control = 0x%02x\n", 117cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); 118cb7a01acSMauro Carvalho Chehab printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", 119cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), 120cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), 121cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); 122cb7a01acSMauro Carvalho Chehab printk("tvp5150: Brightness control = 0x%02x\n", 123cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_BRIGHT_CTL)); 124cb7a01acSMauro Carvalho Chehab printk("tvp5150: Color saturation control = 0x%02x\n", 125cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_SATURATION_CTL)); 126cb7a01acSMauro Carvalho Chehab printk("tvp5150: Hue control = 0x%02x\n", 127cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HUE_CTL)); 128cb7a01acSMauro Carvalho Chehab printk("tvp5150: Contrast control = 0x%02x\n", 129cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONTRAST_CTL)); 130cb7a01acSMauro Carvalho Chehab printk("tvp5150: Outputs and data rates select = 0x%02x\n", 131cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); 132cb7a01acSMauro Carvalho Chehab printk("tvp5150: Configuration shared pins = 0x%02x\n", 133cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); 134cb7a01acSMauro Carvalho Chehab printk("tvp5150: Active video cropping start = 0x%02x%02x\n", 135cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), 136cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); 137cb7a01acSMauro Carvalho Chehab printk("tvp5150: Active video cropping stop = 0x%02x%02x\n", 138cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), 139cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); 140cb7a01acSMauro Carvalho Chehab printk("tvp5150: Genlock/RTC = 0x%02x\n", 141cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_GENLOCK)); 142cb7a01acSMauro Carvalho Chehab printk("tvp5150: Horizontal sync start = 0x%02x\n", 143cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); 144cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical blanking start = 0x%02x\n", 145cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); 146cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical blanking stop = 0x%02x\n", 147cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); 148cb7a01acSMauro Carvalho Chehab printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", 149cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), 150cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); 151cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt reset register B = 0x%02x\n", 152cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); 153cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt enable register B = 0x%02x\n", 154cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); 155cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt configuration register B = 0x%02x\n", 156cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); 157cb7a01acSMauro Carvalho Chehab printk("tvp5150: Video standard = 0x%02x\n", 158cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VIDEO_STD)); 159cb7a01acSMauro Carvalho Chehab printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", 160cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CB_GAIN_FACT), 161cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); 162cb7a01acSMauro Carvalho Chehab printk("tvp5150: Macrovision on counter = 0x%02x\n", 163cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); 164cb7a01acSMauro Carvalho Chehab printk("tvp5150: Macrovision off counter = 0x%02x\n", 165cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); 166cb7a01acSMauro Carvalho Chehab printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", 167cb7a01acSMauro Carvalho Chehab (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); 168cb7a01acSMauro Carvalho Chehab printk("tvp5150: Device ID = %02x%02x\n", 169cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MSB_DEV_ID), 170cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LSB_DEV_ID)); 171cb7a01acSMauro Carvalho Chehab printk("tvp5150: ROM version = (hex) %02x.%02x\n", 172cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), 173cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); 174cb7a01acSMauro Carvalho Chehab printk("tvp5150: Vertical line count = 0x%02x%02x\n", 175cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), 176cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); 177cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt status register B = 0x%02x\n", 178cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); 179cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt active register B = 0x%02x\n", 180cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); 181cb7a01acSMauro Carvalho Chehab printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", 182cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_1), 183cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_2), 184cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_3), 185cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_4), 186cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_5)); 187cb7a01acSMauro Carvalho Chehab 188cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, 189cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL1_END, 8); 190cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, 191cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL2_END, 8); 192cb7a01acSMauro Carvalho Chehab 193cb7a01acSMauro Carvalho Chehab printk("tvp5150: Teletext filter enable = 0x%02x\n", 194cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); 195cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt status register A = 0x%02x\n", 196cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); 197cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt enable register A = 0x%02x\n", 198cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); 199cb7a01acSMauro Carvalho Chehab printk("tvp5150: Interrupt configuration = 0x%02x\n", 200cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_CONF)); 201cb7a01acSMauro Carvalho Chehab printk("tvp5150: VDP status register = 0x%02x\n", 202cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); 203cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO word count = 0x%02x\n", 204cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); 205cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO interrupt threshold = 0x%02x\n", 206cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); 207cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO reset = 0x%02x\n", 208cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_RESET)); 209cb7a01acSMauro Carvalho Chehab printk("tvp5150: Line number interrupt = 0x%02x\n", 210cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); 211cb7a01acSMauro Carvalho Chehab printk("tvp5150: Pixel alignment register = 0x%02x%02x\n", 212cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), 213cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); 214cb7a01acSMauro Carvalho Chehab printk("tvp5150: FIFO output control = 0x%02x\n", 215cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); 216cb7a01acSMauro Carvalho Chehab printk("tvp5150: Full field enable = 0x%02x\n", 217cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); 218cb7a01acSMauro Carvalho Chehab printk("tvp5150: Full field mode register = 0x%02x\n", 219cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); 220cb7a01acSMauro Carvalho Chehab 221cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI, 222cb7a01acSMauro Carvalho Chehab TVP5150_CC_DATA_END, 8); 223cb7a01acSMauro Carvalho Chehab 224cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "WSS data", TVP5150_WSS_DATA_INI, 225cb7a01acSMauro Carvalho Chehab TVP5150_WSS_DATA_END, 8); 226cb7a01acSMauro Carvalho Chehab 227cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VPS data", TVP5150_VPS_DATA_INI, 228cb7a01acSMauro Carvalho Chehab TVP5150_VPS_DATA_END, 8); 229cb7a01acSMauro Carvalho Chehab 230cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VITC data", TVP5150_VITC_DATA_INI, 231cb7a01acSMauro Carvalho Chehab TVP5150_VITC_DATA_END, 10); 232cb7a01acSMauro Carvalho Chehab 233cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Line mode", TVP5150_LINE_MODE_INI, 234cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_END, 8); 235cb7a01acSMauro Carvalho Chehab return 0; 236cb7a01acSMauro Carvalho Chehab } 237cb7a01acSMauro Carvalho Chehab 238cb7a01acSMauro Carvalho Chehab /**************************************************************************** 239cb7a01acSMauro Carvalho Chehab Basic functions 240cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 241cb7a01acSMauro Carvalho Chehab 242cb7a01acSMauro Carvalho Chehab static inline void tvp5150_selmux(struct v4l2_subdev *sd) 243cb7a01acSMauro Carvalho Chehab { 244cb7a01acSMauro Carvalho Chehab int opmode = 0; 245cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 246cb7a01acSMauro Carvalho Chehab int input = 0; 247cb7a01acSMauro Carvalho Chehab int val; 248cb7a01acSMauro Carvalho Chehab 249cb7a01acSMauro Carvalho Chehab if ((decoder->output & TVP5150_BLACK_SCREEN) || !decoder->enable) 250cb7a01acSMauro Carvalho Chehab input = 8; 251cb7a01acSMauro Carvalho Chehab 252cb7a01acSMauro Carvalho Chehab switch (decoder->input) { 253cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE1: 254cb7a01acSMauro Carvalho Chehab input |= 2; 255cb7a01acSMauro Carvalho Chehab /* fall through */ 256cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE0: 257cb7a01acSMauro Carvalho Chehab break; 258cb7a01acSMauro Carvalho Chehab case TVP5150_SVIDEO: 259cb7a01acSMauro Carvalho Chehab default: 260cb7a01acSMauro Carvalho Chehab input |= 1; 261cb7a01acSMauro Carvalho Chehab break; 262cb7a01acSMauro Carvalho Chehab } 263cb7a01acSMauro Carvalho Chehab 264cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i " 265cb7a01acSMauro Carvalho Chehab "=> tvp5150 input=%i, opmode=%i\n", 266cb7a01acSMauro Carvalho Chehab decoder->input, decoder->output, 267cb7a01acSMauro Carvalho Chehab input, opmode); 268cb7a01acSMauro Carvalho Chehab 269cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode); 270cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input); 271cb7a01acSMauro Carvalho Chehab 272cb7a01acSMauro Carvalho Chehab /* Svideo should enable YCrCb output and disable GPCL output 273cb7a01acSMauro Carvalho Chehab * For Composite and TV, it should be the reverse 274cb7a01acSMauro Carvalho Chehab */ 275cb7a01acSMauro Carvalho Chehab val = tvp5150_read(sd, TVP5150_MISC_CTL); 276cb7a01acSMauro Carvalho Chehab if (val < 0) { 277cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", __func__, val); 278cb7a01acSMauro Carvalho Chehab return; 279cb7a01acSMauro Carvalho Chehab } 280cb7a01acSMauro Carvalho Chehab 281cb7a01acSMauro Carvalho Chehab if (decoder->input == TVP5150_SVIDEO) 282cb7a01acSMauro Carvalho Chehab val = (val & ~0x40) | 0x10; 283cb7a01acSMauro Carvalho Chehab else 284cb7a01acSMauro Carvalho Chehab val = (val & ~0x10) | 0x40; 285cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_MISC_CTL, val); 286cb7a01acSMauro Carvalho Chehab }; 287cb7a01acSMauro Carvalho Chehab 288cb7a01acSMauro Carvalho Chehab struct i2c_reg_value { 289cb7a01acSMauro Carvalho Chehab unsigned char reg; 290cb7a01acSMauro Carvalho Chehab unsigned char value; 291cb7a01acSMauro Carvalho Chehab }; 292cb7a01acSMauro Carvalho Chehab 293cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 294cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_default[] = { 295cb7a01acSMauro Carvalho Chehab { /* 0x00 */ 296cb7a01acSMauro Carvalho Chehab TVP5150_VD_IN_SRC_SEL_1,0x00 297cb7a01acSMauro Carvalho Chehab }, 298cb7a01acSMauro Carvalho Chehab { /* 0x01 */ 299cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL,0x15 300cb7a01acSMauro Carvalho Chehab }, 301cb7a01acSMauro Carvalho Chehab { /* 0x02 */ 302cb7a01acSMauro Carvalho Chehab TVP5150_OP_MODE_CTL,0x00 303cb7a01acSMauro Carvalho Chehab }, 304cb7a01acSMauro Carvalho Chehab { /* 0x03 */ 305cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL,0x01 306cb7a01acSMauro Carvalho Chehab }, 307cb7a01acSMauro Carvalho Chehab { /* 0x06 */ 308cb7a01acSMauro Carvalho Chehab TVP5150_COLOR_KIL_THSH_CTL,0x10 309cb7a01acSMauro Carvalho Chehab }, 310cb7a01acSMauro Carvalho Chehab { /* 0x07 */ 311cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_1,0x60 312cb7a01acSMauro Carvalho Chehab }, 313cb7a01acSMauro Carvalho Chehab { /* 0x08 */ 314cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_2,0x00 315cb7a01acSMauro Carvalho Chehab }, 316cb7a01acSMauro Carvalho Chehab { /* 0x09 */ 317cb7a01acSMauro Carvalho Chehab TVP5150_BRIGHT_CTL,0x80 318cb7a01acSMauro Carvalho Chehab }, 319cb7a01acSMauro Carvalho Chehab { /* 0x0a */ 320cb7a01acSMauro Carvalho Chehab TVP5150_SATURATION_CTL,0x80 321cb7a01acSMauro Carvalho Chehab }, 322cb7a01acSMauro Carvalho Chehab { /* 0x0b */ 323cb7a01acSMauro Carvalho Chehab TVP5150_HUE_CTL,0x00 324cb7a01acSMauro Carvalho Chehab }, 325cb7a01acSMauro Carvalho Chehab { /* 0x0c */ 326cb7a01acSMauro Carvalho Chehab TVP5150_CONTRAST_CTL,0x80 327cb7a01acSMauro Carvalho Chehab }, 328cb7a01acSMauro Carvalho Chehab { /* 0x0d */ 329cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL,0x47 330cb7a01acSMauro Carvalho Chehab }, 331cb7a01acSMauro Carvalho Chehab { /* 0x0e */ 332cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_3,0x00 333cb7a01acSMauro Carvalho Chehab }, 334cb7a01acSMauro Carvalho Chehab { /* 0x0f */ 335cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN,0x08 336cb7a01acSMauro Carvalho Chehab }, 337cb7a01acSMauro Carvalho Chehab { /* 0x11 */ 338cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_MSB,0x00 339cb7a01acSMauro Carvalho Chehab }, 340cb7a01acSMauro Carvalho Chehab { /* 0x12 */ 341cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_LSB,0x00 342cb7a01acSMauro Carvalho Chehab }, 343cb7a01acSMauro Carvalho Chehab { /* 0x13 */ 344cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_MSB,0x00 345cb7a01acSMauro Carvalho Chehab }, 346cb7a01acSMauro Carvalho Chehab { /* 0x14 */ 347cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_LSB,0x00 348cb7a01acSMauro Carvalho Chehab }, 349cb7a01acSMauro Carvalho Chehab { /* 0x15 */ 350cb7a01acSMauro Carvalho Chehab TVP5150_GENLOCK,0x01 351cb7a01acSMauro Carvalho Chehab }, 352cb7a01acSMauro Carvalho Chehab { /* 0x16 */ 353cb7a01acSMauro Carvalho Chehab TVP5150_HORIZ_SYNC_START,0x80 354cb7a01acSMauro Carvalho Chehab }, 355cb7a01acSMauro Carvalho Chehab { /* 0x18 */ 356cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_START,0x00 357cb7a01acSMauro Carvalho Chehab }, 358cb7a01acSMauro Carvalho Chehab { /* 0x19 */ 359cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_STOP,0x00 360cb7a01acSMauro Carvalho Chehab }, 361cb7a01acSMauro Carvalho Chehab { /* 0x1a */ 362cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1,0x0c 363cb7a01acSMauro Carvalho Chehab }, 364cb7a01acSMauro Carvalho Chehab { /* 0x1b */ 365cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2,0x14 366cb7a01acSMauro Carvalho Chehab }, 367cb7a01acSMauro Carvalho Chehab { /* 0x1c */ 368cb7a01acSMauro Carvalho Chehab TVP5150_INT_RESET_REG_B,0x00 369cb7a01acSMauro Carvalho Chehab }, 370cb7a01acSMauro Carvalho Chehab { /* 0x1d */ 371cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_B,0x00 372cb7a01acSMauro Carvalho Chehab }, 373cb7a01acSMauro Carvalho Chehab { /* 0x1e */ 374cb7a01acSMauro Carvalho Chehab TVP5150_INTT_CONFIG_REG_B,0x00 375cb7a01acSMauro Carvalho Chehab }, 376cb7a01acSMauro Carvalho Chehab { /* 0x28 */ 377cb7a01acSMauro Carvalho Chehab TVP5150_VIDEO_STD,0x00 378cb7a01acSMauro Carvalho Chehab }, 379cb7a01acSMauro Carvalho Chehab { /* 0x2e */ 380cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_ON_CTR,0x0f 381cb7a01acSMauro Carvalho Chehab }, 382cb7a01acSMauro Carvalho Chehab { /* 0x2f */ 383cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_OFF_CTR,0x01 384cb7a01acSMauro Carvalho Chehab }, 385cb7a01acSMauro Carvalho Chehab { /* 0xbb */ 386cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL_ENA,0x00 387cb7a01acSMauro Carvalho Chehab }, 388cb7a01acSMauro Carvalho Chehab { /* 0xc0 */ 389cb7a01acSMauro Carvalho Chehab TVP5150_INT_STATUS_REG_A,0x00 390cb7a01acSMauro Carvalho Chehab }, 391cb7a01acSMauro Carvalho Chehab { /* 0xc1 */ 392cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_A,0x00 393cb7a01acSMauro Carvalho Chehab }, 394cb7a01acSMauro Carvalho Chehab { /* 0xc2 */ 395cb7a01acSMauro Carvalho Chehab TVP5150_INT_CONF,0x04 396cb7a01acSMauro Carvalho Chehab }, 397cb7a01acSMauro Carvalho Chehab { /* 0xc8 */ 398cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_INT_THRESHOLD,0x80 399cb7a01acSMauro Carvalho Chehab }, 400cb7a01acSMauro Carvalho Chehab { /* 0xc9 */ 401cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_RESET,0x00 402cb7a01acSMauro Carvalho Chehab }, 403cb7a01acSMauro Carvalho Chehab { /* 0xca */ 404cb7a01acSMauro Carvalho Chehab TVP5150_LINE_NUMBER_INT,0x00 405cb7a01acSMauro Carvalho Chehab }, 406cb7a01acSMauro Carvalho Chehab { /* 0xcb */ 407cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_LOW,0x4e 408cb7a01acSMauro Carvalho Chehab }, 409cb7a01acSMauro Carvalho Chehab { /* 0xcc */ 410cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_HIGH,0x00 411cb7a01acSMauro Carvalho Chehab }, 412cb7a01acSMauro Carvalho Chehab { /* 0xcd */ 413cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_OUT_CTRL,0x01 414cb7a01acSMauro Carvalho Chehab }, 415cb7a01acSMauro Carvalho Chehab { /* 0xcf */ 416cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_ENA,0x00 417cb7a01acSMauro Carvalho Chehab }, 418cb7a01acSMauro Carvalho Chehab { /* 0xd0 */ 419cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_INI,0x00 420cb7a01acSMauro Carvalho Chehab }, 421cb7a01acSMauro Carvalho Chehab { /* 0xfc */ 422cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_MODE_REG,0x7f 423cb7a01acSMauro Carvalho Chehab }, 424cb7a01acSMauro Carvalho Chehab { /* end of data */ 425cb7a01acSMauro Carvalho Chehab 0xff,0xff 426cb7a01acSMauro Carvalho Chehab } 427cb7a01acSMauro Carvalho Chehab }; 428cb7a01acSMauro Carvalho Chehab 429cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 430cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_enable[] = { 431cb7a01acSMauro Carvalho Chehab { 432cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN, 2 433cb7a01acSMauro Carvalho Chehab },{ /* Automatic offset and AGC enabled */ 434cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 435cb7a01acSMauro Carvalho Chehab },{ /* Activate YCrCb output 0x9 or 0xd ? */ 436cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL, 0x6f 437cb7a01acSMauro Carvalho Chehab },{ /* Activates video std autodetection for all standards */ 438cb7a01acSMauro Carvalho Chehab TVP5150_AUTOSW_MSK, 0x0 439cb7a01acSMauro Carvalho Chehab },{ /* Default format: 0x47. For 4:2:2: 0x40 */ 440cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 441cb7a01acSMauro Carvalho Chehab },{ 442cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 443cb7a01acSMauro Carvalho Chehab },{ 444cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x54 445cb7a01acSMauro Carvalho Chehab },{ /* Non documented, but initialized on WinTV USB2 */ 446cb7a01acSMauro Carvalho Chehab 0x27, 0x20 447cb7a01acSMauro Carvalho Chehab },{ 448cb7a01acSMauro Carvalho Chehab 0xff,0xff 449cb7a01acSMauro Carvalho Chehab } 450cb7a01acSMauro Carvalho Chehab }; 451cb7a01acSMauro Carvalho Chehab 452cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type { 453cb7a01acSMauro Carvalho Chehab unsigned int vbi_type; 454cb7a01acSMauro Carvalho Chehab unsigned int ini_line; 455cb7a01acSMauro Carvalho Chehab unsigned int end_line; 456cb7a01acSMauro Carvalho Chehab unsigned int by_field :1; 457cb7a01acSMauro Carvalho Chehab }; 458cb7a01acSMauro Carvalho Chehab 459cb7a01acSMauro Carvalho Chehab struct i2c_vbi_ram_value { 460cb7a01acSMauro Carvalho Chehab u16 reg; 461cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type type; 462cb7a01acSMauro Carvalho Chehab unsigned char values[16]; 463cb7a01acSMauro Carvalho Chehab }; 464cb7a01acSMauro Carvalho Chehab 465cb7a01acSMauro Carvalho Chehab /* This struct have the values for each supported VBI Standard 466cb7a01acSMauro Carvalho Chehab * by 467cb7a01acSMauro Carvalho Chehab tvp5150_vbi_types should follow the same order as vbi_ram_default 468cb7a01acSMauro Carvalho Chehab * value 0 means rom position 0x10, value 1 means rom position 0x30 469cb7a01acSMauro Carvalho Chehab * and so on. There are 16 possible locations from 0 to 15. 470cb7a01acSMauro Carvalho Chehab */ 471cb7a01acSMauro Carvalho Chehab 472cb7a01acSMauro Carvalho Chehab static struct i2c_vbi_ram_value vbi_ram_default[] = 473cb7a01acSMauro Carvalho Chehab { 474cb7a01acSMauro Carvalho Chehab /* FIXME: Current api doesn't handle all VBI types, those not 475cb7a01acSMauro Carvalho Chehab yet supported are placed under #if 0 */ 476cb7a01acSMauro Carvalho Chehab #if 0 477cb7a01acSMauro Carvalho Chehab {0x010, /* Teletext, SECAM, WST System A */ 478cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, 479cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 480cb7a01acSMauro Carvalho Chehab 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } 481cb7a01acSMauro Carvalho Chehab }, 482cb7a01acSMauro Carvalho Chehab #endif 483cb7a01acSMauro Carvalho Chehab {0x030, /* Teletext, PAL, WST System B */ 484cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_B,6,22,1}, 485cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 486cb7a01acSMauro Carvalho Chehab 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } 487cb7a01acSMauro Carvalho Chehab }, 488cb7a01acSMauro Carvalho Chehab #if 0 489cb7a01acSMauro Carvalho Chehab {0x050, /* Teletext, PAL, WST System C */ 490cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, 491cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 492cb7a01acSMauro Carvalho Chehab 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 493cb7a01acSMauro Carvalho Chehab }, 494cb7a01acSMauro Carvalho Chehab {0x070, /* Teletext, NTSC, WST System B */ 495cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, 496cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, 497cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 498cb7a01acSMauro Carvalho Chehab }, 499cb7a01acSMauro Carvalho Chehab {0x090, /* Tetetext, NTSC NABTS System C */ 500cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, 501cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 502cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } 503cb7a01acSMauro Carvalho Chehab }, 504cb7a01acSMauro Carvalho Chehab {0x0b0, /* Teletext, NTSC-J, NABTS System D */ 505cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, 506cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, 507cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 508cb7a01acSMauro Carvalho Chehab }, 509cb7a01acSMauro Carvalho Chehab {0x0d0, /* Closed Caption, PAL/SECAM */ 510cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_625,22,22,1}, 511cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 512cb7a01acSMauro Carvalho Chehab 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 513cb7a01acSMauro Carvalho Chehab }, 514cb7a01acSMauro Carvalho Chehab #endif 515cb7a01acSMauro Carvalho Chehab {0x0f0, /* Closed Caption, NTSC */ 516cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_525,21,21,1}, 517cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 518cb7a01acSMauro Carvalho Chehab 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 519cb7a01acSMauro Carvalho Chehab }, 520cb7a01acSMauro Carvalho Chehab {0x110, /* Wide Screen Signal, PAL/SECAM */ 521cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_625,23,23,1}, 522cb7a01acSMauro Carvalho Chehab { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 523cb7a01acSMauro Carvalho Chehab 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } 524cb7a01acSMauro Carvalho Chehab }, 525cb7a01acSMauro Carvalho Chehab #if 0 526cb7a01acSMauro Carvalho Chehab {0x130, /* Wide Screen Signal, NTSC C */ 527cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_525,20,20,1}, 528cb7a01acSMauro Carvalho Chehab { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, 529cb7a01acSMauro Carvalho Chehab 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } 530cb7a01acSMauro Carvalho Chehab }, 531cb7a01acSMauro Carvalho Chehab {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ 532cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_625,6,22,0}, 533cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 534cb7a01acSMauro Carvalho Chehab 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 535cb7a01acSMauro Carvalho Chehab }, 536cb7a01acSMauro Carvalho Chehab {0x170, /* Vertical Interval Timecode (VITC), NTSC */ 537cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_525,10,20,0}, 538cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 539cb7a01acSMauro Carvalho Chehab 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 540cb7a01acSMauro Carvalho Chehab }, 541cb7a01acSMauro Carvalho Chehab #endif 542cb7a01acSMauro Carvalho Chehab {0x190, /* Video Program System (VPS), PAL */ 543cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_VPS,16,16,0}, 544cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, 545cb7a01acSMauro Carvalho Chehab 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } 546cb7a01acSMauro Carvalho Chehab }, 547cb7a01acSMauro Carvalho Chehab /* 0x1d0 User programmable */ 548cb7a01acSMauro Carvalho Chehab 549cb7a01acSMauro Carvalho Chehab /* End of struct */ 550cb7a01acSMauro Carvalho Chehab { (u16)-1 } 551cb7a01acSMauro Carvalho Chehab }; 552cb7a01acSMauro Carvalho Chehab 553cb7a01acSMauro Carvalho Chehab static int tvp5150_write_inittab(struct v4l2_subdev *sd, 554cb7a01acSMauro Carvalho Chehab const struct i2c_reg_value *regs) 555cb7a01acSMauro Carvalho Chehab { 556cb7a01acSMauro Carvalho Chehab while (regs->reg != 0xff) { 557cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, regs->reg, regs->value); 558cb7a01acSMauro Carvalho Chehab regs++; 559cb7a01acSMauro Carvalho Chehab } 560cb7a01acSMauro Carvalho Chehab return 0; 561cb7a01acSMauro Carvalho Chehab } 562cb7a01acSMauro Carvalho Chehab 563cb7a01acSMauro Carvalho Chehab static int tvp5150_vdp_init(struct v4l2_subdev *sd, 564cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs) 565cb7a01acSMauro Carvalho Chehab { 566cb7a01acSMauro Carvalho Chehab unsigned int i; 567cb7a01acSMauro Carvalho Chehab 568cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 569cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); 570cb7a01acSMauro Carvalho Chehab 571cb7a01acSMauro Carvalho Chehab /* Before programming, Line mode should be at 0xff */ 572cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 573cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, i, 0xff); 574cb7a01acSMauro Carvalho Chehab 575cb7a01acSMauro Carvalho Chehab /* Load Ram Table */ 576cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1) { 577cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); 578cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); 579cb7a01acSMauro Carvalho Chehab 580cb7a01acSMauro Carvalho Chehab for (i = 0; i < 16; i++) 581cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]); 582cb7a01acSMauro Carvalho Chehab 583cb7a01acSMauro Carvalho Chehab regs++; 584cb7a01acSMauro Carvalho Chehab } 585cb7a01acSMauro Carvalho Chehab return 0; 586cb7a01acSMauro Carvalho Chehab } 587cb7a01acSMauro Carvalho Chehab 588cb7a01acSMauro Carvalho Chehab /* Fills VBI capabilities based on i2c_vbi_ram_value struct */ 589cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, 590cb7a01acSMauro Carvalho Chehab struct v4l2_sliced_vbi_cap *cap) 591cb7a01acSMauro Carvalho Chehab { 592cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = vbi_ram_default; 593cb7a01acSMauro Carvalho Chehab int line; 594cb7a01acSMauro Carvalho Chehab 595cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n"); 596cb7a01acSMauro Carvalho Chehab memset(cap, 0, sizeof *cap); 597cb7a01acSMauro Carvalho Chehab 598cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1 ) { 599cb7a01acSMauro Carvalho Chehab for (line=regs->type.ini_line;line<=regs->type.end_line;line++) { 600cb7a01acSMauro Carvalho Chehab cap->service_lines[0][line] |= regs->type.vbi_type; 601cb7a01acSMauro Carvalho Chehab } 602cb7a01acSMauro Carvalho Chehab cap->service_set |= regs->type.vbi_type; 603cb7a01acSMauro Carvalho Chehab 604cb7a01acSMauro Carvalho Chehab regs++; 605cb7a01acSMauro Carvalho Chehab } 606cb7a01acSMauro Carvalho Chehab return 0; 607cb7a01acSMauro Carvalho Chehab } 608cb7a01acSMauro Carvalho Chehab 609cb7a01acSMauro Carvalho Chehab /* Set vbi processing 610cb7a01acSMauro Carvalho Chehab * type - one of tvp5150_vbi_types 611cb7a01acSMauro Carvalho Chehab * line - line to gather data 612cb7a01acSMauro Carvalho Chehab * fields: bit 0 field1, bit 1, field2 613cb7a01acSMauro Carvalho Chehab * flags (default=0xf0) is a bitmask, were set means: 614cb7a01acSMauro Carvalho Chehab * bit 7: enable filtering null bytes on CC 615cb7a01acSMauro Carvalho Chehab * bit 6: send data also to FIFO 616cb7a01acSMauro Carvalho Chehab * bit 5: don't allow data with errors on FIFO 617cb7a01acSMauro Carvalho Chehab * bit 4: enable ECC when possible 618cb7a01acSMauro Carvalho Chehab * pix_align = pix alignment: 619cb7a01acSMauro Carvalho Chehab * LSB = field1 620cb7a01acSMauro Carvalho Chehab * MSB = field2 621cb7a01acSMauro Carvalho Chehab */ 622cb7a01acSMauro Carvalho Chehab static int tvp5150_set_vbi(struct v4l2_subdev *sd, 623cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs, 624cb7a01acSMauro Carvalho Chehab unsigned int type,u8 flags, int line, 625cb7a01acSMauro Carvalho Chehab const int fields) 626cb7a01acSMauro Carvalho Chehab { 627cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 628cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 629cb7a01acSMauro Carvalho Chehab u8 reg; 630cb7a01acSMauro Carvalho Chehab int pos=0; 631cb7a01acSMauro Carvalho Chehab 632cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 633cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); 634cb7a01acSMauro Carvalho Chehab return 0; 635cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 636cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 637cb7a01acSMauro Carvalho Chehab line += 3; 638cb7a01acSMauro Carvalho Chehab } 639cb7a01acSMauro Carvalho Chehab 640cb7a01acSMauro Carvalho Chehab if (line<6||line>27) 641cb7a01acSMauro Carvalho Chehab return 0; 642cb7a01acSMauro Carvalho Chehab 643cb7a01acSMauro Carvalho Chehab while (regs->reg != (u16)-1 ) { 644cb7a01acSMauro Carvalho Chehab if ((type & regs->type.vbi_type) && 645cb7a01acSMauro Carvalho Chehab (line>=regs->type.ini_line) && 646cb7a01acSMauro Carvalho Chehab (line<=regs->type.end_line)) { 647cb7a01acSMauro Carvalho Chehab type=regs->type.vbi_type; 648cb7a01acSMauro Carvalho Chehab break; 649cb7a01acSMauro Carvalho Chehab } 650cb7a01acSMauro Carvalho Chehab 651cb7a01acSMauro Carvalho Chehab regs++; 652cb7a01acSMauro Carvalho Chehab pos++; 653cb7a01acSMauro Carvalho Chehab } 654cb7a01acSMauro Carvalho Chehab if (regs->reg == (u16)-1) 655cb7a01acSMauro Carvalho Chehab return 0; 656cb7a01acSMauro Carvalho Chehab 657cb7a01acSMauro Carvalho Chehab type=pos | (flags & 0xf0); 658cb7a01acSMauro Carvalho Chehab reg=((line-6)<<1)+TVP5150_LINE_MODE_INI; 659cb7a01acSMauro Carvalho Chehab 660cb7a01acSMauro Carvalho Chehab if (fields&1) { 661cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg, type); 662cb7a01acSMauro Carvalho Chehab } 663cb7a01acSMauro Carvalho Chehab 664cb7a01acSMauro Carvalho Chehab if (fields&2) { 665cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg+1, type); 666cb7a01acSMauro Carvalho Chehab } 667cb7a01acSMauro Carvalho Chehab 668cb7a01acSMauro Carvalho Chehab return type; 669cb7a01acSMauro Carvalho Chehab } 670cb7a01acSMauro Carvalho Chehab 671cb7a01acSMauro Carvalho Chehab static int tvp5150_get_vbi(struct v4l2_subdev *sd, 672cb7a01acSMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs, int line) 673cb7a01acSMauro Carvalho Chehab { 674cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 675cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 676cb7a01acSMauro Carvalho Chehab u8 reg; 677cb7a01acSMauro Carvalho Chehab int pos, type = 0; 678cb7a01acSMauro Carvalho Chehab int i, ret = 0; 679cb7a01acSMauro Carvalho Chehab 680cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 681cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); 682cb7a01acSMauro Carvalho Chehab return 0; 683cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 684cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 685cb7a01acSMauro Carvalho Chehab line += 3; 686cb7a01acSMauro Carvalho Chehab } 687cb7a01acSMauro Carvalho Chehab 688cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 689cb7a01acSMauro Carvalho Chehab return 0; 690cb7a01acSMauro Carvalho Chehab 691cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 692cb7a01acSMauro Carvalho Chehab 693cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 1; i++) { 694cb7a01acSMauro Carvalho Chehab ret = tvp5150_read(sd, reg + i); 695cb7a01acSMauro Carvalho Chehab if (ret < 0) { 696cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", 697cb7a01acSMauro Carvalho Chehab __func__, ret); 698cb7a01acSMauro Carvalho Chehab return 0; 699cb7a01acSMauro Carvalho Chehab } 700cb7a01acSMauro Carvalho Chehab pos = ret & 0x0f; 701cb7a01acSMauro Carvalho Chehab if (pos < 0x0f) 702cb7a01acSMauro Carvalho Chehab type |= regs[pos].type.vbi_type; 703cb7a01acSMauro Carvalho Chehab } 704cb7a01acSMauro Carvalho Chehab 705cb7a01acSMauro Carvalho Chehab return type; 706cb7a01acSMauro Carvalho Chehab } 707cb7a01acSMauro Carvalho Chehab 708cb7a01acSMauro Carvalho Chehab static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) 709cb7a01acSMauro Carvalho Chehab { 710cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 711cb7a01acSMauro Carvalho Chehab int fmt = 0; 712cb7a01acSMauro Carvalho Chehab 713cb7a01acSMauro Carvalho Chehab decoder->norm = std; 714cb7a01acSMauro Carvalho Chehab 715cb7a01acSMauro Carvalho Chehab /* First tests should be against specific std */ 716cb7a01acSMauro Carvalho Chehab 71726811ae0SHans Verkuil if (std == V4L2_STD_NTSC_443) { 718cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_4_43_BIT; 71926811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_M) { 720cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_M_BIT; 72126811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) { 722cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_COMBINATION_N_BIT; 723cb7a01acSMauro Carvalho Chehab } else { 724cb7a01acSMauro Carvalho Chehab /* Then, test against generic ones */ 725cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 726cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_MJ_BIT; 727cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_PAL) 728cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_BDGHIN_BIT; 729cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_SECAM) 730cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_SECAM_BIT; 731cb7a01acSMauro Carvalho Chehab } 732cb7a01acSMauro Carvalho Chehab 733cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt); 734cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VIDEO_STD, fmt); 735cb7a01acSMauro Carvalho Chehab return 0; 736cb7a01acSMauro Carvalho Chehab } 737cb7a01acSMauro Carvalho Chehab 738cb7a01acSMauro Carvalho Chehab static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 739cb7a01acSMauro Carvalho Chehab { 740cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 741cb7a01acSMauro Carvalho Chehab 742cb7a01acSMauro Carvalho Chehab if (decoder->norm == std) 743cb7a01acSMauro Carvalho Chehab return 0; 744cb7a01acSMauro Carvalho Chehab 745cb7a01acSMauro Carvalho Chehab /* Change cropping height limits */ 746cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 747cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_525_60; 748cb7a01acSMauro Carvalho Chehab else 749cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_OTHERS; 750cb7a01acSMauro Carvalho Chehab 751cb7a01acSMauro Carvalho Chehab 752cb7a01acSMauro Carvalho Chehab return tvp5150_set_std(sd, std); 753cb7a01acSMauro Carvalho Chehab } 754cb7a01acSMauro Carvalho Chehab 755cb7a01acSMauro Carvalho Chehab static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) 756cb7a01acSMauro Carvalho Chehab { 757cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 758cb7a01acSMauro Carvalho Chehab 759cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to its default values */ 760cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_default); 761cb7a01acSMauro Carvalho Chehab 762cb7a01acSMauro Carvalho Chehab /* Initializes VDP registers */ 763cb7a01acSMauro Carvalho Chehab tvp5150_vdp_init(sd, vbi_ram_default); 764cb7a01acSMauro Carvalho Chehab 765cb7a01acSMauro Carvalho Chehab /* Selects decoder input */ 766cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 767cb7a01acSMauro Carvalho Chehab 768cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to stream enabled values */ 769cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_enable); 770cb7a01acSMauro Carvalho Chehab 771cb7a01acSMauro Carvalho Chehab /* Initialize image preferences */ 772cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&decoder->hdl); 773cb7a01acSMauro Carvalho Chehab 774cb7a01acSMauro Carvalho Chehab tvp5150_set_std(sd, decoder->norm); 775cb7a01acSMauro Carvalho Chehab return 0; 776cb7a01acSMauro Carvalho Chehab }; 777cb7a01acSMauro Carvalho Chehab 778cb7a01acSMauro Carvalho Chehab static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) 779cb7a01acSMauro Carvalho Chehab { 780cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_sd(ctrl); 781cb7a01acSMauro Carvalho Chehab 782cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 783cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 784cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val); 785cb7a01acSMauro Carvalho Chehab return 0; 786cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 787cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val); 788cb7a01acSMauro Carvalho Chehab return 0; 789cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 790cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val); 791cb7a01acSMauro Carvalho Chehab return 0; 792cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 793cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val); 794cb7a01acSMauro Carvalho Chehab return 0; 795cb7a01acSMauro Carvalho Chehab } 796cb7a01acSMauro Carvalho Chehab return -EINVAL; 797cb7a01acSMauro Carvalho Chehab } 798cb7a01acSMauro Carvalho Chehab 799cb7a01acSMauro Carvalho Chehab static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) 800cb7a01acSMauro Carvalho Chehab { 801cb7a01acSMauro Carvalho Chehab int val = tvp5150_read(sd, TVP5150_STATUS_REG_5); 802cb7a01acSMauro Carvalho Chehab 803cb7a01acSMauro Carvalho Chehab switch (val & 0x0F) { 804cb7a01acSMauro Carvalho Chehab case 0x01: 805cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC; 806cb7a01acSMauro Carvalho Chehab case 0x03: 807cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL; 808cb7a01acSMauro Carvalho Chehab case 0x05: 809cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M; 810cb7a01acSMauro Carvalho Chehab case 0x07: 811cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc; 812cb7a01acSMauro Carvalho Chehab case 0x09: 813cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443; 814cb7a01acSMauro Carvalho Chehab case 0xb: 815cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 816cb7a01acSMauro Carvalho Chehab default: 817cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN; 818cb7a01acSMauro Carvalho Chehab } 819cb7a01acSMauro Carvalho Chehab } 820cb7a01acSMauro Carvalho Chehab 821ebcff5fcSHans Verkuil static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, 822ebcff5fcSHans Verkuil struct v4l2_subdev_pad_config *cfg, 823ebcff5fcSHans Verkuil struct v4l2_subdev_mbus_code_enum *code) 824cb7a01acSMauro Carvalho Chehab { 825ebcff5fcSHans Verkuil if (code->pad || code->index) 826cb7a01acSMauro Carvalho Chehab return -EINVAL; 827cb7a01acSMauro Carvalho Chehab 828ebcff5fcSHans Verkuil code->code = MEDIA_BUS_FMT_UYVY8_2X8; 829cb7a01acSMauro Carvalho Chehab return 0; 830cb7a01acSMauro Carvalho Chehab } 831cb7a01acSMauro Carvalho Chehab 832da298c6dSHans Verkuil static int tvp5150_fill_fmt(struct v4l2_subdev *sd, 833da298c6dSHans Verkuil struct v4l2_subdev_pad_config *cfg, 834da298c6dSHans Verkuil struct v4l2_subdev_format *format) 835cb7a01acSMauro Carvalho Chehab { 836da298c6dSHans Verkuil struct v4l2_mbus_framefmt *f; 837cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 838cb7a01acSMauro Carvalho Chehab 839da298c6dSHans Verkuil if (!format || format->pad) 840cb7a01acSMauro Carvalho Chehab return -EINVAL; 841cb7a01acSMauro Carvalho Chehab 842da298c6dSHans Verkuil f = &format->format; 843da298c6dSHans Verkuil 844cb7a01acSMauro Carvalho Chehab tvp5150_reset(sd, 0); 845cb7a01acSMauro Carvalho Chehab 846cb7a01acSMauro Carvalho Chehab f->width = decoder->rect.width; 847cb7a01acSMauro Carvalho Chehab f->height = decoder->rect.height; 848cb7a01acSMauro Carvalho Chehab 849f5fe58fdSBoris BREZILLON f->code = MEDIA_BUS_FMT_UYVY8_2X8; 850cb7a01acSMauro Carvalho Chehab f->field = V4L2_FIELD_SEQ_TB; 851cb7a01acSMauro Carvalho Chehab f->colorspace = V4L2_COLORSPACE_SMPTE170M; 852cb7a01acSMauro Carvalho Chehab 853cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width, 854cb7a01acSMauro Carvalho Chehab f->height); 855cb7a01acSMauro Carvalho Chehab return 0; 856cb7a01acSMauro Carvalho Chehab } 857cb7a01acSMauro Carvalho Chehab 8584f996594SHans Verkuil static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) 859cb7a01acSMauro Carvalho Chehab { 860cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect = a->c; 861cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 862cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 863f90580caSRicardo Ribalda unsigned int hmax; 864cb7a01acSMauro Carvalho Chehab 865cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", 866cb7a01acSMauro Carvalho Chehab __func__, rect.left, rect.top, rect.width, rect.height); 867cb7a01acSMauro Carvalho Chehab 868cb7a01acSMauro Carvalho Chehab if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 869cb7a01acSMauro Carvalho Chehab return -EINVAL; 870cb7a01acSMauro Carvalho Chehab 871cb7a01acSMauro Carvalho Chehab /* tvp5150 has some special limits */ 872cb7a01acSMauro Carvalho Chehab rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); 873f90580caSRicardo Ribalda rect.width = clamp_t(unsigned int, rect.width, 874cb7a01acSMauro Carvalho Chehab TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, 875cb7a01acSMauro Carvalho Chehab TVP5150_H_MAX - rect.left); 876cb7a01acSMauro Carvalho Chehab rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); 877cb7a01acSMauro Carvalho Chehab 878cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 879cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 880cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 881cb7a01acSMauro Carvalho Chehab else 882cb7a01acSMauro Carvalho Chehab std = decoder->norm; 883cb7a01acSMauro Carvalho Chehab 884cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 885cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_525_60; 886cb7a01acSMauro Carvalho Chehab else 887cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_OTHERS; 888cb7a01acSMauro Carvalho Chehab 889f90580caSRicardo Ribalda rect.height = clamp_t(unsigned int, rect.height, 890cb7a01acSMauro Carvalho Chehab hmax - TVP5150_MAX_CROP_TOP - rect.top, 891cb7a01acSMauro Carvalho Chehab hmax - rect.top); 892cb7a01acSMauro Carvalho Chehab 893cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); 894cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 895cb7a01acSMauro Carvalho Chehab rect.top + rect.height - hmax); 896cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB, 897cb7a01acSMauro Carvalho Chehab rect.left >> TVP5150_CROP_SHIFT); 898cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB, 899cb7a01acSMauro Carvalho Chehab rect.left | (1 << TVP5150_CROP_SHIFT)); 900cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB, 901cb7a01acSMauro Carvalho Chehab (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> 902cb7a01acSMauro Carvalho Chehab TVP5150_CROP_SHIFT); 903cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB, 904cb7a01acSMauro Carvalho Chehab rect.left + rect.width - TVP5150_MAX_CROP_LEFT); 905cb7a01acSMauro Carvalho Chehab 906cb7a01acSMauro Carvalho Chehab decoder->rect = rect; 907cb7a01acSMauro Carvalho Chehab 908cb7a01acSMauro Carvalho Chehab return 0; 909cb7a01acSMauro Carvalho Chehab } 910cb7a01acSMauro Carvalho Chehab 911cb7a01acSMauro Carvalho Chehab static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 912cb7a01acSMauro Carvalho Chehab { 91312bd10c7SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 914cb7a01acSMauro Carvalho Chehab 915cb7a01acSMauro Carvalho Chehab a->c = decoder->rect; 916cb7a01acSMauro Carvalho Chehab a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 917cb7a01acSMauro Carvalho Chehab 918cb7a01acSMauro Carvalho Chehab return 0; 919cb7a01acSMauro Carvalho Chehab } 920cb7a01acSMauro Carvalho Chehab 921cb7a01acSMauro Carvalho Chehab static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) 922cb7a01acSMauro Carvalho Chehab { 92312bd10c7SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 924cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 925cb7a01acSMauro Carvalho Chehab 926cb7a01acSMauro Carvalho Chehab if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 927cb7a01acSMauro Carvalho Chehab return -EINVAL; 928cb7a01acSMauro Carvalho Chehab 929cb7a01acSMauro Carvalho Chehab a->bounds.left = 0; 930cb7a01acSMauro Carvalho Chehab a->bounds.top = 0; 931cb7a01acSMauro Carvalho Chehab a->bounds.width = TVP5150_H_MAX; 932cb7a01acSMauro Carvalho Chehab 933cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 934cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 935cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 936cb7a01acSMauro Carvalho Chehab else 937cb7a01acSMauro Carvalho Chehab std = decoder->norm; 938cb7a01acSMauro Carvalho Chehab 939cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 940cb7a01acSMauro Carvalho Chehab a->bounds.height = TVP5150_V_MAX_525_60; 941cb7a01acSMauro Carvalho Chehab else 942cb7a01acSMauro Carvalho Chehab a->bounds.height = TVP5150_V_MAX_OTHERS; 943cb7a01acSMauro Carvalho Chehab 944cb7a01acSMauro Carvalho Chehab a->defrect = a->bounds; 945cb7a01acSMauro Carvalho Chehab a->pixelaspect.numerator = 1; 946cb7a01acSMauro Carvalho Chehab a->pixelaspect.denominator = 1; 947cb7a01acSMauro Carvalho Chehab 948cb7a01acSMauro Carvalho Chehab return 0; 949cb7a01acSMauro Carvalho Chehab } 950cb7a01acSMauro Carvalho Chehab 951cb7a01acSMauro Carvalho Chehab /**************************************************************************** 952cb7a01acSMauro Carvalho Chehab I2C Command 953cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 954cb7a01acSMauro Carvalho Chehab 955cb7a01acSMauro Carvalho Chehab static int tvp5150_s_routing(struct v4l2_subdev *sd, 956cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 957cb7a01acSMauro Carvalho Chehab { 958cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 959cb7a01acSMauro Carvalho Chehab 960cb7a01acSMauro Carvalho Chehab decoder->input = input; 961cb7a01acSMauro Carvalho Chehab decoder->output = output; 962cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 963cb7a01acSMauro Carvalho Chehab return 0; 964cb7a01acSMauro Carvalho Chehab } 965cb7a01acSMauro Carvalho Chehab 966cb7a01acSMauro Carvalho Chehab static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) 967cb7a01acSMauro Carvalho Chehab { 968cb7a01acSMauro Carvalho Chehab /* this is for capturing 36 raw vbi lines 969cb7a01acSMauro Carvalho Chehab if there's a way to cut off the beginning 2 vbi lines 970cb7a01acSMauro Carvalho Chehab with the tvp5150 then the vbi line count could be lowered 971cb7a01acSMauro Carvalho Chehab to 17 lines/field again, although I couldn't find a register 972cb7a01acSMauro Carvalho Chehab which could do that cropping */ 973cb7a01acSMauro Carvalho Chehab if (fmt->sample_format == V4L2_PIX_FMT_GREY) 974cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70); 975cb7a01acSMauro Carvalho Chehab if (fmt->count[0] == 18 && fmt->count[1] == 18) { 976cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00); 977cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01); 978cb7a01acSMauro Carvalho Chehab } 979cb7a01acSMauro Carvalho Chehab return 0; 980cb7a01acSMauro Carvalho Chehab } 981cb7a01acSMauro Carvalho Chehab 982cb7a01acSMauro Carvalho Chehab static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 983cb7a01acSMauro Carvalho Chehab { 984cb7a01acSMauro Carvalho Chehab int i; 985cb7a01acSMauro Carvalho Chehab 986cb7a01acSMauro Carvalho Chehab if (svbi->service_set != 0) { 987cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 988cb7a01acSMauro Carvalho Chehab svbi->service_lines[1][i] = 0; 989cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 990cb7a01acSMauro Carvalho Chehab tvp5150_set_vbi(sd, vbi_ram_default, 991cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i], 0xf0, i, 3); 992cb7a01acSMauro Carvalho Chehab } 993cb7a01acSMauro Carvalho Chehab /* Enables FIFO */ 994cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1); 995cb7a01acSMauro Carvalho Chehab } else { 996cb7a01acSMauro Carvalho Chehab /* Disables FIFO*/ 997cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0); 998cb7a01acSMauro Carvalho Chehab 999cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 1000cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0); 1001cb7a01acSMauro Carvalho Chehab 1002cb7a01acSMauro Carvalho Chehab /* Disable Line modes */ 1003cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 1004cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, i, 0xff); 1005cb7a01acSMauro Carvalho Chehab } 1006cb7a01acSMauro Carvalho Chehab return 0; 1007cb7a01acSMauro Carvalho Chehab } 1008cb7a01acSMauro Carvalho Chehab 1009cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1010cb7a01acSMauro Carvalho Chehab { 1011cb7a01acSMauro Carvalho Chehab int i, mask = 0; 1012cb7a01acSMauro Carvalho Chehab 101330634e8eSHans Verkuil memset(svbi->service_lines, 0, sizeof(svbi->service_lines)); 1014cb7a01acSMauro Carvalho Chehab 1015cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1016cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 1017cb7a01acSMauro Carvalho Chehab tvp5150_get_vbi(sd, vbi_ram_default, i); 1018cb7a01acSMauro Carvalho Chehab mask |= svbi->service_lines[0][i]; 1019cb7a01acSMauro Carvalho Chehab } 1020cb7a01acSMauro Carvalho Chehab svbi->service_set = mask; 1021cb7a01acSMauro Carvalho Chehab return 0; 1022cb7a01acSMauro Carvalho Chehab } 1023cb7a01acSMauro Carvalho Chehab 1024cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1025cb7a01acSMauro Carvalho Chehab static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 1026cb7a01acSMauro Carvalho Chehab { 1027cb7a01acSMauro Carvalho Chehab int res; 1028cb7a01acSMauro Carvalho Chehab 1029cb7a01acSMauro Carvalho Chehab res = tvp5150_read(sd, reg->reg & 0xff); 1030cb7a01acSMauro Carvalho Chehab if (res < 0) { 1031cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "%s: failed with error = %d\n", __func__, res); 1032cb7a01acSMauro Carvalho Chehab return res; 1033cb7a01acSMauro Carvalho Chehab } 1034cb7a01acSMauro Carvalho Chehab 1035cb7a01acSMauro Carvalho Chehab reg->val = res; 1036cb7a01acSMauro Carvalho Chehab reg->size = 1; 1037cb7a01acSMauro Carvalho Chehab return 0; 1038cb7a01acSMauro Carvalho Chehab } 1039cb7a01acSMauro Carvalho Chehab 1040977ba3b1SHans Verkuil static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 1041cb7a01acSMauro Carvalho Chehab { 1042cb7a01acSMauro Carvalho Chehab tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff); 1043cb7a01acSMauro Carvalho Chehab return 0; 1044cb7a01acSMauro Carvalho Chehab } 1045cb7a01acSMauro Carvalho Chehab #endif 1046cb7a01acSMauro Carvalho Chehab 1047cb7a01acSMauro Carvalho Chehab static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) 1048cb7a01acSMauro Carvalho Chehab { 1049cb7a01acSMauro Carvalho Chehab int status = tvp5150_read(sd, 0x88); 1050cb7a01acSMauro Carvalho Chehab 1051cb7a01acSMauro Carvalho Chehab vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0; 1052cb7a01acSMauro Carvalho Chehab return 0; 1053cb7a01acSMauro Carvalho Chehab } 1054cb7a01acSMauro Carvalho Chehab 1055cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1056cb7a01acSMauro Carvalho Chehab 1057cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { 1058cb7a01acSMauro Carvalho Chehab .s_ctrl = tvp5150_s_ctrl, 1059cb7a01acSMauro Carvalho Chehab }; 1060cb7a01acSMauro Carvalho Chehab 1061cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tvp5150_core_ops = { 1062cb7a01acSMauro Carvalho Chehab .log_status = tvp5150_log_status, 1063cb7a01acSMauro Carvalho Chehab .reset = tvp5150_reset, 1064cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1065cb7a01acSMauro Carvalho Chehab .g_register = tvp5150_g_register, 1066cb7a01acSMauro Carvalho Chehab .s_register = tvp5150_s_register, 1067cb7a01acSMauro Carvalho Chehab #endif 1068cb7a01acSMauro Carvalho Chehab }; 1069cb7a01acSMauro Carvalho Chehab 1070cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { 1071cb7a01acSMauro Carvalho Chehab .g_tuner = tvp5150_g_tuner, 1072cb7a01acSMauro Carvalho Chehab }; 1073cb7a01acSMauro Carvalho Chehab 1074cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tvp5150_video_ops = { 10758774bed9SLaurent Pinchart .s_std = tvp5150_s_std, 1076cb7a01acSMauro Carvalho Chehab .s_routing = tvp5150_s_routing, 1077cb7a01acSMauro Carvalho Chehab .s_crop = tvp5150_s_crop, 1078cb7a01acSMauro Carvalho Chehab .g_crop = tvp5150_g_crop, 1079cb7a01acSMauro Carvalho Chehab .cropcap = tvp5150_cropcap, 1080cb7a01acSMauro Carvalho Chehab }; 1081cb7a01acSMauro Carvalho Chehab 1082cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { 1083cb7a01acSMauro Carvalho Chehab .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap, 1084cb7a01acSMauro Carvalho Chehab .g_sliced_fmt = tvp5150_g_sliced_fmt, 1085cb7a01acSMauro Carvalho Chehab .s_sliced_fmt = tvp5150_s_sliced_fmt, 1086cb7a01acSMauro Carvalho Chehab .s_raw_fmt = tvp5150_s_raw_fmt, 1087cb7a01acSMauro Carvalho Chehab }; 1088cb7a01acSMauro Carvalho Chehab 1089ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { 1090ebcff5fcSHans Verkuil .enum_mbus_code = tvp5150_enum_mbus_code, 1091da298c6dSHans Verkuil .set_fmt = tvp5150_fill_fmt, 1092da298c6dSHans Verkuil .get_fmt = tvp5150_fill_fmt, 1093ebcff5fcSHans Verkuil }; 1094ebcff5fcSHans Verkuil 1095cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvp5150_ops = { 1096cb7a01acSMauro Carvalho Chehab .core = &tvp5150_core_ops, 1097cb7a01acSMauro Carvalho Chehab .tuner = &tvp5150_tuner_ops, 1098cb7a01acSMauro Carvalho Chehab .video = &tvp5150_video_ops, 1099cb7a01acSMauro Carvalho Chehab .vbi = &tvp5150_vbi_ops, 1100ebcff5fcSHans Verkuil .pad = &tvp5150_pad_ops, 1101cb7a01acSMauro Carvalho Chehab }; 1102cb7a01acSMauro Carvalho Chehab 1103cb7a01acSMauro Carvalho Chehab 1104cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1105cb7a01acSMauro Carvalho Chehab I2C Client & Driver 1106cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1107cb7a01acSMauro Carvalho Chehab 11087871597aSLaurent Pinchart static int tvp5150_detect_version(struct tvp5150 *core) 11097871597aSLaurent Pinchart { 11107871597aSLaurent Pinchart struct v4l2_subdev *sd = &core->sd; 11117871597aSLaurent Pinchart struct i2c_client *c = v4l2_get_subdevdata(sd); 11127871597aSLaurent Pinchart unsigned int i; 11137871597aSLaurent Pinchart u16 dev_id; 11147871597aSLaurent Pinchart u16 rom_ver; 11157871597aSLaurent Pinchart u8 regs[4]; 11167871597aSLaurent Pinchart int res; 11177871597aSLaurent Pinchart 11187871597aSLaurent Pinchart /* 11197871597aSLaurent Pinchart * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID, 11207871597aSLaurent Pinchart * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 11217871597aSLaurent Pinchart */ 11227871597aSLaurent Pinchart for (i = 0; i < 4; i++) { 11237871597aSLaurent Pinchart res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i); 11247871597aSLaurent Pinchart if (res < 0) 11257871597aSLaurent Pinchart return res; 11267871597aSLaurent Pinchart regs[i] = res; 11277871597aSLaurent Pinchart } 11287871597aSLaurent Pinchart 11297871597aSLaurent Pinchart dev_id = (regs[0] << 8) | regs[1]; 11307871597aSLaurent Pinchart rom_ver = (regs[2] << 8) | regs[3]; 11317871597aSLaurent Pinchart 11327871597aSLaurent Pinchart v4l2_info(sd, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n", 11337871597aSLaurent Pinchart dev_id, regs[2], regs[3], c->addr << 1, c->adapter->name); 11347871597aSLaurent Pinchart 11357871597aSLaurent Pinchart if (dev_id == 0x5150 && rom_ver == 0x0321) { /* TVP51510A */ 11367871597aSLaurent Pinchart v4l2_info(sd, "tvp5150a detected.\n"); 11377871597aSLaurent Pinchart } else if (dev_id == 0x5150 && rom_ver == 0x0400) { /* TVP5150AM1 */ 11387871597aSLaurent Pinchart v4l2_info(sd, "tvp5150am1 detected.\n"); 11397871597aSLaurent Pinchart 11407871597aSLaurent Pinchart /* ITU-T BT.656.4 timing */ 11417871597aSLaurent Pinchart tvp5150_write(sd, TVP5150_REV_SELECT, 0); 114205676b3eSLaurent Pinchart } else if (dev_id == 0x5151 && rom_ver == 0x0100) { /* TVP5151 */ 114305676b3eSLaurent Pinchart v4l2_info(sd, "tvp5151 detected.\n"); 11447871597aSLaurent Pinchart } else { 11457871597aSLaurent Pinchart v4l2_info(sd, "*** unknown tvp%04x chip detected.\n", dev_id); 11467871597aSLaurent Pinchart } 11477871597aSLaurent Pinchart 11487871597aSLaurent Pinchart return 0; 11497871597aSLaurent Pinchart } 11507871597aSLaurent Pinchart 1151cb7a01acSMauro Carvalho Chehab static int tvp5150_probe(struct i2c_client *c, 1152cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1153cb7a01acSMauro Carvalho Chehab { 1154cb7a01acSMauro Carvalho Chehab struct tvp5150 *core; 1155cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 11567871597aSLaurent Pinchart int res; 1157cb7a01acSMauro Carvalho Chehab 1158cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1159cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(c->adapter, 1160cb7a01acSMauro Carvalho Chehab I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 1161cb7a01acSMauro Carvalho Chehab return -EIO; 1162cb7a01acSMauro Carvalho Chehab 1163c02b211dSLaurent Pinchart core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL); 1164c02b211dSLaurent Pinchart if (!core) 1165cb7a01acSMauro Carvalho Chehab return -ENOMEM; 1166cb7a01acSMauro Carvalho Chehab sd = &core->sd; 1167cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); 1168cb7a01acSMauro Carvalho Chehab 11697871597aSLaurent Pinchart res = tvp5150_detect_version(core); 1170cb7a01acSMauro Carvalho Chehab if (res < 0) 1171c02b211dSLaurent Pinchart return res; 1172cb7a01acSMauro Carvalho Chehab 1173cb7a01acSMauro Carvalho Chehab core->norm = V4L2_STD_ALL; /* Default is autodetect */ 1174cb7a01acSMauro Carvalho Chehab core->input = TVP5150_COMPOSITE1; 1175cb7a01acSMauro Carvalho Chehab core->enable = 1; 1176cb7a01acSMauro Carvalho Chehab 1177cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_init(&core->hdl, 4); 1178cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1179cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 1180cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1181cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 255, 1, 128); 1182cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1183cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, 0, 255, 1, 128); 1184cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1185cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, -128, 127, 1, 0); 1186cb7a01acSMauro Carvalho Chehab sd->ctrl_handler = &core->hdl; 1187cb7a01acSMauro Carvalho Chehab if (core->hdl.error) { 1188cb7a01acSMauro Carvalho Chehab res = core->hdl.error; 1189c7d97499SJavier Martinez Canillas goto err; 1190cb7a01acSMauro Carvalho Chehab } 1191cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&core->hdl); 1192cb7a01acSMauro Carvalho Chehab 1193cb7a01acSMauro Carvalho Chehab /* Default is no cropping */ 1194cb7a01acSMauro Carvalho Chehab core->rect.top = 0; 1195cb7a01acSMauro Carvalho Chehab if (tvp5150_read_std(sd) & V4L2_STD_525_60) 1196cb7a01acSMauro Carvalho Chehab core->rect.height = TVP5150_V_MAX_525_60; 1197cb7a01acSMauro Carvalho Chehab else 1198cb7a01acSMauro Carvalho Chehab core->rect.height = TVP5150_V_MAX_OTHERS; 1199cb7a01acSMauro Carvalho Chehab core->rect.left = 0; 1200cb7a01acSMauro Carvalho Chehab core->rect.width = TVP5150_H_MAX; 1201cb7a01acSMauro Carvalho Chehab 1202c7d97499SJavier Martinez Canillas res = v4l2_async_register_subdev(sd); 1203c7d97499SJavier Martinez Canillas if (res < 0) 1204c7d97499SJavier Martinez Canillas goto err; 1205c7d97499SJavier Martinez Canillas 1206cb7a01acSMauro Carvalho Chehab if (debug > 1) 1207cb7a01acSMauro Carvalho Chehab tvp5150_log_status(sd); 1208cb7a01acSMauro Carvalho Chehab return 0; 1209c7d97499SJavier Martinez Canillas 1210c7d97499SJavier Martinez Canillas err: 1211c7d97499SJavier Martinez Canillas v4l2_ctrl_handler_free(&core->hdl); 1212c7d97499SJavier Martinez Canillas return res; 1213cb7a01acSMauro Carvalho Chehab } 1214cb7a01acSMauro Carvalho Chehab 1215cb7a01acSMauro Carvalho Chehab static int tvp5150_remove(struct i2c_client *c) 1216cb7a01acSMauro Carvalho Chehab { 1217cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(c); 1218cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1219cb7a01acSMauro Carvalho Chehab 1220cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, 1221cb7a01acSMauro Carvalho Chehab "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", 1222cb7a01acSMauro Carvalho Chehab c->addr << 1); 1223cb7a01acSMauro Carvalho Chehab 1224c7d97499SJavier Martinez Canillas v4l2_async_unregister_subdev(sd); 1225cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&decoder->hdl); 1226cb7a01acSMauro Carvalho Chehab return 0; 1227cb7a01acSMauro Carvalho Chehab } 1228cb7a01acSMauro Carvalho Chehab 1229cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1230cb7a01acSMauro Carvalho Chehab 1231cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvp5150_id[] = { 1232cb7a01acSMauro Carvalho Chehab { "tvp5150", 0 }, 1233cb7a01acSMauro Carvalho Chehab { } 1234cb7a01acSMauro Carvalho Chehab }; 1235cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvp5150_id); 1236cb7a01acSMauro Carvalho Chehab 1237cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvp5150_driver = { 1238cb7a01acSMauro Carvalho Chehab .driver = { 1239cb7a01acSMauro Carvalho Chehab .name = "tvp5150", 1240cb7a01acSMauro Carvalho Chehab }, 1241cb7a01acSMauro Carvalho Chehab .probe = tvp5150_probe, 1242cb7a01acSMauro Carvalho Chehab .remove = tvp5150_remove, 1243cb7a01acSMauro Carvalho Chehab .id_table = tvp5150_id, 1244cb7a01acSMauro Carvalho Chehab }; 1245cb7a01acSMauro Carvalho Chehab 1246cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvp5150_driver); 1247