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