1459ee17cSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0 2459ee17cSMauro Carvalho Chehab // 3459ee17cSMauro Carvalho Chehab // tvp5150 - Texas Instruments TVP5150A/AM1 and TVP5151 video decoder driver 4459ee17cSMauro Carvalho Chehab // 532590819SMauro Carvalho Chehab // Copyright (c) 2005,2006 Mauro Carvalho Chehab <mchehab@kernel.org> 6cb7a01acSMauro Carvalho Chehab 7b802fb99SJavier Martinez Canillas #include <dt-bindings/media/tvp5150.h> 8cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 9cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 10cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 11cb7a01acSMauro Carvalho Chehab #include <linux/delay.h> 1209aa2609SJavier Martinez Canillas #include <linux/gpio/consumer.h> 138e4c97e0SPhilipp Zabel #include <linux/interrupt.h> 14cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 15859969b3SSakari Ailus #include <linux/of_graph.h> 1628b9e227SPhilipp Zabel #include <linux/regmap.h> 17c7d97499SJavier Martinez Canillas #include <media/v4l2-async.h> 18cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 19cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 20859969b3SSakari Ailus #include <media/v4l2-fwnode.h> 2155606310SMauro Carvalho Chehab #include <media/v4l2-mc.h> 22cb7a01acSMauro Carvalho Chehab 23cb7a01acSMauro Carvalho Chehab #include "tvp5150_reg.h" 24cb7a01acSMauro Carvalho Chehab 25785a3de1SPhilipp Zabel #define TVP5150_H_MAX 720U 26785a3de1SPhilipp Zabel #define TVP5150_V_MAX_525_60 480U 27785a3de1SPhilipp Zabel #define TVP5150_V_MAX_OTHERS 576U 28cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_LEFT 511 29cb7a01acSMauro Carvalho Chehab #define TVP5150_MAX_CROP_TOP 127 30cb7a01acSMauro Carvalho Chehab #define TVP5150_CROP_SHIFT 2 315cb82940SMarco Felsch #define TVP5150_MBUS_FMT MEDIA_BUS_FMT_UYVY8_2X8 325cb82940SMarco Felsch #define TVP5150_FIELD V4L2_FIELD_ALTERNATE 335cb82940SMarco Felsch #define TVP5150_COLORSPACE V4L2_COLORSPACE_SMPTE170M 34cb7a01acSMauro Carvalho Chehab 35c43875f6SMauro Carvalho Chehab MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver"); 36cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab"); 37459ee17cSMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 38cb7a01acSMauro Carvalho Chehab 39cb7a01acSMauro Carvalho Chehab 40cb7a01acSMauro Carvalho Chehab static int debug; 412a0489d3SPhilipp Zabel module_param(debug, int, 0644); 42cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-2)"); 43cb7a01acSMauro Carvalho Chehab 44ad0e3744SMauro Carvalho Chehab #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg) 45ad0e3744SMauro Carvalho Chehab 46bc322c0dSMauro Carvalho Chehab enum tvp5150_pads { 47bc322c0dSMauro Carvalho Chehab TVP5150_PAD_IF_INPUT, 48bc322c0dSMauro Carvalho Chehab TVP5150_PAD_VID_OUT, 49bc322c0dSMauro Carvalho Chehab TVP5150_NUM_PADS 50bc322c0dSMauro Carvalho Chehab }; 51bc322c0dSMauro Carvalho Chehab 52cb7a01acSMauro Carvalho Chehab struct tvp5150 { 53cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 5455606310SMauro Carvalho Chehab #ifdef CONFIG_MEDIA_CONTROLLER 55bc322c0dSMauro Carvalho Chehab struct media_pad pads[TVP5150_NUM_PADS]; 56f7b4b54eSJavier Martinez Canillas struct media_entity input_ent[TVP5150_INPUT_NUM]; 57f7b4b54eSJavier Martinez Canillas struct media_pad input_pad[TVP5150_INPUT_NUM]; 5855606310SMauro Carvalho Chehab #endif 59cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler hdl; 60cb7a01acSMauro Carvalho Chehab struct v4l2_rect rect; 6128b9e227SPhilipp Zabel struct regmap *regmap; 628e4c97e0SPhilipp Zabel int irq; 63cb7a01acSMauro Carvalho Chehab 64cb7a01acSMauro Carvalho Chehab v4l2_std_id norm; /* Current set standard */ 65b440b733SPhilipp Zabel v4l2_std_id detected_norm; 66cb7a01acSMauro Carvalho Chehab u32 input; 67cb7a01acSMauro Carvalho Chehab u32 output; 6862a764e1SPhilipp Zabel u32 oe; 69cb7a01acSMauro Carvalho Chehab int enable; 708e4c97e0SPhilipp Zabel bool lock; 71a2e5f1b3SJavier Martinez Canillas 7282275133SJavier Martinez Canillas u16 dev_id; 7382275133SJavier Martinez Canillas u16 rom_ver; 7482275133SJavier Martinez Canillas 75a2e5f1b3SJavier Martinez Canillas enum v4l2_mbus_type mbus_type; 76cb7a01acSMauro Carvalho Chehab }; 77cb7a01acSMauro Carvalho Chehab 78cb7a01acSMauro Carvalho Chehab static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) 79cb7a01acSMauro Carvalho Chehab { 80cb7a01acSMauro Carvalho Chehab return container_of(sd, struct tvp5150, sd); 81cb7a01acSMauro Carvalho Chehab } 82cb7a01acSMauro Carvalho Chehab 83cb7a01acSMauro Carvalho Chehab static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 84cb7a01acSMauro Carvalho Chehab { 85cb7a01acSMauro Carvalho Chehab return &container_of(ctrl->handler, struct tvp5150, hdl)->sd; 86cb7a01acSMauro Carvalho Chehab } 87cb7a01acSMauro Carvalho Chehab 88cb7a01acSMauro Carvalho Chehab static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) 89cb7a01acSMauro Carvalho Chehab { 9028b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 9128b9e227SPhilipp Zabel int ret, val; 92cb7a01acSMauro Carvalho Chehab 9328b9e227SPhilipp Zabel ret = regmap_read(decoder->regmap, addr, &val); 9428b9e227SPhilipp Zabel if (ret < 0) 9528b9e227SPhilipp Zabel return ret; 96cb7a01acSMauro Carvalho Chehab 9728b9e227SPhilipp Zabel return val; 98cb7a01acSMauro Carvalho Chehab } 99cb7a01acSMauro Carvalho Chehab 100cb7a01acSMauro Carvalho Chehab static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, 101cb7a01acSMauro Carvalho Chehab const u8 end, int max_line) 102cb7a01acSMauro Carvalho Chehab { 103e5134114SMauro Carvalho Chehab u8 buf[16]; 104e5134114SMauro Carvalho Chehab int i = 0, j, len; 105cb7a01acSMauro Carvalho Chehab 106e5134114SMauro Carvalho Chehab if (max_line > 16) { 107e5134114SMauro Carvalho Chehab dprintk0(sd->dev, "too much data to dump\n"); 108e5134114SMauro Carvalho Chehab return; 109cb7a01acSMauro Carvalho Chehab } 110cb7a01acSMauro Carvalho Chehab 111e5134114SMauro Carvalho Chehab for (i = init; i < end; i += max_line) { 112e5134114SMauro Carvalho Chehab len = (end - i > max_line) ? max_line : end - i; 113e5134114SMauro Carvalho Chehab 114e5134114SMauro Carvalho Chehab for (j = 0; j < len; j++) 115e5134114SMauro Carvalho Chehab buf[j] = tvp5150_read(sd, i + j); 116e5134114SMauro Carvalho Chehab 117e5134114SMauro Carvalho Chehab dprintk0(sd->dev, "%s reg %02x = %*ph\n", s, i, len, buf); 118cb7a01acSMauro Carvalho Chehab } 119cb7a01acSMauro Carvalho Chehab } 120cb7a01acSMauro Carvalho Chehab 121cb7a01acSMauro Carvalho Chehab static int tvp5150_log_status(struct v4l2_subdev *sd) 122cb7a01acSMauro Carvalho Chehab { 123ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Video input source selection #1 = 0x%02x\n", 124cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); 125ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Analog channel controls = 0x%02x\n", 126cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); 127ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Operation mode controls = 0x%02x\n", 128cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_OP_MODE_CTL)); 129ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Miscellaneous controls = 0x%02x\n", 130cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MISC_CTL)); 131ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Autoswitch mask= 0x%02x\n", 132cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_AUTOSW_MSK)); 133ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Color killer threshold control = 0x%02x\n", 134cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); 135ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", 136cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), 137cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), 138cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); 139ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Brightness control = 0x%02x\n", 140cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_BRIGHT_CTL)); 141ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Color saturation control = 0x%02x\n", 142cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_SATURATION_CTL)); 143ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Hue control = 0x%02x\n", 144cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HUE_CTL)); 145ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Contrast control = 0x%02x\n", 146cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONTRAST_CTL)); 147ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Outputs and data rates select = 0x%02x\n", 148cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); 149ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Configuration shared pins = 0x%02x\n", 150cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); 151ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Active video cropping start = 0x%02x%02x\n", 152cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), 153cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); 154ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Active video cropping stop = 0x%02x%02x\n", 155cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), 156cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); 157ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Genlock/RTC = 0x%02x\n", 158cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_GENLOCK)); 159ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Horizontal sync start = 0x%02x\n", 160cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); 161ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical blanking start = 0x%02x\n", 162cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); 163ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical blanking stop = 0x%02x\n", 164cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); 165ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", 166cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), 167cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); 168ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt reset register B = 0x%02x\n", 169cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); 170ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt enable register B = 0x%02x\n", 171cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); 172ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt configuration register B = 0x%02x\n", 173cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); 174ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Video standard = 0x%02x\n", 175cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VIDEO_STD)); 176ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", 177cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CB_GAIN_FACT), 178cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); 179ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Macrovision on counter = 0x%02x\n", 180cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); 181ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Macrovision off counter = 0x%02x\n", 182cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); 183ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", 184cb7a01acSMauro Carvalho Chehab (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); 185ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Device ID = %02x%02x\n", 186cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_MSB_DEV_ID), 187cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LSB_DEV_ID)); 188ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: ROM version = (hex) %02x.%02x\n", 189cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), 190cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); 191ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Vertical line count = 0x%02x%02x\n", 192cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), 193cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); 194ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt status register B = 0x%02x\n", 195cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); 196ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt active register B = 0x%02x\n", 197cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); 198ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", 199cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_1), 200cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_2), 201cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_3), 202cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_4), 203cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_STATUS_REG_5)); 204cb7a01acSMauro Carvalho Chehab 205cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, 206cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL1_END, 8); 207cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, 208cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL2_END, 8); 209cb7a01acSMauro Carvalho Chehab 210ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Teletext filter enable = 0x%02x\n", 211cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); 212ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt status register A = 0x%02x\n", 213cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); 214ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt enable register A = 0x%02x\n", 215cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); 216ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Interrupt configuration = 0x%02x\n", 217cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_INT_CONF)); 218ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: VDP status register = 0x%02x\n", 219cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); 220ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO word count = 0x%02x\n", 221cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); 222ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO interrupt threshold = 0x%02x\n", 223cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); 224ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO reset = 0x%02x\n", 225cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_RESET)); 226ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Line number interrupt = 0x%02x\n", 227cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); 228ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Pixel alignment register = 0x%02x%02x\n", 229cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), 230cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); 231ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: FIFO output control = 0x%02x\n", 232cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); 233ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Full field enable = 0x%02x\n", 234cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); 235ad0e3744SMauro Carvalho Chehab dprintk0(sd->dev, "tvp5150: Full field mode register = 0x%02x\n", 236cb7a01acSMauro Carvalho Chehab tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); 237cb7a01acSMauro Carvalho Chehab 238cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI, 239cb7a01acSMauro Carvalho Chehab TVP5150_CC_DATA_END, 8); 240cb7a01acSMauro Carvalho Chehab 241cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "WSS data", TVP5150_WSS_DATA_INI, 242cb7a01acSMauro Carvalho Chehab TVP5150_WSS_DATA_END, 8); 243cb7a01acSMauro Carvalho Chehab 244cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VPS data", TVP5150_VPS_DATA_INI, 245cb7a01acSMauro Carvalho Chehab TVP5150_VPS_DATA_END, 8); 246cb7a01acSMauro Carvalho Chehab 247cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "VITC data", TVP5150_VITC_DATA_INI, 248cb7a01acSMauro Carvalho Chehab TVP5150_VITC_DATA_END, 10); 249cb7a01acSMauro Carvalho Chehab 250cb7a01acSMauro Carvalho Chehab dump_reg_range(sd, "Line mode", TVP5150_LINE_MODE_INI, 251cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_END, 8); 252cb7a01acSMauro Carvalho Chehab return 0; 253cb7a01acSMauro Carvalho Chehab } 254cb7a01acSMauro Carvalho Chehab 255cb7a01acSMauro Carvalho Chehab /**************************************************************************** 256cb7a01acSMauro Carvalho Chehab Basic functions 257cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 258cb7a01acSMauro Carvalho Chehab 2596e98bee2SLaurent Pinchart static void tvp5150_selmux(struct v4l2_subdev *sd) 260cb7a01acSMauro Carvalho Chehab { 261cb7a01acSMauro Carvalho Chehab int opmode = 0; 262cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 2638a7441baSMarco Felsch unsigned int mask, val; 264cb7a01acSMauro Carvalho Chehab int input = 0; 265cb7a01acSMauro Carvalho Chehab 266c43875f6SMauro Carvalho Chehab /* Only tvp5150am1 and tvp5151 have signal generator support */ 267c43875f6SMauro Carvalho Chehab if ((decoder->dev_id == 0x5150 && decoder->rom_ver == 0x0400) || 268c43875f6SMauro Carvalho Chehab (decoder->dev_id == 0x5151 && decoder->rom_ver == 0x0100)) { 269c43875f6SMauro Carvalho Chehab if (!decoder->enable) 270cb7a01acSMauro Carvalho Chehab input = 8; 271c43875f6SMauro Carvalho Chehab } 272cb7a01acSMauro Carvalho Chehab 273cb7a01acSMauro Carvalho Chehab switch (decoder->input) { 274cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE1: 275cb7a01acSMauro Carvalho Chehab input |= 2; 276cb7a01acSMauro Carvalho Chehab /* fall through */ 277cb7a01acSMauro Carvalho Chehab case TVP5150_COMPOSITE0: 278cb7a01acSMauro Carvalho Chehab break; 279cb7a01acSMauro Carvalho Chehab case TVP5150_SVIDEO: 280cb7a01acSMauro Carvalho Chehab default: 281cb7a01acSMauro Carvalho Chehab input |= 1; 282cb7a01acSMauro Carvalho Chehab break; 283cb7a01acSMauro Carvalho Chehab } 284cb7a01acSMauro Carvalho Chehab 285257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n", 286cb7a01acSMauro Carvalho Chehab decoder->input, decoder->output, 287cb7a01acSMauro Carvalho Chehab input, opmode); 288cb7a01acSMauro Carvalho Chehab 28928b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode); 29028b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input); 291cb7a01acSMauro Carvalho Chehab 292b4b2de38SLaurent Pinchart /* 293b4b2de38SLaurent Pinchart * Setup the FID/GLCO/VLK/HVLK and INTREQ/GPCL/VBLK output signals. For 294b4b2de38SLaurent Pinchart * S-Video we output the vertical lock (VLK) signal on FID/GLCO/VLK/HVLK 295b4b2de38SLaurent Pinchart * and set INTREQ/GPCL/VBLK to logic 0. For composite we output the 296b4b2de38SLaurent Pinchart * field indicator (FID) signal on FID/GLCO/VLK/HVLK and set 297b4b2de38SLaurent Pinchart * INTREQ/GPCL/VBLK to logic 1. 298cb7a01acSMauro Carvalho Chehab */ 2998a7441baSMarco Felsch mask = TVP5150_MISC_CTL_GPCL | TVP5150_MISC_CTL_HVLK; 300cb7a01acSMauro Carvalho Chehab if (decoder->input == TVP5150_SVIDEO) 3018a7441baSMarco Felsch val = TVP5150_MISC_CTL_HVLK; 302cb7a01acSMauro Carvalho Chehab else 3038a7441baSMarco Felsch val = TVP5150_MISC_CTL_GPCL; 3048a7441baSMarco Felsch regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val); 305cb7a01acSMauro Carvalho Chehab }; 306cb7a01acSMauro Carvalho Chehab 307cb7a01acSMauro Carvalho Chehab struct i2c_reg_value { 308cb7a01acSMauro Carvalho Chehab unsigned char reg; 309cb7a01acSMauro Carvalho Chehab unsigned char value; 310cb7a01acSMauro Carvalho Chehab }; 311cb7a01acSMauro Carvalho Chehab 312cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 313cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_default[] = { 314cb7a01acSMauro Carvalho Chehab { /* 0x00 */ 315cb7a01acSMauro Carvalho Chehab TVP5150_VD_IN_SRC_SEL_1, 0x00 316cb7a01acSMauro Carvalho Chehab }, 317cb7a01acSMauro Carvalho Chehab { /* 0x01 */ 318cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 319cb7a01acSMauro Carvalho Chehab }, 320cb7a01acSMauro Carvalho Chehab { /* 0x02 */ 321cb7a01acSMauro Carvalho Chehab TVP5150_OP_MODE_CTL, 0x00 322cb7a01acSMauro Carvalho Chehab }, 323cb7a01acSMauro Carvalho Chehab { /* 0x03 */ 324cb7a01acSMauro Carvalho Chehab TVP5150_MISC_CTL, 0x01 325cb7a01acSMauro Carvalho Chehab }, 326cb7a01acSMauro Carvalho Chehab { /* 0x06 */ 327cb7a01acSMauro Carvalho Chehab TVP5150_COLOR_KIL_THSH_CTL, 0x10 328cb7a01acSMauro Carvalho Chehab }, 329cb7a01acSMauro Carvalho Chehab { /* 0x07 */ 330cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_1, 0x60 331cb7a01acSMauro Carvalho Chehab }, 332cb7a01acSMauro Carvalho Chehab { /* 0x08 */ 333cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_2, 0x00 334cb7a01acSMauro Carvalho Chehab }, 335cb7a01acSMauro Carvalho Chehab { /* 0x09 */ 336cb7a01acSMauro Carvalho Chehab TVP5150_BRIGHT_CTL, 0x80 337cb7a01acSMauro Carvalho Chehab }, 338cb7a01acSMauro Carvalho Chehab { /* 0x0a */ 339cb7a01acSMauro Carvalho Chehab TVP5150_SATURATION_CTL, 0x80 340cb7a01acSMauro Carvalho Chehab }, 341cb7a01acSMauro Carvalho Chehab { /* 0x0b */ 342cb7a01acSMauro Carvalho Chehab TVP5150_HUE_CTL, 0x00 343cb7a01acSMauro Carvalho Chehab }, 344cb7a01acSMauro Carvalho Chehab { /* 0x0c */ 345cb7a01acSMauro Carvalho Chehab TVP5150_CONTRAST_CTL, 0x80 346cb7a01acSMauro Carvalho Chehab }, 347cb7a01acSMauro Carvalho Chehab { /* 0x0d */ 348cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 349cb7a01acSMauro Carvalho Chehab }, 350cb7a01acSMauro Carvalho Chehab { /* 0x0e */ 351cb7a01acSMauro Carvalho Chehab TVP5150_LUMA_PROC_CTL_3, 0x00 352cb7a01acSMauro Carvalho Chehab }, 353cb7a01acSMauro Carvalho Chehab { /* 0x0f */ 354cb7a01acSMauro Carvalho Chehab TVP5150_CONF_SHARED_PIN, 0x08 355cb7a01acSMauro Carvalho Chehab }, 356cb7a01acSMauro Carvalho Chehab { /* 0x11 */ 357cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_MSB, 0x00 358cb7a01acSMauro Carvalho Chehab }, 359cb7a01acSMauro Carvalho Chehab { /* 0x12 */ 360cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_ST_LSB, 0x00 361cb7a01acSMauro Carvalho Chehab }, 362cb7a01acSMauro Carvalho Chehab { /* 0x13 */ 363cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_MSB, 0x00 364cb7a01acSMauro Carvalho Chehab }, 365cb7a01acSMauro Carvalho Chehab { /* 0x14 */ 366cb7a01acSMauro Carvalho Chehab TVP5150_ACT_VD_CROP_STP_LSB, 0x00 367cb7a01acSMauro Carvalho Chehab }, 368cb7a01acSMauro Carvalho Chehab { /* 0x15 */ 369cb7a01acSMauro Carvalho Chehab TVP5150_GENLOCK, 0x01 370cb7a01acSMauro Carvalho Chehab }, 371cb7a01acSMauro Carvalho Chehab { /* 0x16 */ 372cb7a01acSMauro Carvalho Chehab TVP5150_HORIZ_SYNC_START, 0x80 373cb7a01acSMauro Carvalho Chehab }, 374cb7a01acSMauro Carvalho Chehab { /* 0x18 */ 375cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_START, 0x00 376cb7a01acSMauro Carvalho Chehab }, 377cb7a01acSMauro Carvalho Chehab { /* 0x19 */ 378cb7a01acSMauro Carvalho Chehab TVP5150_VERT_BLANKING_STOP, 0x00 379cb7a01acSMauro Carvalho Chehab }, 380cb7a01acSMauro Carvalho Chehab { /* 0x1a */ 381cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 382cb7a01acSMauro Carvalho Chehab }, 383cb7a01acSMauro Carvalho Chehab { /* 0x1b */ 384cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x14 385cb7a01acSMauro Carvalho Chehab }, 386cb7a01acSMauro Carvalho Chehab { /* 0x1c */ 387cb7a01acSMauro Carvalho Chehab TVP5150_INT_RESET_REG_B, 0x00 388cb7a01acSMauro Carvalho Chehab }, 389cb7a01acSMauro Carvalho Chehab { /* 0x1d */ 390cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_B, 0x00 391cb7a01acSMauro Carvalho Chehab }, 392cb7a01acSMauro Carvalho Chehab { /* 0x1e */ 393cb7a01acSMauro Carvalho Chehab TVP5150_INTT_CONFIG_REG_B, 0x00 394cb7a01acSMauro Carvalho Chehab }, 395cb7a01acSMauro Carvalho Chehab { /* 0x28 */ 396cb7a01acSMauro Carvalho Chehab TVP5150_VIDEO_STD, 0x00 397cb7a01acSMauro Carvalho Chehab }, 398cb7a01acSMauro Carvalho Chehab { /* 0x2e */ 399cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_ON_CTR, 0x0f 400cb7a01acSMauro Carvalho Chehab }, 401cb7a01acSMauro Carvalho Chehab { /* 0x2f */ 402cb7a01acSMauro Carvalho Chehab TVP5150_MACROVISION_OFF_CTR, 0x01 403cb7a01acSMauro Carvalho Chehab }, 404cb7a01acSMauro Carvalho Chehab { /* 0xbb */ 405cb7a01acSMauro Carvalho Chehab TVP5150_TELETEXT_FIL_ENA, 0x00 406cb7a01acSMauro Carvalho Chehab }, 407cb7a01acSMauro Carvalho Chehab { /* 0xc0 */ 408cb7a01acSMauro Carvalho Chehab TVP5150_INT_STATUS_REG_A, 0x00 409cb7a01acSMauro Carvalho Chehab }, 410cb7a01acSMauro Carvalho Chehab { /* 0xc1 */ 411cb7a01acSMauro Carvalho Chehab TVP5150_INT_ENABLE_REG_A, 0x00 412cb7a01acSMauro Carvalho Chehab }, 413cb7a01acSMauro Carvalho Chehab { /* 0xc2 */ 414cb7a01acSMauro Carvalho Chehab TVP5150_INT_CONF, 0x04 415cb7a01acSMauro Carvalho Chehab }, 416cb7a01acSMauro Carvalho Chehab { /* 0xc8 */ 417cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_INT_THRESHOLD, 0x80 418cb7a01acSMauro Carvalho Chehab }, 419cb7a01acSMauro Carvalho Chehab { /* 0xc9 */ 420cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_RESET, 0x00 421cb7a01acSMauro Carvalho Chehab }, 422cb7a01acSMauro Carvalho Chehab { /* 0xca */ 423cb7a01acSMauro Carvalho Chehab TVP5150_LINE_NUMBER_INT, 0x00 424cb7a01acSMauro Carvalho Chehab }, 425cb7a01acSMauro Carvalho Chehab { /* 0xcb */ 426cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_LOW, 0x4e 427cb7a01acSMauro Carvalho Chehab }, 428cb7a01acSMauro Carvalho Chehab { /* 0xcc */ 429cb7a01acSMauro Carvalho Chehab TVP5150_PIX_ALIGN_REG_HIGH, 0x00 430cb7a01acSMauro Carvalho Chehab }, 431cb7a01acSMauro Carvalho Chehab { /* 0xcd */ 432cb7a01acSMauro Carvalho Chehab TVP5150_FIFO_OUT_CTRL, 0x01 433cb7a01acSMauro Carvalho Chehab }, 434cb7a01acSMauro Carvalho Chehab { /* 0xcf */ 435cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_ENA, 0x00 436cb7a01acSMauro Carvalho Chehab }, 437cb7a01acSMauro Carvalho Chehab { /* 0xd0 */ 438cb7a01acSMauro Carvalho Chehab TVP5150_LINE_MODE_INI, 0x00 439cb7a01acSMauro Carvalho Chehab }, 440cb7a01acSMauro Carvalho Chehab { /* 0xfc */ 441cb7a01acSMauro Carvalho Chehab TVP5150_FULL_FIELD_MODE_REG, 0x7f 442cb7a01acSMauro Carvalho Chehab }, 443cb7a01acSMauro Carvalho Chehab { /* end of data */ 444cb7a01acSMauro Carvalho Chehab 0xff, 0xff 445cb7a01acSMauro Carvalho Chehab } 446cb7a01acSMauro Carvalho Chehab }; 447cb7a01acSMauro Carvalho Chehab 448cb7a01acSMauro Carvalho Chehab /* Default values as sugested at TVP5150AM1 datasheet */ 449cb7a01acSMauro Carvalho Chehab static const struct i2c_reg_value tvp5150_init_enable[] = { 4508105e1bcSPhilipp Zabel { /* Automatic offset and AGC enabled */ 451cb7a01acSMauro Carvalho Chehab TVP5150_ANAL_CHL_CTL, 0x15 452cb7a01acSMauro Carvalho Chehab }, { /* Activate YCrCb output 0x9 or 0xd ? */ 453b4b2de38SLaurent Pinchart TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL | 454b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_INTREQ_OE | 455b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_YCBCR_OE | 456b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_SYNC_OE | 457b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_VBLANK | 458b4b2de38SLaurent Pinchart TVP5150_MISC_CTL_CLOCK_OE, 459cb7a01acSMauro Carvalho Chehab }, { /* Activates video std autodetection for all standards */ 460cb7a01acSMauro Carvalho Chehab TVP5150_AUTOSW_MSK, 0x0 461cb7a01acSMauro Carvalho Chehab }, { /* Default format: 0x47. For 4:2:2: 0x40 */ 462cb7a01acSMauro Carvalho Chehab TVP5150_DATA_RATE_SEL, 0x47 463cb7a01acSMauro Carvalho Chehab }, { 464cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_1, 0x0c 465cb7a01acSMauro Carvalho Chehab }, { 466cb7a01acSMauro Carvalho Chehab TVP5150_CHROMA_PROC_CTL_2, 0x54 467cb7a01acSMauro Carvalho Chehab }, { /* Non documented, but initialized on WinTV USB2 */ 468cb7a01acSMauro Carvalho Chehab 0x27, 0x20 469cb7a01acSMauro Carvalho Chehab }, { 470cb7a01acSMauro Carvalho Chehab 0xff, 0xff 471cb7a01acSMauro Carvalho Chehab } 472cb7a01acSMauro Carvalho Chehab }; 473cb7a01acSMauro Carvalho Chehab 474cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type { 475cb7a01acSMauro Carvalho Chehab unsigned int vbi_type; 476cb7a01acSMauro Carvalho Chehab unsigned int ini_line; 477cb7a01acSMauro Carvalho Chehab unsigned int end_line; 478cb7a01acSMauro Carvalho Chehab unsigned int by_field :1; 479cb7a01acSMauro Carvalho Chehab }; 480cb7a01acSMauro Carvalho Chehab 481cb7a01acSMauro Carvalho Chehab struct i2c_vbi_ram_value { 482cb7a01acSMauro Carvalho Chehab u16 reg; 483cb7a01acSMauro Carvalho Chehab struct tvp5150_vbi_type type; 484cb7a01acSMauro Carvalho Chehab unsigned char values[16]; 485cb7a01acSMauro Carvalho Chehab }; 486cb7a01acSMauro Carvalho Chehab 487cb7a01acSMauro Carvalho Chehab /* This struct have the values for each supported VBI Standard 488cb7a01acSMauro Carvalho Chehab * by 489cb7a01acSMauro Carvalho Chehab tvp5150_vbi_types should follow the same order as vbi_ram_default 490cb7a01acSMauro Carvalho Chehab * value 0 means rom position 0x10, value 1 means rom position 0x30 491cb7a01acSMauro Carvalho Chehab * and so on. There are 16 possible locations from 0 to 15. 492cb7a01acSMauro Carvalho Chehab */ 493cb7a01acSMauro Carvalho Chehab 49465dc760bSNasser Afshin static struct i2c_vbi_ram_value vbi_ram_default[] = { 49565dc760bSNasser Afshin 4969bfd8f88SNasser Afshin /* 4979bfd8f88SNasser Afshin * FIXME: Current api doesn't handle all VBI types, those not 4989bfd8f88SNasser Afshin * yet supported are placed under #if 0 4999bfd8f88SNasser Afshin */ 500cb7a01acSMauro Carvalho Chehab #if 0 5013dd6b560SMauro Carvalho Chehab [0] = {0x010, /* Teletext, SECAM, WST System A */ 502cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_SECAM, 6, 23, 1}, 503cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 504cb7a01acSMauro Carvalho Chehab 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } 505cb7a01acSMauro Carvalho Chehab }, 506cb7a01acSMauro Carvalho Chehab #endif 5073dd6b560SMauro Carvalho Chehab [1] = {0x030, /* Teletext, PAL, WST System B */ 508cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_B, 6, 22, 1}, 509cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 510cb7a01acSMauro Carvalho Chehab 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } 511cb7a01acSMauro Carvalho Chehab }, 512cb7a01acSMauro Carvalho Chehab #if 0 5133dd6b560SMauro Carvalho Chehab [2] = {0x050, /* Teletext, PAL, WST System C */ 514cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_PAL_C, 6, 22, 1}, 515cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 516cb7a01acSMauro Carvalho Chehab 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 517cb7a01acSMauro Carvalho Chehab }, 5183dd6b560SMauro Carvalho Chehab [3] = {0x070, /* Teletext, NTSC, WST System B */ 519cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_B, 10, 21, 1}, 520cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, 521cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 522cb7a01acSMauro Carvalho Chehab }, 5233dd6b560SMauro Carvalho Chehab [4] = {0x090, /* Tetetext, NTSC NABTS System C */ 524cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_C, 10, 21, 1}, 525cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, 526cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } 527cb7a01acSMauro Carvalho Chehab }, 5283dd6b560SMauro Carvalho Chehab [5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */ 529cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_TELETEXT_NTSC_D, 10, 21, 1}, 530cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, 531cb7a01acSMauro Carvalho Chehab 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } 532cb7a01acSMauro Carvalho Chehab }, 5333dd6b560SMauro Carvalho Chehab [6] = {0x0d0, /* Closed Caption, PAL/SECAM */ 534cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_625, 22, 22, 1}, 535cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 536cb7a01acSMauro Carvalho Chehab 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 537cb7a01acSMauro Carvalho Chehab }, 538cb7a01acSMauro Carvalho Chehab #endif 5393dd6b560SMauro Carvalho Chehab [7] = {0x0f0, /* Closed Caption, NTSC */ 540cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_CAPTION_525, 21, 21, 1}, 541cb7a01acSMauro Carvalho Chehab { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 542cb7a01acSMauro Carvalho Chehab 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } 543cb7a01acSMauro Carvalho Chehab }, 5443dd6b560SMauro Carvalho Chehab [8] = {0x110, /* Wide Screen Signal, PAL/SECAM */ 545cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_625, 23, 23, 1}, 546cb7a01acSMauro Carvalho Chehab { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 547cb7a01acSMauro Carvalho Chehab 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } 548cb7a01acSMauro Carvalho Chehab }, 549cb7a01acSMauro Carvalho Chehab #if 0 5503dd6b560SMauro Carvalho Chehab [9] = {0x130, /* Wide Screen Signal, NTSC C */ 551cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_WSS_525, 20, 20, 1}, 552cb7a01acSMauro Carvalho Chehab { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, 553cb7a01acSMauro Carvalho Chehab 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } 554cb7a01acSMauro Carvalho Chehab }, 5553dd6b560SMauro Carvalho Chehab [10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ 556cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_625, 6, 22, 0}, 557cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 558cb7a01acSMauro Carvalho Chehab 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 559cb7a01acSMauro Carvalho Chehab }, 5603dd6b560SMauro Carvalho Chehab [11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */ 561cb7a01acSMauro Carvalho Chehab {V4l2_SLICED_VITC_525, 10, 20, 0}, 562cb7a01acSMauro Carvalho Chehab { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 563cb7a01acSMauro Carvalho Chehab 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } 564cb7a01acSMauro Carvalho Chehab }, 565cb7a01acSMauro Carvalho Chehab #endif 5663dd6b560SMauro Carvalho Chehab [12] = {0x190, /* Video Program System (VPS), PAL */ 567cb7a01acSMauro Carvalho Chehab {V4L2_SLICED_VPS, 16, 16, 0}, 568cb7a01acSMauro Carvalho Chehab { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, 569cb7a01acSMauro Carvalho Chehab 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } 570cb7a01acSMauro Carvalho Chehab }, 571cb7a01acSMauro Carvalho Chehab /* 0x1d0 User programmable */ 572cb7a01acSMauro Carvalho Chehab }; 573cb7a01acSMauro Carvalho Chehab 574cb7a01acSMauro Carvalho Chehab static int tvp5150_write_inittab(struct v4l2_subdev *sd, 575cb7a01acSMauro Carvalho Chehab const struct i2c_reg_value *regs) 576cb7a01acSMauro Carvalho Chehab { 57728b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 57828b9e227SPhilipp Zabel 579cb7a01acSMauro Carvalho Chehab while (regs->reg != 0xff) { 58028b9e227SPhilipp Zabel regmap_write(decoder->regmap, regs->reg, regs->value); 581cb7a01acSMauro Carvalho Chehab regs++; 582cb7a01acSMauro Carvalho Chehab } 583cb7a01acSMauro Carvalho Chehab return 0; 584cb7a01acSMauro Carvalho Chehab } 585cb7a01acSMauro Carvalho Chehab 5863dd6b560SMauro Carvalho Chehab static int tvp5150_vdp_init(struct v4l2_subdev *sd) 587cb7a01acSMauro Carvalho Chehab { 58828b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 58928b9e227SPhilipp Zabel struct regmap *map = decoder->regmap; 590cb7a01acSMauro Carvalho Chehab unsigned int i; 5913dd6b560SMauro Carvalho Chehab int j; 592cb7a01acSMauro Carvalho Chehab 593cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 59428b9e227SPhilipp Zabel regmap_write(map, TVP5150_FULL_FIELD_ENA, 0); 595cb7a01acSMauro Carvalho Chehab 596cb7a01acSMauro Carvalho Chehab /* Before programming, Line mode should be at 0xff */ 597cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 59828b9e227SPhilipp Zabel regmap_write(map, i, 0xff); 599cb7a01acSMauro Carvalho Chehab 600cb7a01acSMauro Carvalho Chehab /* Load Ram Table */ 6013dd6b560SMauro Carvalho Chehab for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) { 6023dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j]; 6033dd6b560SMauro Carvalho Chehab 6043dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 6053dd6b560SMauro Carvalho Chehab continue; 6063dd6b560SMauro Carvalho Chehab 60728b9e227SPhilipp Zabel regmap_write(map, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8); 60828b9e227SPhilipp Zabel regmap_write(map, TVP5150_CONF_RAM_ADDR_LOW, regs->reg); 609cb7a01acSMauro Carvalho Chehab 610cb7a01acSMauro Carvalho Chehab for (i = 0; i < 16; i++) 61128b9e227SPhilipp Zabel regmap_write(map, TVP5150_VDP_CONF_RAM_DATA, 61228b9e227SPhilipp Zabel regs->values[i]); 613cb7a01acSMauro Carvalho Chehab } 614cb7a01acSMauro Carvalho Chehab return 0; 615cb7a01acSMauro Carvalho Chehab } 616cb7a01acSMauro Carvalho Chehab 617cb7a01acSMauro Carvalho Chehab /* Fills VBI capabilities based on i2c_vbi_ram_value struct */ 618cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, 619cb7a01acSMauro Carvalho Chehab struct v4l2_sliced_vbi_cap *cap) 620cb7a01acSMauro Carvalho Chehab { 6213dd6b560SMauro Carvalho Chehab int line, i; 622cb7a01acSMauro Carvalho Chehab 623257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n"); 624bb7a3681SNasser Afshin memset(cap, 0, sizeof(*cap)); 625cb7a01acSMauro Carvalho Chehab 6263dd6b560SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { 6273dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; 6283dd6b560SMauro Carvalho Chehab 6293dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 6303dd6b560SMauro Carvalho Chehab continue; 6313dd6b560SMauro Carvalho Chehab 6323dd6b560SMauro Carvalho Chehab for (line = regs->type.ini_line; 6333dd6b560SMauro Carvalho Chehab line <= regs->type.end_line; 6343dd6b560SMauro Carvalho Chehab line++) { 635cb7a01acSMauro Carvalho Chehab cap->service_lines[0][line] |= regs->type.vbi_type; 636cb7a01acSMauro Carvalho Chehab } 637cb7a01acSMauro Carvalho Chehab cap->service_set |= regs->type.vbi_type; 638cb7a01acSMauro Carvalho Chehab } 639cb7a01acSMauro Carvalho Chehab return 0; 640cb7a01acSMauro Carvalho Chehab } 641cb7a01acSMauro Carvalho Chehab 642cb7a01acSMauro Carvalho Chehab /* Set vbi processing 643cb7a01acSMauro Carvalho Chehab * type - one of tvp5150_vbi_types 644cb7a01acSMauro Carvalho Chehab * line - line to gather data 645cb7a01acSMauro Carvalho Chehab * fields: bit 0 field1, bit 1, field2 646cb7a01acSMauro Carvalho Chehab * flags (default=0xf0) is a bitmask, were set means: 647cb7a01acSMauro Carvalho Chehab * bit 7: enable filtering null bytes on CC 648cb7a01acSMauro Carvalho Chehab * bit 6: send data also to FIFO 649cb7a01acSMauro Carvalho Chehab * bit 5: don't allow data with errors on FIFO 650cb7a01acSMauro Carvalho Chehab * bit 4: enable ECC when possible 651cb7a01acSMauro Carvalho Chehab * pix_align = pix alignment: 652cb7a01acSMauro Carvalho Chehab * LSB = field1 653cb7a01acSMauro Carvalho Chehab * MSB = field2 654cb7a01acSMauro Carvalho Chehab */ 655cb7a01acSMauro Carvalho Chehab static int tvp5150_set_vbi(struct v4l2_subdev *sd, 656cb7a01acSMauro Carvalho Chehab unsigned int type, u8 flags, int line, 657cb7a01acSMauro Carvalho Chehab const int fields) 658cb7a01acSMauro Carvalho Chehab { 659cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 660cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 661cb7a01acSMauro Carvalho Chehab u8 reg; 6623dd6b560SMauro Carvalho Chehab int i, pos = 0; 663cb7a01acSMauro Carvalho Chehab 664cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 665257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); 666cb7a01acSMauro Carvalho Chehab return 0; 667cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 668cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 669cb7a01acSMauro Carvalho Chehab line += 3; 670cb7a01acSMauro Carvalho Chehab } 671cb7a01acSMauro Carvalho Chehab 672cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 673cb7a01acSMauro Carvalho Chehab return 0; 674cb7a01acSMauro Carvalho Chehab 6753dd6b560SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) { 6763dd6b560SMauro Carvalho Chehab const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i]; 6773dd6b560SMauro Carvalho Chehab 6783dd6b560SMauro Carvalho Chehab if (!regs->type.vbi_type) 6793dd6b560SMauro Carvalho Chehab continue; 6803dd6b560SMauro Carvalho Chehab 681cb7a01acSMauro Carvalho Chehab if ((type & regs->type.vbi_type) && 682cb7a01acSMauro Carvalho Chehab (line >= regs->type.ini_line) && 683b3d930aaSGustavo A. R. Silva (line <= regs->type.end_line)) 684cb7a01acSMauro Carvalho Chehab break; 685cb7a01acSMauro Carvalho Chehab pos++; 686cb7a01acSMauro Carvalho Chehab } 687b3d930aaSGustavo A. R. Silva 688cb7a01acSMauro Carvalho Chehab type = pos | (flags & 0xf0); 689cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 690cb7a01acSMauro Carvalho Chehab 691b3d930aaSGustavo A. R. Silva if (fields & 1) 69228b9e227SPhilipp Zabel regmap_write(decoder->regmap, reg, type); 693cb7a01acSMauro Carvalho Chehab 694b3d930aaSGustavo A. R. Silva if (fields & 2) 69528b9e227SPhilipp Zabel regmap_write(decoder->regmap, reg + 1, type); 696cb7a01acSMauro Carvalho Chehab 697cb7a01acSMauro Carvalho Chehab return type; 698cb7a01acSMauro Carvalho Chehab } 699cb7a01acSMauro Carvalho Chehab 7003dd6b560SMauro Carvalho Chehab static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line) 701cb7a01acSMauro Carvalho Chehab { 702cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 703cb7a01acSMauro Carvalho Chehab v4l2_std_id std = decoder->norm; 704cb7a01acSMauro Carvalho Chehab u8 reg; 705cb7a01acSMauro Carvalho Chehab int pos, type = 0; 706cb7a01acSMauro Carvalho Chehab int i, ret = 0; 707cb7a01acSMauro Carvalho Chehab 708cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 709257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); 710cb7a01acSMauro Carvalho Chehab return 0; 711cb7a01acSMauro Carvalho Chehab } else if (std & V4L2_STD_625_50) { 712cb7a01acSMauro Carvalho Chehab /* Don't follow NTSC Line number convension */ 713cb7a01acSMauro Carvalho Chehab line += 3; 714cb7a01acSMauro Carvalho Chehab } 715cb7a01acSMauro Carvalho Chehab 716cb7a01acSMauro Carvalho Chehab if (line < 6 || line > 27) 717cb7a01acSMauro Carvalho Chehab return 0; 718cb7a01acSMauro Carvalho Chehab 719cb7a01acSMauro Carvalho Chehab reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; 720cb7a01acSMauro Carvalho Chehab 721cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 1; i++) { 722cb7a01acSMauro Carvalho Chehab ret = tvp5150_read(sd, reg + i); 723cb7a01acSMauro Carvalho Chehab if (ret < 0) { 724257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "%s: failed with error = %d\n", 725cb7a01acSMauro Carvalho Chehab __func__, ret); 726cb7a01acSMauro Carvalho Chehab return 0; 727cb7a01acSMauro Carvalho Chehab } 728cb7a01acSMauro Carvalho Chehab pos = ret & 0x0f; 7293dd6b560SMauro Carvalho Chehab if (pos < ARRAY_SIZE(vbi_ram_default)) 7303dd6b560SMauro Carvalho Chehab type |= vbi_ram_default[pos].type.vbi_type; 731cb7a01acSMauro Carvalho Chehab } 732cb7a01acSMauro Carvalho Chehab 733cb7a01acSMauro Carvalho Chehab return type; 734cb7a01acSMauro Carvalho Chehab } 735cb7a01acSMauro Carvalho Chehab 736cb7a01acSMauro Carvalho Chehab static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) 737cb7a01acSMauro Carvalho Chehab { 738cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 739cb7a01acSMauro Carvalho Chehab int fmt = 0; 740cb7a01acSMauro Carvalho Chehab 741cb7a01acSMauro Carvalho Chehab /* First tests should be against specific std */ 742cb7a01acSMauro Carvalho Chehab 74326811ae0SHans Verkuil if (std == V4L2_STD_NTSC_443) { 744cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_4_43_BIT; 74526811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_M) { 746cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_M_BIT; 74726811ae0SHans Verkuil } else if (std == V4L2_STD_PAL_N || std == V4L2_STD_PAL_Nc) { 748cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_COMBINATION_N_BIT; 749cb7a01acSMauro Carvalho Chehab } else { 750cb7a01acSMauro Carvalho Chehab /* Then, test against generic ones */ 751cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 752cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_NTSC_MJ_BIT; 753cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_PAL) 754cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_PAL_BDGHIN_BIT; 755cb7a01acSMauro Carvalho Chehab else if (std & V4L2_STD_SECAM) 756cb7a01acSMauro Carvalho Chehab fmt = VIDEO_STD_SECAM_BIT; 757cb7a01acSMauro Carvalho Chehab } 758cb7a01acSMauro Carvalho Chehab 759257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "Set video std register to %d.\n", fmt); 76028b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VIDEO_STD, fmt); 761cb7a01acSMauro Carvalho Chehab return 0; 762cb7a01acSMauro Carvalho Chehab } 763cb7a01acSMauro Carvalho Chehab 7640db87cc7SMarco Felsch static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) 7650db87cc7SMarco Felsch { 7660db87cc7SMarco Felsch struct tvp5150 *decoder = to_tvp5150(sd); 7670db87cc7SMarco Felsch 7680db87cc7SMarco Felsch *std = decoder->norm; 7690db87cc7SMarco Felsch 7700db87cc7SMarco Felsch return 0; 7710db87cc7SMarco Felsch } 7720db87cc7SMarco Felsch 773cb7a01acSMauro Carvalho Chehab static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 774cb7a01acSMauro Carvalho Chehab { 775cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 776cb7a01acSMauro Carvalho Chehab 777cb7a01acSMauro Carvalho Chehab if (decoder->norm == std) 778cb7a01acSMauro Carvalho Chehab return 0; 779cb7a01acSMauro Carvalho Chehab 780cb7a01acSMauro Carvalho Chehab /* Change cropping height limits */ 781cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 782cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_525_60; 783cb7a01acSMauro Carvalho Chehab else 784cb7a01acSMauro Carvalho Chehab decoder->rect.height = TVP5150_V_MAX_OTHERS; 785cb7a01acSMauro Carvalho Chehab 78615695866SPhilipp Zabel decoder->norm = std; 787cb7a01acSMauro Carvalho Chehab 788cb7a01acSMauro Carvalho Chehab return tvp5150_set_std(sd, std); 789cb7a01acSMauro Carvalho Chehab } 790cb7a01acSMauro Carvalho Chehab 79115695866SPhilipp Zabel static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) 79215695866SPhilipp Zabel { 79315695866SPhilipp Zabel int val = tvp5150_read(sd, TVP5150_STATUS_REG_5); 79415695866SPhilipp Zabel 79515695866SPhilipp Zabel switch (val & 0x0F) { 79615695866SPhilipp Zabel case 0x01: 79715695866SPhilipp Zabel return V4L2_STD_NTSC; 79815695866SPhilipp Zabel case 0x03: 79915695866SPhilipp Zabel return V4L2_STD_PAL; 80015695866SPhilipp Zabel case 0x05: 80115695866SPhilipp Zabel return V4L2_STD_PAL_M; 80215695866SPhilipp Zabel case 0x07: 80315695866SPhilipp Zabel return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc; 80415695866SPhilipp Zabel case 0x09: 80515695866SPhilipp Zabel return V4L2_STD_NTSC_443; 80615695866SPhilipp Zabel case 0xb: 80715695866SPhilipp Zabel return V4L2_STD_SECAM; 80815695866SPhilipp Zabel default: 80915695866SPhilipp Zabel return V4L2_STD_UNKNOWN; 81015695866SPhilipp Zabel } 81115695866SPhilipp Zabel } 81215695866SPhilipp Zabel 813ee9a6ff6SPhilipp Zabel static int tvp5150_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) 814ee9a6ff6SPhilipp Zabel { 815ee9a6ff6SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 816ee9a6ff6SPhilipp Zabel 817ee9a6ff6SPhilipp Zabel *std_id = decoder->lock ? tvp5150_read_std(sd) : V4L2_STD_UNKNOWN; 818ee9a6ff6SPhilipp Zabel 819ee9a6ff6SPhilipp Zabel return 0; 820ee9a6ff6SPhilipp Zabel } 821ee9a6ff6SPhilipp Zabel 8222f0a5c65SPhilipp Zabel static const struct v4l2_event tvp5150_ev_fmt = { 8232f0a5c65SPhilipp Zabel .type = V4L2_EVENT_SOURCE_CHANGE, 8242f0a5c65SPhilipp Zabel .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 8252f0a5c65SPhilipp Zabel }; 8262f0a5c65SPhilipp Zabel 8278e4c97e0SPhilipp Zabel static irqreturn_t tvp5150_isr(int irq, void *dev_id) 8288e4c97e0SPhilipp Zabel { 8298e4c97e0SPhilipp Zabel struct tvp5150 *decoder = dev_id; 8308e4c97e0SPhilipp Zabel struct regmap *map = decoder->regmap; 83162a764e1SPhilipp Zabel unsigned int mask, active = 0, status = 0; 83262a764e1SPhilipp Zabel 83362a764e1SPhilipp Zabel mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE | 83462a764e1SPhilipp Zabel TVP5150_MISC_CTL_CLOCK_OE; 8358e4c97e0SPhilipp Zabel 8368e4c97e0SPhilipp Zabel regmap_read(map, TVP5150_INT_STATUS_REG_A, &status); 8378e4c97e0SPhilipp Zabel if (status) { 8388e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INT_STATUS_REG_A, status); 8398e4c97e0SPhilipp Zabel 84062a764e1SPhilipp Zabel if (status & TVP5150_INT_A_LOCK) { 8418e4c97e0SPhilipp Zabel decoder->lock = !!(status & TVP5150_INT_A_LOCK_STATUS); 8427bb3c338SPhilipp Zabel dev_dbg_lvl(decoder->sd.dev, 1, debug, 8437bb3c338SPhilipp Zabel "sync lo%s signal\n", 8447bb3c338SPhilipp Zabel decoder->lock ? "ck" : "ss"); 8452f0a5c65SPhilipp Zabel v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt); 84662a764e1SPhilipp Zabel regmap_update_bits(map, TVP5150_MISC_CTL, mask, 84762a764e1SPhilipp Zabel decoder->lock ? decoder->oe : 0); 84862a764e1SPhilipp Zabel } 8498e4c97e0SPhilipp Zabel 8508e4c97e0SPhilipp Zabel return IRQ_HANDLED; 8518e4c97e0SPhilipp Zabel } 8528e4c97e0SPhilipp Zabel 8538e4c97e0SPhilipp Zabel regmap_read(map, TVP5150_INT_ACTIVE_REG_B, &active); 8548e4c97e0SPhilipp Zabel if (active) { 8558e4c97e0SPhilipp Zabel status = 0; 8568e4c97e0SPhilipp Zabel regmap_read(map, TVP5150_INT_STATUS_REG_B, &status); 8578e4c97e0SPhilipp Zabel if (status) 8588e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INT_RESET_REG_B, status); 8598e4c97e0SPhilipp Zabel } 8608e4c97e0SPhilipp Zabel 8618e4c97e0SPhilipp Zabel return IRQ_HANDLED; 8628e4c97e0SPhilipp Zabel } 8638e4c97e0SPhilipp Zabel 864cb7a01acSMauro Carvalho Chehab static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) 865cb7a01acSMauro Carvalho Chehab { 866cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 8678105e1bcSPhilipp Zabel struct regmap *map = decoder->regmap; 868cb7a01acSMauro Carvalho Chehab 869cb7a01acSMauro Carvalho Chehab /* Initializes TVP5150 to its default values */ 870cb7a01acSMauro Carvalho Chehab tvp5150_write_inittab(sd, tvp5150_init_default); 871cb7a01acSMauro Carvalho Chehab 8728e4c97e0SPhilipp Zabel if (decoder->irq) { 8738e4c97e0SPhilipp Zabel /* Configure pins: FID, VSYNC, INTREQ, SCLK */ 8748e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x0); 8758e4c97e0SPhilipp Zabel /* Set interrupt polarity to active high */ 8768e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE | 0x1); 8778e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x1); 8788e4c97e0SPhilipp Zabel } else { 8798105e1bcSPhilipp Zabel /* Configure pins: FID, VSYNC, GPCL/VBLK, SCLK */ 8808105e1bcSPhilipp Zabel regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x2); 8818e4c97e0SPhilipp Zabel /* Keep interrupt polarity active low */ 8828e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE); 8838e4c97e0SPhilipp Zabel regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x0); 8848e4c97e0SPhilipp Zabel } 8858105e1bcSPhilipp Zabel 886cb7a01acSMauro Carvalho Chehab /* Initializes VDP registers */ 8873dd6b560SMauro Carvalho Chehab tvp5150_vdp_init(sd); 888cb7a01acSMauro Carvalho Chehab 889cb7a01acSMauro Carvalho Chehab /* Selects decoder input */ 890cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 891cb7a01acSMauro Carvalho Chehab 892cb7a01acSMauro Carvalho Chehab /* Initialize image preferences */ 893cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&decoder->hdl); 894cb7a01acSMauro Carvalho Chehab 8951bb086bcSPhilipp Zabel return 0; 8961bb086bcSPhilipp Zabel } 8971bb086bcSPhilipp Zabel 8981bb086bcSPhilipp Zabel static int tvp5150_enable(struct v4l2_subdev *sd) 8991bb086bcSPhilipp Zabel { 9001bb086bcSPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 9011bb086bcSPhilipp Zabel v4l2_std_id std; 9021bb086bcSPhilipp Zabel 9031bb086bcSPhilipp Zabel /* Initializes TVP5150 to stream enabled values */ 9041bb086bcSPhilipp Zabel tvp5150_write_inittab(sd, tvp5150_init_enable); 9051bb086bcSPhilipp Zabel 90615695866SPhilipp Zabel if (decoder->norm == V4L2_STD_ALL) 90715695866SPhilipp Zabel std = tvp5150_read_std(sd); 90815695866SPhilipp Zabel else 90915695866SPhilipp Zabel std = decoder->norm; 91015695866SPhilipp Zabel 91115695866SPhilipp Zabel /* Disable autoswitch mode */ 91215695866SPhilipp Zabel tvp5150_set_std(sd, std); 913a2e5f1b3SJavier Martinez Canillas 91462a764e1SPhilipp Zabel /* 91562a764e1SPhilipp Zabel * Enable the YCbCr and clock outputs. In discrete sync mode 91662a764e1SPhilipp Zabel * (non-BT.656) additionally enable the the sync outputs. 91762a764e1SPhilipp Zabel */ 91862a764e1SPhilipp Zabel switch (decoder->mbus_type) { 91962a764e1SPhilipp Zabel case V4L2_MBUS_PARALLEL: 9208a7441baSMarco Felsch /* 8-bit 4:2:2 YUV with discrete sync output */ 9218a7441baSMarco Felsch regmap_update_bits(decoder->regmap, TVP5150_DATA_RATE_SEL, 9228a7441baSMarco Felsch 0x7, 0x0); 92362a764e1SPhilipp Zabel decoder->oe = TVP5150_MISC_CTL_YCBCR_OE | 92462a764e1SPhilipp Zabel TVP5150_MISC_CTL_CLOCK_OE | 92562a764e1SPhilipp Zabel TVP5150_MISC_CTL_SYNC_OE; 92662a764e1SPhilipp Zabel break; 92762a764e1SPhilipp Zabel case V4L2_MBUS_BT656: 92862a764e1SPhilipp Zabel decoder->oe = TVP5150_MISC_CTL_YCBCR_OE | 92962a764e1SPhilipp Zabel TVP5150_MISC_CTL_CLOCK_OE; 93062a764e1SPhilipp Zabel break; 93162a764e1SPhilipp Zabel default: 93262a764e1SPhilipp Zabel return -EINVAL; 93362a764e1SPhilipp Zabel } 934a2e5f1b3SJavier Martinez Canillas 935cb7a01acSMauro Carvalho Chehab return 0; 936cb7a01acSMauro Carvalho Chehab }; 937cb7a01acSMauro Carvalho Chehab 938cb7a01acSMauro Carvalho Chehab static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) 939cb7a01acSMauro Carvalho Chehab { 940cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_sd(ctrl); 941c43875f6SMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 942cb7a01acSMauro Carvalho Chehab 943cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 944cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 94528b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_BRIGHT_CTL, ctrl->val); 946cb7a01acSMauro Carvalho Chehab return 0; 947cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 94828b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_CONTRAST_CTL, ctrl->val); 949cb7a01acSMauro Carvalho Chehab return 0; 950cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 95128b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_SATURATION_CTL, 95228b9e227SPhilipp Zabel ctrl->val); 953cb7a01acSMauro Carvalho Chehab return 0; 954cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 95528b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_HUE_CTL, ctrl->val); 9562d29bcc8SMarco Felsch return 0; 957c43875f6SMauro Carvalho Chehab case V4L2_CID_TEST_PATTERN: 958c43875f6SMauro Carvalho Chehab decoder->enable = ctrl->val ? false : true; 959c43875f6SMauro Carvalho Chehab tvp5150_selmux(sd); 960cb7a01acSMauro Carvalho Chehab return 0; 961cb7a01acSMauro Carvalho Chehab } 962cb7a01acSMauro Carvalho Chehab return -EINVAL; 963cb7a01acSMauro Carvalho Chehab } 964cb7a01acSMauro Carvalho Chehab 9655cb82940SMarco Felsch static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop) 9665cb82940SMarco Felsch { 9675cb82940SMarco Felsch /* Default is no cropping */ 9685cb82940SMarco Felsch crop->top = 0; 9695cb82940SMarco Felsch crop->left = 0; 9705cb82940SMarco Felsch crop->width = TVP5150_H_MAX; 9715cb82940SMarco Felsch if (std & V4L2_STD_525_60) 9725cb82940SMarco Felsch crop->height = TVP5150_V_MAX_525_60; 9735cb82940SMarco Felsch else 9745cb82940SMarco Felsch crop->height = TVP5150_V_MAX_OTHERS; 9755cb82940SMarco Felsch } 9765cb82940SMarco Felsch 977da298c6dSHans Verkuil static int tvp5150_fill_fmt(struct v4l2_subdev *sd, 978da298c6dSHans Verkuil struct v4l2_subdev_pad_config *cfg, 979da298c6dSHans Verkuil struct v4l2_subdev_format *format) 980cb7a01acSMauro Carvalho Chehab { 981da298c6dSHans Verkuil struct v4l2_mbus_framefmt *f; 982cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 983cb7a01acSMauro Carvalho Chehab 984bc322c0dSMauro Carvalho Chehab if (!format || (format->pad != TVP5150_PAD_VID_OUT)) 985cb7a01acSMauro Carvalho Chehab return -EINVAL; 986cb7a01acSMauro Carvalho Chehab 987da298c6dSHans Verkuil f = &format->format; 988da298c6dSHans Verkuil 989cb7a01acSMauro Carvalho Chehab f->width = decoder->rect.width; 9901831af09SJavier Martinez Canillas f->height = decoder->rect.height / 2; 991cb7a01acSMauro Carvalho Chehab 9925cb82940SMarco Felsch f->code = TVP5150_MBUS_FMT; 9935cb82940SMarco Felsch f->field = TVP5150_FIELD; 9945cb82940SMarco Felsch f->colorspace = TVP5150_COLORSPACE; 995cb7a01acSMauro Carvalho Chehab 996257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "width = %d, height = %d\n", f->width, 997cb7a01acSMauro Carvalho Chehab f->height); 998cb7a01acSMauro Carvalho Chehab return 0; 999cb7a01acSMauro Carvalho Chehab } 1000cb7a01acSMauro Carvalho Chehab 100110d5509cSHans Verkuil static int tvp5150_set_selection(struct v4l2_subdev *sd, 100210d5509cSHans Verkuil struct v4l2_subdev_pad_config *cfg, 100310d5509cSHans Verkuil struct v4l2_subdev_selection *sel) 1004cb7a01acSMauro Carvalho Chehab { 1005cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 100610d5509cSHans Verkuil struct v4l2_rect rect = sel->r; 1007cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 100810d5509cSHans Verkuil int hmax; 100910d5509cSHans Verkuil 101010d5509cSHans Verkuil if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || 101110d5509cSHans Verkuil sel->target != V4L2_SEL_TGT_CROP) 101210d5509cSHans Verkuil return -EINVAL; 1013cb7a01acSMauro Carvalho Chehab 1014257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n", 1015cb7a01acSMauro Carvalho Chehab __func__, rect.left, rect.top, rect.width, rect.height); 1016cb7a01acSMauro Carvalho Chehab 1017cb7a01acSMauro Carvalho Chehab /* tvp5150 has some special limits */ 1018cb7a01acSMauro Carvalho Chehab rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); 1019cb7a01acSMauro Carvalho Chehab rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); 1020cb7a01acSMauro Carvalho Chehab 1021cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 1022cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 1023cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 1024cb7a01acSMauro Carvalho Chehab else 1025cb7a01acSMauro Carvalho Chehab std = decoder->norm; 1026cb7a01acSMauro Carvalho Chehab 1027cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 1028cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_525_60; 1029cb7a01acSMauro Carvalho Chehab else 1030cb7a01acSMauro Carvalho Chehab hmax = TVP5150_V_MAX_OTHERS; 1031cb7a01acSMauro Carvalho Chehab 1032bd24db04SMarco Felsch /* 1033bd24db04SMarco Felsch * alignments: 1034bd24db04SMarco Felsch * - width = 2 due to UYVY colorspace 1035bd24db04SMarco Felsch * - height, image = no special alignment 1036bd24db04SMarco Felsch */ 1037bd24db04SMarco Felsch v4l_bound_align_image(&rect.width, 1038bd24db04SMarco Felsch TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, 1039bd24db04SMarco Felsch TVP5150_H_MAX - rect.left, 1, &rect.height, 1040cb7a01acSMauro Carvalho Chehab hmax - TVP5150_MAX_CROP_TOP - rect.top, 1041bd24db04SMarco Felsch hmax - rect.top, 0, 0); 1042cb7a01acSMauro Carvalho Chehab 104328b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top); 104428b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, 1045cb7a01acSMauro Carvalho Chehab rect.top + rect.height - hmax); 104628b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB, 1047cb7a01acSMauro Carvalho Chehab rect.left >> TVP5150_CROP_SHIFT); 104828b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB, 1049cb7a01acSMauro Carvalho Chehab rect.left | (1 << TVP5150_CROP_SHIFT)); 105028b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB, 1051cb7a01acSMauro Carvalho Chehab (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> 1052cb7a01acSMauro Carvalho Chehab TVP5150_CROP_SHIFT); 105328b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB, 1054cb7a01acSMauro Carvalho Chehab rect.left + rect.width - TVP5150_MAX_CROP_LEFT); 1055cb7a01acSMauro Carvalho Chehab 1056cb7a01acSMauro Carvalho Chehab decoder->rect = rect; 1057cb7a01acSMauro Carvalho Chehab 1058cb7a01acSMauro Carvalho Chehab return 0; 1059cb7a01acSMauro Carvalho Chehab } 1060cb7a01acSMauro Carvalho Chehab 106110d5509cSHans Verkuil static int tvp5150_get_selection(struct v4l2_subdev *sd, 106210d5509cSHans Verkuil struct v4l2_subdev_pad_config *cfg, 106310d5509cSHans Verkuil struct v4l2_subdev_selection *sel) 1064cb7a01acSMauro Carvalho Chehab { 106510d5509cSHans Verkuil struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); 1066cb7a01acSMauro Carvalho Chehab v4l2_std_id std; 1067cb7a01acSMauro Carvalho Chehab 106810d5509cSHans Verkuil if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 1069cb7a01acSMauro Carvalho Chehab return -EINVAL; 1070cb7a01acSMauro Carvalho Chehab 107110d5509cSHans Verkuil switch (sel->target) { 107210d5509cSHans Verkuil case V4L2_SEL_TGT_CROP_BOUNDS: 107310d5509cSHans Verkuil case V4L2_SEL_TGT_CROP_DEFAULT: 107410d5509cSHans Verkuil sel->r.left = 0; 107510d5509cSHans Verkuil sel->r.top = 0; 107610d5509cSHans Verkuil sel->r.width = TVP5150_H_MAX; 1077cb7a01acSMauro Carvalho Chehab 1078cb7a01acSMauro Carvalho Chehab /* Calculate height based on current standard */ 1079cb7a01acSMauro Carvalho Chehab if (decoder->norm == V4L2_STD_ALL) 1080cb7a01acSMauro Carvalho Chehab std = tvp5150_read_std(sd); 1081cb7a01acSMauro Carvalho Chehab else 1082cb7a01acSMauro Carvalho Chehab std = decoder->norm; 1083cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_525_60) 108410d5509cSHans Verkuil sel->r.height = TVP5150_V_MAX_525_60; 1085cb7a01acSMauro Carvalho Chehab else 108610d5509cSHans Verkuil sel->r.height = TVP5150_V_MAX_OTHERS; 1087cb7a01acSMauro Carvalho Chehab return 0; 108810d5509cSHans Verkuil case V4L2_SEL_TGT_CROP: 108910d5509cSHans Verkuil sel->r = decoder->rect; 109010d5509cSHans Verkuil return 0; 109110d5509cSHans Verkuil default: 109210d5509cSHans Verkuil return -EINVAL; 109310d5509cSHans Verkuil } 1094cb7a01acSMauro Carvalho Chehab } 1095cb7a01acSMauro Carvalho Chehab 1096dd3a46bbSLaurent Pinchart static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, 1097dd3a46bbSLaurent Pinchart struct v4l2_mbus_config *cfg) 1098dd3a46bbSLaurent Pinchart { 1099a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1100a2e5f1b3SJavier Martinez Canillas 1101a2e5f1b3SJavier Martinez Canillas cfg->type = decoder->mbus_type; 1102dd3a46bbSLaurent Pinchart cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING 1103dd3a46bbSLaurent Pinchart | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; 1104dd3a46bbSLaurent Pinchart 1105dd3a46bbSLaurent Pinchart return 0; 1106dd3a46bbSLaurent Pinchart } 1107dd3a46bbSLaurent Pinchart 1108cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1109e545ac87SLaurent Pinchart V4L2 subdev pad ops 1110e545ac87SLaurent Pinchart ****************************************************************************/ 1111b440b733SPhilipp Zabel static int tvp5150_init_cfg(struct v4l2_subdev *sd, 1112b440b733SPhilipp Zabel struct v4l2_subdev_pad_config *cfg) 1113b440b733SPhilipp Zabel { 1114b440b733SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 1115b440b733SPhilipp Zabel v4l2_std_id std; 1116b440b733SPhilipp Zabel 1117b440b733SPhilipp Zabel /* 1118b440b733SPhilipp Zabel * Reset selection to maximum on subdev_open() if autodetection is on 1119b440b733SPhilipp Zabel * and a standard change is detected. 1120b440b733SPhilipp Zabel */ 1121b440b733SPhilipp Zabel if (decoder->norm == V4L2_STD_ALL) { 1122b440b733SPhilipp Zabel std = tvp5150_read_std(sd); 1123b440b733SPhilipp Zabel if (std != decoder->detected_norm) { 1124b440b733SPhilipp Zabel decoder->detected_norm = std; 1125b440b733SPhilipp Zabel tvp5150_set_default(std, &decoder->rect); 1126b440b733SPhilipp Zabel } 1127b440b733SPhilipp Zabel } 1128b440b733SPhilipp Zabel 1129b440b733SPhilipp Zabel return 0; 1130b440b733SPhilipp Zabel } 1131b440b733SPhilipp Zabel 1132e545ac87SLaurent Pinchart static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, 1133e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 1134e545ac87SLaurent Pinchart struct v4l2_subdev_mbus_code_enum *code) 1135e545ac87SLaurent Pinchart { 1136e545ac87SLaurent Pinchart if (code->pad || code->index) 1137e545ac87SLaurent Pinchart return -EINVAL; 1138e545ac87SLaurent Pinchart 11395cb82940SMarco Felsch code->code = TVP5150_MBUS_FMT; 1140e545ac87SLaurent Pinchart return 0; 1141e545ac87SLaurent Pinchart } 1142e545ac87SLaurent Pinchart 1143e545ac87SLaurent Pinchart static int tvp5150_enum_frame_size(struct v4l2_subdev *sd, 1144e545ac87SLaurent Pinchart struct v4l2_subdev_pad_config *cfg, 1145e545ac87SLaurent Pinchart struct v4l2_subdev_frame_size_enum *fse) 1146e545ac87SLaurent Pinchart { 1147e545ac87SLaurent Pinchart struct tvp5150 *decoder = to_tvp5150(sd); 1148e545ac87SLaurent Pinchart 11495cb82940SMarco Felsch if (fse->index >= 8 || fse->code != TVP5150_MBUS_FMT) 1150e545ac87SLaurent Pinchart return -EINVAL; 1151e545ac87SLaurent Pinchart 11525cb82940SMarco Felsch fse->code = TVP5150_MBUS_FMT; 1153e545ac87SLaurent Pinchart fse->min_width = decoder->rect.width; 1154e545ac87SLaurent Pinchart fse->max_width = decoder->rect.width; 1155e545ac87SLaurent Pinchart fse->min_height = decoder->rect.height / 2; 1156e545ac87SLaurent Pinchart fse->max_height = decoder->rect.height / 2; 1157e545ac87SLaurent Pinchart 1158e545ac87SLaurent Pinchart return 0; 1159e545ac87SLaurent Pinchart } 1160e545ac87SLaurent Pinchart 1161e545ac87SLaurent Pinchart /**************************************************************************** 1162f7b4b54eSJavier Martinez Canillas Media entity ops 1163f7b4b54eSJavier Martinez Canillas ****************************************************************************/ 1164f7b4b54eSJavier Martinez Canillas 1165406ff67dSLaurent Pinchart #ifdef CONFIG_MEDIA_CONTROLLER 1166f7b4b54eSJavier Martinez Canillas static int tvp5150_link_setup(struct media_entity *entity, 1167f7b4b54eSJavier Martinez Canillas const struct media_pad *local, 1168f7b4b54eSJavier Martinez Canillas const struct media_pad *remote, u32 flags) 1169f7b4b54eSJavier Martinez Canillas { 1170f7b4b54eSJavier Martinez Canillas struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 1171f7b4b54eSJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1172f7b4b54eSJavier Martinez Canillas int i; 1173f7b4b54eSJavier Martinez Canillas 1174f7b4b54eSJavier Martinez Canillas for (i = 0; i < TVP5150_INPUT_NUM; i++) { 1175f7b4b54eSJavier Martinez Canillas if (remote->entity == &decoder->input_ent[i]) 1176f7b4b54eSJavier Martinez Canillas break; 1177f7b4b54eSJavier Martinez Canillas } 1178f7b4b54eSJavier Martinez Canillas 1179f7b4b54eSJavier Martinez Canillas /* Do nothing for entities that are not input connectors */ 1180f7b4b54eSJavier Martinez Canillas if (i == TVP5150_INPUT_NUM) 1181f7b4b54eSJavier Martinez Canillas return 0; 1182f7b4b54eSJavier Martinez Canillas 1183f7b4b54eSJavier Martinez Canillas decoder->input = i; 1184f7b4b54eSJavier Martinez Canillas 1185f7b4b54eSJavier Martinez Canillas tvp5150_selmux(sd); 1186f7b4b54eSJavier Martinez Canillas 1187f7b4b54eSJavier Martinez Canillas return 0; 1188f7b4b54eSJavier Martinez Canillas } 1189f7b4b54eSJavier Martinez Canillas 1190f7b4b54eSJavier Martinez Canillas static const struct media_entity_operations tvp5150_sd_media_ops = { 1191f7b4b54eSJavier Martinez Canillas .link_setup = tvp5150_link_setup, 1192f7b4b54eSJavier Martinez Canillas }; 1193406ff67dSLaurent Pinchart #endif 1194f7b4b54eSJavier Martinez Canillas 1195f7b4b54eSJavier Martinez Canillas /**************************************************************************** 1196cb7a01acSMauro Carvalho Chehab I2C Command 1197cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1198cb7a01acSMauro Carvalho Chehab 1199460b6c08SLaurent Pinchart static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) 1200460b6c08SLaurent Pinchart { 1201a2e5f1b3SJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 12028e4c97e0SPhilipp Zabel unsigned int mask, val = 0, int_val = 0; 1203a2e5f1b3SJavier Martinez Canillas 12048a7441baSMarco Felsch mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE | 12058a7441baSMarco Felsch TVP5150_MISC_CTL_CLOCK_OE; 120679d6205aSLaurent Pinchart 120779d6205aSLaurent Pinchart if (enable) { 12081bb086bcSPhilipp Zabel tvp5150_enable(sd); 12091bb086bcSPhilipp Zabel 121062a764e1SPhilipp Zabel /* Enable outputs if decoder is locked */ 121162a764e1SPhilipp Zabel val = decoder->lock ? decoder->oe : 0; 12128e4c97e0SPhilipp Zabel int_val = TVP5150_INT_A_LOCK; 12132f0a5c65SPhilipp Zabel v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt); 121479d6205aSLaurent Pinchart } 1215a2e5f1b3SJavier Martinez Canillas 12168a7441baSMarco Felsch regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val); 12178e4c97e0SPhilipp Zabel if (decoder->irq) 12188e4c97e0SPhilipp Zabel /* Enable / Disable lock interrupt */ 12198e4c97e0SPhilipp Zabel regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A, 12208e4c97e0SPhilipp Zabel TVP5150_INT_A_LOCK, int_val); 1221460b6c08SLaurent Pinchart 1222460b6c08SLaurent Pinchart return 0; 1223460b6c08SLaurent Pinchart } 1224460b6c08SLaurent Pinchart 1225cb7a01acSMauro Carvalho Chehab static int tvp5150_s_routing(struct v4l2_subdev *sd, 1226cb7a01acSMauro Carvalho Chehab u32 input, u32 output, u32 config) 1227cb7a01acSMauro Carvalho Chehab { 1228cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1229cb7a01acSMauro Carvalho Chehab 1230cb7a01acSMauro Carvalho Chehab decoder->input = input; 1231cb7a01acSMauro Carvalho Chehab decoder->output = output; 1232c43875f6SMauro Carvalho Chehab 1233c43875f6SMauro Carvalho Chehab if (output == TVP5150_BLACK_SCREEN) 1234c43875f6SMauro Carvalho Chehab decoder->enable = false; 1235c43875f6SMauro Carvalho Chehab else 1236c43875f6SMauro Carvalho Chehab decoder->enable = true; 1237c43875f6SMauro Carvalho Chehab 1238cb7a01acSMauro Carvalho Chehab tvp5150_selmux(sd); 1239cb7a01acSMauro Carvalho Chehab return 0; 1240cb7a01acSMauro Carvalho Chehab } 1241cb7a01acSMauro Carvalho Chehab 1242cb7a01acSMauro Carvalho Chehab static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) 1243cb7a01acSMauro Carvalho Chehab { 124428b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 124528b9e227SPhilipp Zabel 12469bfd8f88SNasser Afshin /* 12479bfd8f88SNasser Afshin * this is for capturing 36 raw vbi lines 12489bfd8f88SNasser Afshin * if there's a way to cut off the beginning 2 vbi lines 12499bfd8f88SNasser Afshin * with the tvp5150 then the vbi line count could be lowered 12509bfd8f88SNasser Afshin * to 17 lines/field again, although I couldn't find a register 12519bfd8f88SNasser Afshin * which could do that cropping 12529bfd8f88SNasser Afshin */ 12539bfd8f88SNasser Afshin 1254cb7a01acSMauro Carvalho Chehab if (fmt->sample_format == V4L2_PIX_FMT_GREY) 125528b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_LUMA_PROC_CTL_1, 0x70); 1256cb7a01acSMauro Carvalho Chehab if (fmt->count[0] == 18 && fmt->count[1] == 18) { 125728b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, 125828b9e227SPhilipp Zabel 0x00); 125928b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, 0x01); 1260cb7a01acSMauro Carvalho Chehab } 1261cb7a01acSMauro Carvalho Chehab return 0; 1262cb7a01acSMauro Carvalho Chehab } 1263cb7a01acSMauro Carvalho Chehab 1264cb7a01acSMauro Carvalho Chehab static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1265cb7a01acSMauro Carvalho Chehab { 126628b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 1267cb7a01acSMauro Carvalho Chehab int i; 1268cb7a01acSMauro Carvalho Chehab 1269cb7a01acSMauro Carvalho Chehab if (svbi->service_set != 0) { 1270cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1271cb7a01acSMauro Carvalho Chehab svbi->service_lines[1][i] = 0; 1272cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 12733dd6b560SMauro Carvalho Chehab tvp5150_set_vbi(sd, svbi->service_lines[0][i], 12743dd6b560SMauro Carvalho Chehab 0xf0, i, 3); 1275cb7a01acSMauro Carvalho Chehab } 1276cb7a01acSMauro Carvalho Chehab /* Enables FIFO */ 127728b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 1); 1278cb7a01acSMauro Carvalho Chehab } else { 1279cb7a01acSMauro Carvalho Chehab /* Disables FIFO*/ 128028b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 0); 1281cb7a01acSMauro Carvalho Chehab 1282cb7a01acSMauro Carvalho Chehab /* Disable Full Field */ 128328b9e227SPhilipp Zabel regmap_write(decoder->regmap, TVP5150_FULL_FIELD_ENA, 0); 1284cb7a01acSMauro Carvalho Chehab 1285cb7a01acSMauro Carvalho Chehab /* Disable Line modes */ 1286cb7a01acSMauro Carvalho Chehab for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++) 128728b9e227SPhilipp Zabel regmap_write(decoder->regmap, i, 0xff); 1288cb7a01acSMauro Carvalho Chehab } 1289cb7a01acSMauro Carvalho Chehab return 0; 1290cb7a01acSMauro Carvalho Chehab } 1291cb7a01acSMauro Carvalho Chehab 1292cb7a01acSMauro Carvalho Chehab static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) 1293cb7a01acSMauro Carvalho Chehab { 1294cb7a01acSMauro Carvalho Chehab int i, mask = 0; 1295cb7a01acSMauro Carvalho Chehab 129630634e8eSHans Verkuil memset(svbi->service_lines, 0, sizeof(svbi->service_lines)); 1297cb7a01acSMauro Carvalho Chehab 1298cb7a01acSMauro Carvalho Chehab for (i = 0; i <= 23; i++) { 1299cb7a01acSMauro Carvalho Chehab svbi->service_lines[0][i] = 13003dd6b560SMauro Carvalho Chehab tvp5150_get_vbi(sd, i); 1301cb7a01acSMauro Carvalho Chehab mask |= svbi->service_lines[0][i]; 1302cb7a01acSMauro Carvalho Chehab } 1303cb7a01acSMauro Carvalho Chehab svbi->service_set = mask; 1304cb7a01acSMauro Carvalho Chehab return 0; 1305cb7a01acSMauro Carvalho Chehab } 1306cb7a01acSMauro Carvalho Chehab 1307cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1308cb7a01acSMauro Carvalho Chehab static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 1309cb7a01acSMauro Carvalho Chehab { 1310cb7a01acSMauro Carvalho Chehab int res; 1311cb7a01acSMauro Carvalho Chehab 1312cb7a01acSMauro Carvalho Chehab res = tvp5150_read(sd, reg->reg & 0xff); 1313cb7a01acSMauro Carvalho Chehab if (res < 0) { 1314257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "%s: failed with error = %d\n", __func__, res); 1315cb7a01acSMauro Carvalho Chehab return res; 1316cb7a01acSMauro Carvalho Chehab } 1317cb7a01acSMauro Carvalho Chehab 1318cb7a01acSMauro Carvalho Chehab reg->val = res; 1319cb7a01acSMauro Carvalho Chehab reg->size = 1; 1320cb7a01acSMauro Carvalho Chehab return 0; 1321cb7a01acSMauro Carvalho Chehab } 1322cb7a01acSMauro Carvalho Chehab 1323977ba3b1SHans Verkuil static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 1324cb7a01acSMauro Carvalho Chehab { 132528b9e227SPhilipp Zabel struct tvp5150 *decoder = to_tvp5150(sd); 132628b9e227SPhilipp Zabel 132728b9e227SPhilipp Zabel return regmap_write(decoder->regmap, reg->reg & 0xff, reg->val & 0xff); 1328cb7a01acSMauro Carvalho Chehab } 1329cb7a01acSMauro Carvalho Chehab #endif 1330cb7a01acSMauro Carvalho Chehab 1331cb7a01acSMauro Carvalho Chehab static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) 1332cb7a01acSMauro Carvalho Chehab { 1333cb7a01acSMauro Carvalho Chehab int status = tvp5150_read(sd, 0x88); 1334cb7a01acSMauro Carvalho Chehab 1335cb7a01acSMauro Carvalho Chehab vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0; 1336cb7a01acSMauro Carvalho Chehab return 0; 1337cb7a01acSMauro Carvalho Chehab } 1338cb7a01acSMauro Carvalho Chehab 13395a08bc00SJavier Martinez Canillas static int tvp5150_registered(struct v4l2_subdev *sd) 1340f7b4b54eSJavier Martinez Canillas { 1341f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1342f7b4b54eSJavier Martinez Canillas struct tvp5150 *decoder = to_tvp5150(sd); 1343f7b4b54eSJavier Martinez Canillas int ret = 0; 1344f7b4b54eSJavier Martinez Canillas int i; 1345f7b4b54eSJavier Martinez Canillas 1346f7b4b54eSJavier Martinez Canillas for (i = 0; i < TVP5150_INPUT_NUM; i++) { 1347f7b4b54eSJavier Martinez Canillas struct media_entity *input = &decoder->input_ent[i]; 1348f7b4b54eSJavier Martinez Canillas struct media_pad *pad = &decoder->input_pad[i]; 1349f7b4b54eSJavier Martinez Canillas 1350f7b4b54eSJavier Martinez Canillas if (!input->name) 1351f7b4b54eSJavier Martinez Canillas continue; 1352f7b4b54eSJavier Martinez Canillas 1353f7b4b54eSJavier Martinez Canillas decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE; 1354f7b4b54eSJavier Martinez Canillas 1355f7b4b54eSJavier Martinez Canillas ret = media_entity_pads_init(input, 1, pad); 1356f7b4b54eSJavier Martinez Canillas if (ret < 0) 1357f7b4b54eSJavier Martinez Canillas return ret; 1358f7b4b54eSJavier Martinez Canillas 1359f7b4b54eSJavier Martinez Canillas ret = media_device_register_entity(sd->v4l2_dev->mdev, input); 1360f7b4b54eSJavier Martinez Canillas if (ret < 0) 1361f7b4b54eSJavier Martinez Canillas return ret; 1362f7b4b54eSJavier Martinez Canillas 1363f7b4b54eSJavier Martinez Canillas ret = media_create_pad_link(input, 0, &sd->entity, 1364bc322c0dSMauro Carvalho Chehab TVP5150_PAD_IF_INPUT, 0); 1365f7b4b54eSJavier Martinez Canillas if (ret < 0) { 1366f7b4b54eSJavier Martinez Canillas media_device_unregister_entity(input); 1367f7b4b54eSJavier Martinez Canillas return ret; 1368f7b4b54eSJavier Martinez Canillas } 1369f7b4b54eSJavier Martinez Canillas } 1370f7b4b54eSJavier Martinez Canillas #endif 1371f7b4b54eSJavier Martinez Canillas 1372f7b4b54eSJavier Martinez Canillas return 0; 1373f7b4b54eSJavier Martinez Canillas } 1374f7b4b54eSJavier Martinez Canillas 1375cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1376cb7a01acSMauro Carvalho Chehab 1377cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { 1378cb7a01acSMauro Carvalho Chehab .s_ctrl = tvp5150_s_ctrl, 1379cb7a01acSMauro Carvalho Chehab }; 1380cb7a01acSMauro Carvalho Chehab 1381cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tvp5150_core_ops = { 1382cb7a01acSMauro Carvalho Chehab .log_status = tvp5150_log_status, 1383cb7a01acSMauro Carvalho Chehab .reset = tvp5150_reset, 1384cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG 1385cb7a01acSMauro Carvalho Chehab .g_register = tvp5150_g_register, 1386cb7a01acSMauro Carvalho Chehab .s_register = tvp5150_s_register, 1387cb7a01acSMauro Carvalho Chehab #endif 1388cb7a01acSMauro Carvalho Chehab }; 1389cb7a01acSMauro Carvalho Chehab 1390cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { 1391cb7a01acSMauro Carvalho Chehab .g_tuner = tvp5150_g_tuner, 1392cb7a01acSMauro Carvalho Chehab }; 1393cb7a01acSMauro Carvalho Chehab 1394cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tvp5150_video_ops = { 13958774bed9SLaurent Pinchart .s_std = tvp5150_s_std, 13960db87cc7SMarco Felsch .g_std = tvp5150_g_std, 1397ee9a6ff6SPhilipp Zabel .querystd = tvp5150_querystd, 1398460b6c08SLaurent Pinchart .s_stream = tvp5150_s_stream, 1399cb7a01acSMauro Carvalho Chehab .s_routing = tvp5150_s_routing, 1400dd3a46bbSLaurent Pinchart .g_mbus_config = tvp5150_g_mbus_config, 1401cb7a01acSMauro Carvalho Chehab }; 1402cb7a01acSMauro Carvalho Chehab 1403cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { 1404cb7a01acSMauro Carvalho Chehab .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap, 1405cb7a01acSMauro Carvalho Chehab .g_sliced_fmt = tvp5150_g_sliced_fmt, 1406cb7a01acSMauro Carvalho Chehab .s_sliced_fmt = tvp5150_s_sliced_fmt, 1407cb7a01acSMauro Carvalho Chehab .s_raw_fmt = tvp5150_s_raw_fmt, 1408cb7a01acSMauro Carvalho Chehab }; 1409cb7a01acSMauro Carvalho Chehab 1410ebcff5fcSHans Verkuil static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { 1411b440b733SPhilipp Zabel .init_cfg = tvp5150_init_cfg, 1412ebcff5fcSHans Verkuil .enum_mbus_code = tvp5150_enum_mbus_code, 1413e545ac87SLaurent Pinchart .enum_frame_size = tvp5150_enum_frame_size, 1414da298c6dSHans Verkuil .set_fmt = tvp5150_fill_fmt, 1415da298c6dSHans Verkuil .get_fmt = tvp5150_fill_fmt, 141610d5509cSHans Verkuil .get_selection = tvp5150_get_selection, 141710d5509cSHans Verkuil .set_selection = tvp5150_set_selection, 1418ebcff5fcSHans Verkuil }; 1419ebcff5fcSHans Verkuil 1420cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tvp5150_ops = { 1421cb7a01acSMauro Carvalho Chehab .core = &tvp5150_core_ops, 1422cb7a01acSMauro Carvalho Chehab .tuner = &tvp5150_tuner_ops, 1423cb7a01acSMauro Carvalho Chehab .video = &tvp5150_video_ops, 1424cb7a01acSMauro Carvalho Chehab .vbi = &tvp5150_vbi_ops, 1425ebcff5fcSHans Verkuil .pad = &tvp5150_pad_ops, 1426cb7a01acSMauro Carvalho Chehab }; 1427cb7a01acSMauro Carvalho Chehab 14285a08bc00SJavier Martinez Canillas static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = { 14295a08bc00SJavier Martinez Canillas .registered = tvp5150_registered, 14305a08bc00SJavier Martinez Canillas }; 14315a08bc00SJavier Martinez Canillas 1432cb7a01acSMauro Carvalho Chehab /**************************************************************************** 1433cb7a01acSMauro Carvalho Chehab I2C Client & Driver 1434cb7a01acSMauro Carvalho Chehab ****************************************************************************/ 1435cb7a01acSMauro Carvalho Chehab 143628b9e227SPhilipp Zabel static const struct regmap_range tvp5150_readable_ranges[] = { 143728b9e227SPhilipp Zabel { 143828b9e227SPhilipp Zabel .range_min = TVP5150_VD_IN_SRC_SEL_1, 143928b9e227SPhilipp Zabel .range_max = TVP5150_AUTOSW_MSK, 144028b9e227SPhilipp Zabel }, { 144128b9e227SPhilipp Zabel .range_min = TVP5150_COLOR_KIL_THSH_CTL, 144228b9e227SPhilipp Zabel .range_max = TVP5150_CONF_SHARED_PIN, 144328b9e227SPhilipp Zabel }, { 144428b9e227SPhilipp Zabel .range_min = TVP5150_ACT_VD_CROP_ST_MSB, 144528b9e227SPhilipp Zabel .range_max = TVP5150_HORIZ_SYNC_START, 144628b9e227SPhilipp Zabel }, { 144728b9e227SPhilipp Zabel .range_min = TVP5150_VERT_BLANKING_START, 144828b9e227SPhilipp Zabel .range_max = TVP5150_INTT_CONFIG_REG_B, 144928b9e227SPhilipp Zabel }, { 145028b9e227SPhilipp Zabel .range_min = TVP5150_VIDEO_STD, 145128b9e227SPhilipp Zabel .range_max = TVP5150_VIDEO_STD, 145228b9e227SPhilipp Zabel }, { 145328b9e227SPhilipp Zabel .range_min = TVP5150_CB_GAIN_FACT, 145428b9e227SPhilipp Zabel .range_max = TVP5150_REV_SELECT, 145528b9e227SPhilipp Zabel }, { 145628b9e227SPhilipp Zabel .range_min = TVP5150_MSB_DEV_ID, 145728b9e227SPhilipp Zabel .range_max = TVP5150_STATUS_REG_5, 145828b9e227SPhilipp Zabel }, { 145928b9e227SPhilipp Zabel .range_min = TVP5150_CC_DATA_INI, 146028b9e227SPhilipp Zabel .range_max = TVP5150_TELETEXT_FIL_ENA, 146128b9e227SPhilipp Zabel }, { 146228b9e227SPhilipp Zabel .range_min = TVP5150_INT_STATUS_REG_A, 146328b9e227SPhilipp Zabel .range_max = TVP5150_FIFO_OUT_CTRL, 146428b9e227SPhilipp Zabel }, { 146528b9e227SPhilipp Zabel .range_min = TVP5150_FULL_FIELD_ENA, 146628b9e227SPhilipp Zabel .range_max = TVP5150_FULL_FIELD_MODE_REG, 146728b9e227SPhilipp Zabel }, 146828b9e227SPhilipp Zabel }; 146928b9e227SPhilipp Zabel 147028b9e227SPhilipp Zabel bool tvp5150_volatile_reg(struct device *dev, unsigned int reg) 147128b9e227SPhilipp Zabel { 147228b9e227SPhilipp Zabel switch (reg) { 147328b9e227SPhilipp Zabel case TVP5150_VERT_LN_COUNT_MSB: 147428b9e227SPhilipp Zabel case TVP5150_VERT_LN_COUNT_LSB: 147528b9e227SPhilipp Zabel case TVP5150_INT_STATUS_REG_A: 147628b9e227SPhilipp Zabel case TVP5150_INT_STATUS_REG_B: 147728b9e227SPhilipp Zabel case TVP5150_INT_ACTIVE_REG_B: 147828b9e227SPhilipp Zabel case TVP5150_STATUS_REG_1: 147928b9e227SPhilipp Zabel case TVP5150_STATUS_REG_2: 148028b9e227SPhilipp Zabel case TVP5150_STATUS_REG_3: 148128b9e227SPhilipp Zabel case TVP5150_STATUS_REG_4: 148228b9e227SPhilipp Zabel case TVP5150_STATUS_REG_5: 148328b9e227SPhilipp Zabel /* CC, WSS, VPS, VITC data? */ 148428b9e227SPhilipp Zabel case TVP5150_VBI_FIFO_READ_DATA: 148528b9e227SPhilipp Zabel case TVP5150_VDP_STATUS_REG: 148628b9e227SPhilipp Zabel case TVP5150_FIFO_WORD_COUNT: 148728b9e227SPhilipp Zabel return true; 148828b9e227SPhilipp Zabel default: 148928b9e227SPhilipp Zabel return false; 149028b9e227SPhilipp Zabel } 149128b9e227SPhilipp Zabel } 149228b9e227SPhilipp Zabel 149328b9e227SPhilipp Zabel static const struct regmap_access_table tvp5150_readable_table = { 149428b9e227SPhilipp Zabel .yes_ranges = tvp5150_readable_ranges, 149528b9e227SPhilipp Zabel .n_yes_ranges = ARRAY_SIZE(tvp5150_readable_ranges), 149628b9e227SPhilipp Zabel }; 149728b9e227SPhilipp Zabel 149828b9e227SPhilipp Zabel static struct regmap_config tvp5150_config = { 149928b9e227SPhilipp Zabel .reg_bits = 8, 150028b9e227SPhilipp Zabel .val_bits = 8, 150128b9e227SPhilipp Zabel .max_register = 0xff, 150228b9e227SPhilipp Zabel 150328b9e227SPhilipp Zabel .cache_type = REGCACHE_RBTREE, 150428b9e227SPhilipp Zabel 150528b9e227SPhilipp Zabel .rd_table = &tvp5150_readable_table, 150628b9e227SPhilipp Zabel .volatile_reg = tvp5150_volatile_reg, 150728b9e227SPhilipp Zabel }; 150828b9e227SPhilipp Zabel 15097871597aSLaurent Pinchart static int tvp5150_detect_version(struct tvp5150 *core) 15107871597aSLaurent Pinchart { 15117871597aSLaurent Pinchart struct v4l2_subdev *sd = &core->sd; 15127871597aSLaurent Pinchart struct i2c_client *c = v4l2_get_subdevdata(sd); 15137871597aSLaurent Pinchart u8 regs[4]; 15147871597aSLaurent Pinchart int res; 15157871597aSLaurent Pinchart 15167871597aSLaurent Pinchart /* 15177871597aSLaurent Pinchart * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID, 15187871597aSLaurent Pinchart * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 15197871597aSLaurent Pinchart */ 152028b9e227SPhilipp Zabel res = regmap_bulk_read(core->regmap, TVP5150_MSB_DEV_ID, regs, 4); 152128b9e227SPhilipp Zabel if (res < 0) { 152228b9e227SPhilipp Zabel dev_err(&c->dev, "reading ID registers failed: %d\n", res); 15237871597aSLaurent Pinchart return res; 15247871597aSLaurent Pinchart } 15257871597aSLaurent Pinchart 152682275133SJavier Martinez Canillas core->dev_id = (regs[0] << 8) | regs[1]; 152782275133SJavier Martinez Canillas core->rom_ver = (regs[2] << 8) | regs[3]; 15287871597aSLaurent Pinchart 1529257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n", 153082275133SJavier Martinez Canillas core->dev_id, regs[2], regs[3], c->addr << 1, 153182275133SJavier Martinez Canillas c->adapter->name); 15327871597aSLaurent Pinchart 153382275133SJavier Martinez Canillas if (core->dev_id == 0x5150 && core->rom_ver == 0x0321) { 1534257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5150a detected.\n"); 153582275133SJavier Martinez Canillas } else if (core->dev_id == 0x5150 && core->rom_ver == 0x0400) { 1536257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5150am1 detected.\n"); 15377871597aSLaurent Pinchart 15387871597aSLaurent Pinchart /* ITU-T BT.656.4 timing */ 153928b9e227SPhilipp Zabel regmap_write(core->regmap, TVP5150_REV_SELECT, 0); 154082275133SJavier Martinez Canillas } else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) { 1541257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "tvp5151 detected.\n"); 15427871597aSLaurent Pinchart } else { 1543257e29f8SMauro Carvalho Chehab dev_info(sd->dev, "*** unknown tvp%04x chip detected.\n", 154482275133SJavier Martinez Canillas core->dev_id); 15457871597aSLaurent Pinchart } 15467871597aSLaurent Pinchart 15477871597aSLaurent Pinchart return 0; 15487871597aSLaurent Pinchart } 15497871597aSLaurent Pinchart 155009aa2609SJavier Martinez Canillas static int tvp5150_init(struct i2c_client *c) 155109aa2609SJavier Martinez Canillas { 155209aa2609SJavier Martinez Canillas struct gpio_desc *pdn_gpio; 155309aa2609SJavier Martinez Canillas struct gpio_desc *reset_gpio; 155409aa2609SJavier Martinez Canillas 155509aa2609SJavier Martinez Canillas pdn_gpio = devm_gpiod_get_optional(&c->dev, "pdn", GPIOD_OUT_HIGH); 155609aa2609SJavier Martinez Canillas if (IS_ERR(pdn_gpio)) 155709aa2609SJavier Martinez Canillas return PTR_ERR(pdn_gpio); 155809aa2609SJavier Martinez Canillas 155909aa2609SJavier Martinez Canillas if (pdn_gpio) { 156009aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(pdn_gpio, 0); 156109aa2609SJavier Martinez Canillas /* Delay time between power supplies active and reset */ 156209aa2609SJavier Martinez Canillas msleep(20); 156309aa2609SJavier Martinez Canillas } 156409aa2609SJavier Martinez Canillas 156509aa2609SJavier Martinez Canillas reset_gpio = devm_gpiod_get_optional(&c->dev, "reset", GPIOD_OUT_HIGH); 156609aa2609SJavier Martinez Canillas if (IS_ERR(reset_gpio)) 156709aa2609SJavier Martinez Canillas return PTR_ERR(reset_gpio); 156809aa2609SJavier Martinez Canillas 156909aa2609SJavier Martinez Canillas if (reset_gpio) { 157009aa2609SJavier Martinez Canillas /* RESETB pulse duration */ 157109aa2609SJavier Martinez Canillas ndelay(500); 157209aa2609SJavier Martinez Canillas gpiod_set_value_cansleep(reset_gpio, 0); 157309aa2609SJavier Martinez Canillas /* Delay time between end of reset to I2C active */ 157409aa2609SJavier Martinez Canillas usleep_range(200, 250); 157509aa2609SJavier Martinez Canillas } 157609aa2609SJavier Martinez Canillas 157709aa2609SJavier Martinez Canillas return 0; 157809aa2609SJavier Martinez Canillas } 157909aa2609SJavier Martinez Canillas 1580a2e5f1b3SJavier Martinez Canillas static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) 1581a2e5f1b3SJavier Martinez Canillas { 1582859969b3SSakari Ailus struct v4l2_fwnode_endpoint bus_cfg; 1583a2e5f1b3SJavier Martinez Canillas struct device_node *ep; 1584f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1585f7b4b54eSJavier Martinez Canillas struct device_node *connectors, *child; 1586f7b4b54eSJavier Martinez Canillas struct media_entity *input; 1587f7b4b54eSJavier Martinez Canillas const char *name; 1588f7b4b54eSJavier Martinez Canillas u32 input_type; 1589f7b4b54eSJavier Martinez Canillas #endif 1590a2e5f1b3SJavier Martinez Canillas unsigned int flags; 1591a2e5f1b3SJavier Martinez Canillas int ret = 0; 1592a2e5f1b3SJavier Martinez Canillas 1593a2e5f1b3SJavier Martinez Canillas ep = of_graph_get_next_endpoint(np, NULL); 1594a2e5f1b3SJavier Martinez Canillas if (!ep) 1595a2e5f1b3SJavier Martinez Canillas return -EINVAL; 1596a2e5f1b3SJavier Martinez Canillas 1597859969b3SSakari Ailus ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); 1598a2e5f1b3SJavier Martinez Canillas if (ret) 1599a2e5f1b3SJavier Martinez Canillas goto err; 1600a2e5f1b3SJavier Martinez Canillas 1601a2e5f1b3SJavier Martinez Canillas flags = bus_cfg.bus.parallel.flags; 1602a2e5f1b3SJavier Martinez Canillas 1603a2e5f1b3SJavier Martinez Canillas if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL && 1604a2e5f1b3SJavier Martinez Canillas !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH && 1605a2e5f1b3SJavier Martinez Canillas flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH && 16062bd5e437SJavier Martinez Canillas flags & V4L2_MBUS_FIELD_EVEN_LOW)) { 16072bd5e437SJavier Martinez Canillas ret = -EINVAL; 16082bd5e437SJavier Martinez Canillas goto err; 16092bd5e437SJavier Martinez Canillas } 1610a2e5f1b3SJavier Martinez Canillas 1611a2e5f1b3SJavier Martinez Canillas decoder->mbus_type = bus_cfg.bus_type; 1612a2e5f1b3SJavier Martinez Canillas 1613f7b4b54eSJavier Martinez Canillas #ifdef CONFIG_MEDIA_CONTROLLER 1614f7b4b54eSJavier Martinez Canillas connectors = of_get_child_by_name(np, "connectors"); 1615f7b4b54eSJavier Martinez Canillas 1616f7b4b54eSJavier Martinez Canillas if (!connectors) 1617f7b4b54eSJavier Martinez Canillas goto err; 1618f7b4b54eSJavier Martinez Canillas 1619f7b4b54eSJavier Martinez Canillas for_each_available_child_of_node(connectors, child) { 1620f7b4b54eSJavier Martinez Canillas ret = of_property_read_u32(child, "input", &input_type); 1621f7b4b54eSJavier Martinez Canillas if (ret) { 1622257e29f8SMauro Carvalho Chehab dev_err(decoder->sd.dev, 1623f764e6d6SRob Herring "missing type property in node %pOFn\n", 1624f764e6d6SRob Herring child); 1625f7b4b54eSJavier Martinez Canillas goto err_connector; 1626f7b4b54eSJavier Martinez Canillas } 1627f7b4b54eSJavier Martinez Canillas 162860ad7689SMauro Carvalho Chehab if (input_type >= TVP5150_INPUT_NUM) { 1629f7b4b54eSJavier Martinez Canillas ret = -EINVAL; 1630f7b4b54eSJavier Martinez Canillas goto err_connector; 1631f7b4b54eSJavier Martinez Canillas } 1632f7b4b54eSJavier Martinez Canillas 1633f7b4b54eSJavier Martinez Canillas input = &decoder->input_ent[input_type]; 1634f7b4b54eSJavier Martinez Canillas 1635f7b4b54eSJavier Martinez Canillas /* Each input connector can only be defined once */ 1636f7b4b54eSJavier Martinez Canillas if (input->name) { 1637257e29f8SMauro Carvalho Chehab dev_err(decoder->sd.dev, 1638f7b4b54eSJavier Martinez Canillas "input %s with same type already exists\n", 1639f7b4b54eSJavier Martinez Canillas input->name); 1640f7b4b54eSJavier Martinez Canillas ret = -EINVAL; 1641f7b4b54eSJavier Martinez Canillas goto err_connector; 1642f7b4b54eSJavier Martinez Canillas } 1643f7b4b54eSJavier Martinez Canillas 1644f7b4b54eSJavier Martinez Canillas switch (input_type) { 1645f7b4b54eSJavier Martinez Canillas case TVP5150_COMPOSITE0: 1646f7b4b54eSJavier Martinez Canillas case TVP5150_COMPOSITE1: 1647f7b4b54eSJavier Martinez Canillas input->function = MEDIA_ENT_F_CONN_COMPOSITE; 1648f7b4b54eSJavier Martinez Canillas break; 1649f7b4b54eSJavier Martinez Canillas case TVP5150_SVIDEO: 1650f7b4b54eSJavier Martinez Canillas input->function = MEDIA_ENT_F_CONN_SVIDEO; 1651f7b4b54eSJavier Martinez Canillas break; 1652f7b4b54eSJavier Martinez Canillas } 1653f7b4b54eSJavier Martinez Canillas 1654f7b4b54eSJavier Martinez Canillas input->flags = MEDIA_ENT_FL_CONNECTOR; 1655f7b4b54eSJavier Martinez Canillas 1656f7b4b54eSJavier Martinez Canillas ret = of_property_read_string(child, "label", &name); 1657f7b4b54eSJavier Martinez Canillas if (ret < 0) { 1658257e29f8SMauro Carvalho Chehab dev_err(decoder->sd.dev, 1659f764e6d6SRob Herring "missing label property in node %pOFn\n", 1660f764e6d6SRob Herring child); 1661f7b4b54eSJavier Martinez Canillas goto err_connector; 1662f7b4b54eSJavier Martinez Canillas } 1663f7b4b54eSJavier Martinez Canillas 1664f7b4b54eSJavier Martinez Canillas input->name = name; 1665f7b4b54eSJavier Martinez Canillas } 1666f7b4b54eSJavier Martinez Canillas 1667f7b4b54eSJavier Martinez Canillas err_connector: 1668f7b4b54eSJavier Martinez Canillas of_node_put(connectors); 1669f7b4b54eSJavier Martinez Canillas #endif 1670a2e5f1b3SJavier Martinez Canillas err: 1671a2e5f1b3SJavier Martinez Canillas of_node_put(ep); 1672a2e5f1b3SJavier Martinez Canillas return ret; 1673a2e5f1b3SJavier Martinez Canillas } 1674a2e5f1b3SJavier Martinez Canillas 1675c43875f6SMauro Carvalho Chehab static const char * const tvp5150_test_patterns[2] = { 1676c43875f6SMauro Carvalho Chehab "Disabled", 1677c43875f6SMauro Carvalho Chehab "Black screen" 1678c43875f6SMauro Carvalho Chehab }; 1679c43875f6SMauro Carvalho Chehab 1680cb7a01acSMauro Carvalho Chehab static int tvp5150_probe(struct i2c_client *c, 1681cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1682cb7a01acSMauro Carvalho Chehab { 1683cb7a01acSMauro Carvalho Chehab struct tvp5150 *core; 1684cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 1685a2e5f1b3SJavier Martinez Canillas struct device_node *np = c->dev.of_node; 168628b9e227SPhilipp Zabel struct regmap *map; 16877871597aSLaurent Pinchart int res; 1688cb7a01acSMauro Carvalho Chehab 1689cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1690cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(c->adapter, 1691cb7a01acSMauro Carvalho Chehab I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 1692cb7a01acSMauro Carvalho Chehab return -EIO; 1693cb7a01acSMauro Carvalho Chehab 169409aa2609SJavier Martinez Canillas res = tvp5150_init(c); 169509aa2609SJavier Martinez Canillas if (res) 169609aa2609SJavier Martinez Canillas return res; 169709aa2609SJavier Martinez Canillas 1698c02b211dSLaurent Pinchart core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL); 1699c02b211dSLaurent Pinchart if (!core) 1700cb7a01acSMauro Carvalho Chehab return -ENOMEM; 1701a2e5f1b3SJavier Martinez Canillas 170228b9e227SPhilipp Zabel map = devm_regmap_init_i2c(c, &tvp5150_config); 170328b9e227SPhilipp Zabel if (IS_ERR(map)) 170428b9e227SPhilipp Zabel return PTR_ERR(map); 170528b9e227SPhilipp Zabel 170628b9e227SPhilipp Zabel core->regmap = map; 1707cb7a01acSMauro Carvalho Chehab sd = &core->sd; 1708a2e5f1b3SJavier Martinez Canillas 1709a2e5f1b3SJavier Martinez Canillas if (IS_ENABLED(CONFIG_OF) && np) { 1710a2e5f1b3SJavier Martinez Canillas res = tvp5150_parse_dt(core, np); 1711a2e5f1b3SJavier Martinez Canillas if (res) { 1712257e29f8SMauro Carvalho Chehab dev_err(sd->dev, "DT parsing error: %d\n", res); 1713a2e5f1b3SJavier Martinez Canillas return res; 1714a2e5f1b3SJavier Martinez Canillas } 1715a2e5f1b3SJavier Martinez Canillas } else { 1716a2e5f1b3SJavier Martinez Canillas /* Default to BT.656 embedded sync */ 1717a2e5f1b3SJavier Martinez Canillas core->mbus_type = V4L2_MBUS_BT656; 1718a2e5f1b3SJavier Martinez Canillas } 1719a2e5f1b3SJavier Martinez Canillas 1720cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); 17215a08bc00SJavier Martinez Canillas sd->internal_ops = &tvp5150_internal_ops; 1722e545ac87SLaurent Pinchart sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1723e545ac87SLaurent Pinchart 1724e545ac87SLaurent Pinchart #if defined(CONFIG_MEDIA_CONTROLLER) 1725bc322c0dSMauro Carvalho Chehab core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; 1726bc322c0dSMauro Carvalho Chehab core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG; 1727bc322c0dSMauro Carvalho Chehab core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; 1728bc322c0dSMauro Carvalho Chehab core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV; 1729f92c70adSMauro Carvalho Chehab 1730f92c70adSMauro Carvalho Chehab sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 1731f92c70adSMauro Carvalho Chehab 1732bc322c0dSMauro Carvalho Chehab res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads); 1733e545ac87SLaurent Pinchart if (res < 0) 1734e545ac87SLaurent Pinchart return res; 1735f7b4b54eSJavier Martinez Canillas 1736f7b4b54eSJavier Martinez Canillas sd->entity.ops = &tvp5150_sd_media_ops; 1737e545ac87SLaurent Pinchart #endif 1738cb7a01acSMauro Carvalho Chehab 17397871597aSLaurent Pinchart res = tvp5150_detect_version(core); 1740cb7a01acSMauro Carvalho Chehab if (res < 0) 1741c02b211dSLaurent Pinchart return res; 1742cb7a01acSMauro Carvalho Chehab 1743cb7a01acSMauro Carvalho Chehab core->norm = V4L2_STD_ALL; /* Default is autodetect */ 1744b440b733SPhilipp Zabel core->detected_norm = V4L2_STD_UNKNOWN; 1745cb7a01acSMauro Carvalho Chehab core->input = TVP5150_COMPOSITE1; 1746c43875f6SMauro Carvalho Chehab core->enable = true; 1747cb7a01acSMauro Carvalho Chehab 1748b1950b8dSLaurent Pinchart v4l2_ctrl_handler_init(&core->hdl, 5); 1749cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1750cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 1751cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1752cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 255, 1, 128); 1753cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1754cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, 0, 255, 1, 128); 1755cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1756cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, -128, 127, 1, 0); 1757b1950b8dSLaurent Pinchart v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, 1758b1950b8dSLaurent Pinchart V4L2_CID_PIXEL_RATE, 27000000, 1759b1950b8dSLaurent Pinchart 27000000, 1, 27000000); 1760c43875f6SMauro Carvalho Chehab v4l2_ctrl_new_std_menu_items(&core->hdl, &tvp5150_ctrl_ops, 1761c43875f6SMauro Carvalho Chehab V4L2_CID_TEST_PATTERN, 17625c4c4505SMauro Carvalho Chehab ARRAY_SIZE(tvp5150_test_patterns) - 1, 1763c43875f6SMauro Carvalho Chehab 0, 0, tvp5150_test_patterns); 1764cb7a01acSMauro Carvalho Chehab sd->ctrl_handler = &core->hdl; 1765cb7a01acSMauro Carvalho Chehab if (core->hdl.error) { 1766cb7a01acSMauro Carvalho Chehab res = core->hdl.error; 1767c7d97499SJavier Martinez Canillas goto err; 1768cb7a01acSMauro Carvalho Chehab } 1769cb7a01acSMauro Carvalho Chehab 17705cb82940SMarco Felsch tvp5150_set_default(tvp5150_read_std(sd), &core->rect); 1771cb7a01acSMauro Carvalho Chehab 17728e4c97e0SPhilipp Zabel core->irq = c->irq; 1773aff808e8SLaurent Pinchart tvp5150_reset(sd, 0); /* Calls v4l2_ctrl_handler_setup() */ 17748e4c97e0SPhilipp Zabel if (c->irq) { 17758e4c97e0SPhilipp Zabel res = devm_request_threaded_irq(&c->dev, c->irq, NULL, 17768e4c97e0SPhilipp Zabel tvp5150_isr, IRQF_TRIGGER_HIGH | 17778e4c97e0SPhilipp Zabel IRQF_ONESHOT, "tvp5150", core); 17788e4c97e0SPhilipp Zabel if (res) 17798e4c97e0SPhilipp Zabel return res; 17808e4c97e0SPhilipp Zabel } else { 17818e4c97e0SPhilipp Zabel core->lock = true; 17828e4c97e0SPhilipp Zabel } 1783aff808e8SLaurent Pinchart 1784c7d97499SJavier Martinez Canillas res = v4l2_async_register_subdev(sd); 1785c7d97499SJavier Martinez Canillas if (res < 0) 1786c7d97499SJavier Martinez Canillas goto err; 1787c7d97499SJavier Martinez Canillas 1788cb7a01acSMauro Carvalho Chehab if (debug > 1) 1789cb7a01acSMauro Carvalho Chehab tvp5150_log_status(sd); 1790cb7a01acSMauro Carvalho Chehab return 0; 1791c7d97499SJavier Martinez Canillas 1792c7d97499SJavier Martinez Canillas err: 1793c7d97499SJavier Martinez Canillas v4l2_ctrl_handler_free(&core->hdl); 1794c7d97499SJavier Martinez Canillas return res; 1795cb7a01acSMauro Carvalho Chehab } 1796cb7a01acSMauro Carvalho Chehab 1797cb7a01acSMauro Carvalho Chehab static int tvp5150_remove(struct i2c_client *c) 1798cb7a01acSMauro Carvalho Chehab { 1799cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(c); 1800cb7a01acSMauro Carvalho Chehab struct tvp5150 *decoder = to_tvp5150(sd); 1801cb7a01acSMauro Carvalho Chehab 1802257e29f8SMauro Carvalho Chehab dev_dbg_lvl(sd->dev, 1, debug, 1803cb7a01acSMauro Carvalho Chehab "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", 1804cb7a01acSMauro Carvalho Chehab c->addr << 1); 1805cb7a01acSMauro Carvalho Chehab 1806c7d97499SJavier Martinez Canillas v4l2_async_unregister_subdev(sd); 1807cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&decoder->hdl); 1808cb7a01acSMauro Carvalho Chehab return 0; 1809cb7a01acSMauro Carvalho Chehab } 1810cb7a01acSMauro Carvalho Chehab 1811cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 1812cb7a01acSMauro Carvalho Chehab 1813cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tvp5150_id[] = { 1814cb7a01acSMauro Carvalho Chehab { "tvp5150", 0 }, 1815cb7a01acSMauro Carvalho Chehab { } 1816cb7a01acSMauro Carvalho Chehab }; 1817cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tvp5150_id); 1818cb7a01acSMauro Carvalho Chehab 18197ef930a7SEduard Gavin #if IS_ENABLED(CONFIG_OF) 18207ef930a7SEduard Gavin static const struct of_device_id tvp5150_of_match[] = { 18217ef930a7SEduard Gavin { .compatible = "ti,tvp5150", }, 18227ef930a7SEduard Gavin { /* sentinel */ }, 18237ef930a7SEduard Gavin }; 18247ef930a7SEduard Gavin MODULE_DEVICE_TABLE(of, tvp5150_of_match); 18257ef930a7SEduard Gavin #endif 18267ef930a7SEduard Gavin 1827cb7a01acSMauro Carvalho Chehab static struct i2c_driver tvp5150_driver = { 1828cb7a01acSMauro Carvalho Chehab .driver = { 18297ef930a7SEduard Gavin .of_match_table = of_match_ptr(tvp5150_of_match), 1830cb7a01acSMauro Carvalho Chehab .name = "tvp5150", 1831cb7a01acSMauro Carvalho Chehab }, 1832cb7a01acSMauro Carvalho Chehab .probe = tvp5150_probe, 1833cb7a01acSMauro Carvalho Chehab .remove = tvp5150_remove, 1834cb7a01acSMauro Carvalho Chehab .id_table = tvp5150_id, 1835cb7a01acSMauro Carvalho Chehab }; 1836cb7a01acSMauro Carvalho Chehab 1837cb7a01acSMauro Carvalho Chehab module_i2c_driver(tvp5150_driver); 1838