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