1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2968cf782SDevin Heitmueller /* 3968cf782SDevin Heitmueller * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder 4968cf782SDevin Heitmueller * 5968cf782SDevin Heitmueller * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org> 6968cf782SDevin Heitmueller * Copyright (C) 2005-2008 Auvitek International, Ltd. 7968cf782SDevin Heitmueller */ 8968cf782SDevin Heitmueller 9968cf782SDevin Heitmueller /* Developer notes: 10968cf782SDevin Heitmueller * 11968cf782SDevin Heitmueller * Enough is implemented here for CVBS and S-Video inputs, but the actual 12968cf782SDevin Heitmueller * analog demodulator code isn't implemented (not needed for xc5000 since it 13968cf782SDevin Heitmueller * has its own demodulator and outputs CVBS) 14968cf782SDevin Heitmueller * 15968cf782SDevin Heitmueller */ 16968cf782SDevin Heitmueller 17968cf782SDevin Heitmueller #include <linux/kernel.h> 18968cf782SDevin Heitmueller #include <linux/slab.h> 19968cf782SDevin Heitmueller #include <linux/videodev2.h> 20968cf782SDevin Heitmueller #include <linux/i2c.h> 21968cf782SDevin Heitmueller #include <linux/delay.h> 22968cf782SDevin Heitmueller #include <media/v4l2-common.h> 23968cf782SDevin Heitmueller #include <media/v4l2-device.h> 24968cf782SDevin Heitmueller #include "au8522.h" 25968cf782SDevin Heitmueller #include "au8522_priv.h" 26968cf782SDevin Heitmueller 27968cf782SDevin Heitmueller MODULE_AUTHOR("Devin Heitmueller"); 28968cf782SDevin Heitmueller MODULE_LICENSE("GPL"); 29968cf782SDevin Heitmueller 30968cf782SDevin Heitmueller static int au8522_analog_debug; 31968cf782SDevin Heitmueller 32968cf782SDevin Heitmueller 33968cf782SDevin Heitmueller module_param_named(analog_debug, au8522_analog_debug, int, 0644); 34968cf782SDevin Heitmueller 35968cf782SDevin Heitmueller MODULE_PARM_DESC(analog_debug, 36968cf782SDevin Heitmueller "Analog debugging messages [0=Off (default) 1=On]"); 37968cf782SDevin Heitmueller 38968cf782SDevin Heitmueller struct au8522_register_config { 39968cf782SDevin Heitmueller u16 reg_name; 40968cf782SDevin Heitmueller u8 reg_val[8]; 41968cf782SDevin Heitmueller }; 42968cf782SDevin Heitmueller 43968cf782SDevin Heitmueller 44968cf782SDevin Heitmueller /* Video Decoder Filter Coefficients 45968cf782SDevin Heitmueller The values are as follows from left to right 46968cf782SDevin Heitmueller 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13" 47968cf782SDevin Heitmueller */ 48c86a3c37SMárton Németh static const struct au8522_register_config filter_coef[] = { 49968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} }, 50968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} }, 51968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} }, 52968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} }, 53968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} }, 54968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} }, 55968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} }, 56968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} }, 57968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} }, 58968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} }, 59968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} }, 60968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} }, 61968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} }, 62968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} }, 63968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} }, 64968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} }, 65968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} }, 66968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} }, 67968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} }, 68968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} }, 69968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} }, 70968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} }, 71968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} }, 72968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} }, 73968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} }, 74968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} }, 75968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} }, 76968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} }, 77968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} }, 78968cf782SDevin Heitmueller {AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} }, 79968cf782SDevin Heitmueller 80968cf782SDevin Heitmueller }; 8162899a28SDevin Heitmueller #define NUM_FILTER_COEF (sizeof(filter_coef)\ 8262899a28SDevin Heitmueller / sizeof(struct au8522_register_config)) 83968cf782SDevin Heitmueller 84968cf782SDevin Heitmueller 85968cf782SDevin Heitmueller /* Registers 0x060b through 0x0652 are the LP Filter coefficients 86968cf782SDevin Heitmueller The values are as follows from left to right 87968cf782SDevin Heitmueller 0="SIF" 1="ATVRF/ATVRF13" 88968cf782SDevin Heitmueller Note: the "ATVRF/ATVRF13" mode has never been tested 89968cf782SDevin Heitmueller */ 90c86a3c37SMárton Németh static const struct au8522_register_config lpfilter_coef[] = { 91968cf782SDevin Heitmueller {0x060b, {0x21, 0x0b} }, 92968cf782SDevin Heitmueller {0x060c, {0xad, 0xad} }, 93968cf782SDevin Heitmueller {0x060d, {0x70, 0xf0} }, 94968cf782SDevin Heitmueller {0x060e, {0xea, 0xe9} }, 95968cf782SDevin Heitmueller {0x060f, {0xdd, 0xdd} }, 96968cf782SDevin Heitmueller {0x0610, {0x08, 0x64} }, 97968cf782SDevin Heitmueller {0x0611, {0x60, 0x60} }, 98968cf782SDevin Heitmueller {0x0612, {0xf8, 0xb2} }, 99968cf782SDevin Heitmueller {0x0613, {0x01, 0x02} }, 100968cf782SDevin Heitmueller {0x0614, {0xe4, 0xb4} }, 101968cf782SDevin Heitmueller {0x0615, {0x19, 0x02} }, 102968cf782SDevin Heitmueller {0x0616, {0xae, 0x2e} }, 103968cf782SDevin Heitmueller {0x0617, {0xee, 0xc5} }, 104968cf782SDevin Heitmueller {0x0618, {0x56, 0x56} }, 105968cf782SDevin Heitmueller {0x0619, {0x30, 0x58} }, 106968cf782SDevin Heitmueller {0x061a, {0xf9, 0xf8} }, 107968cf782SDevin Heitmueller {0x061b, {0x24, 0x64} }, 108968cf782SDevin Heitmueller {0x061c, {0x07, 0x07} }, 109968cf782SDevin Heitmueller {0x061d, {0x30, 0x30} }, 110968cf782SDevin Heitmueller {0x061e, {0xa9, 0xed} }, 111968cf782SDevin Heitmueller {0x061f, {0x09, 0x0b} }, 112968cf782SDevin Heitmueller {0x0620, {0x42, 0xc2} }, 113968cf782SDevin Heitmueller {0x0621, {0x1d, 0x2a} }, 114968cf782SDevin Heitmueller {0x0622, {0xd6, 0x56} }, 115968cf782SDevin Heitmueller {0x0623, {0x95, 0x8b} }, 116968cf782SDevin Heitmueller {0x0624, {0x2b, 0x2b} }, 117968cf782SDevin Heitmueller {0x0625, {0x30, 0x24} }, 118968cf782SDevin Heitmueller {0x0626, {0x3e, 0x3e} }, 119968cf782SDevin Heitmueller {0x0627, {0x62, 0xe2} }, 120968cf782SDevin Heitmueller {0x0628, {0xe9, 0xf5} }, 121968cf782SDevin Heitmueller {0x0629, {0x99, 0x19} }, 122968cf782SDevin Heitmueller {0x062a, {0xd4, 0x11} }, 123968cf782SDevin Heitmueller {0x062b, {0x03, 0x04} }, 124968cf782SDevin Heitmueller {0x062c, {0xb5, 0x85} }, 125968cf782SDevin Heitmueller {0x062d, {0x1e, 0x20} }, 126968cf782SDevin Heitmueller {0x062e, {0x2a, 0xea} }, 127968cf782SDevin Heitmueller {0x062f, {0xd7, 0xd2} }, 128968cf782SDevin Heitmueller {0x0630, {0x15, 0x15} }, 129968cf782SDevin Heitmueller {0x0631, {0xa3, 0xa9} }, 130968cf782SDevin Heitmueller {0x0632, {0x1f, 0x1f} }, 131968cf782SDevin Heitmueller {0x0633, {0xf9, 0xd1} }, 132968cf782SDevin Heitmueller {0x0634, {0xc0, 0xc3} }, 133968cf782SDevin Heitmueller {0x0635, {0x4d, 0x8d} }, 134968cf782SDevin Heitmueller {0x0636, {0x21, 0x31} }, 135968cf782SDevin Heitmueller {0x0637, {0x83, 0x83} }, 136968cf782SDevin Heitmueller {0x0638, {0x08, 0x8c} }, 137968cf782SDevin Heitmueller {0x0639, {0x19, 0x19} }, 138968cf782SDevin Heitmueller {0x063a, {0x45, 0xa5} }, 139968cf782SDevin Heitmueller {0x063b, {0xef, 0xec} }, 140968cf782SDevin Heitmueller {0x063c, {0x8a, 0x8a} }, 141968cf782SDevin Heitmueller {0x063d, {0xf4, 0xf6} }, 142968cf782SDevin Heitmueller {0x063e, {0x8f, 0x8f} }, 143968cf782SDevin Heitmueller {0x063f, {0x44, 0x0c} }, 144968cf782SDevin Heitmueller {0x0640, {0xef, 0xf0} }, 145968cf782SDevin Heitmueller {0x0641, {0x66, 0x66} }, 146968cf782SDevin Heitmueller {0x0642, {0xcc, 0xd2} }, 147968cf782SDevin Heitmueller {0x0643, {0x41, 0x41} }, 148968cf782SDevin Heitmueller {0x0644, {0x63, 0x93} }, 149968cf782SDevin Heitmueller {0x0645, {0x8e, 0x8e} }, 150968cf782SDevin Heitmueller {0x0646, {0xa2, 0x42} }, 151968cf782SDevin Heitmueller {0x0647, {0x7b, 0x7b} }, 152968cf782SDevin Heitmueller {0x0648, {0x04, 0x04} }, 153968cf782SDevin Heitmueller {0x0649, {0x00, 0x00} }, 154968cf782SDevin Heitmueller {0x064a, {0x40, 0x40} }, 155968cf782SDevin Heitmueller {0x064b, {0x8c, 0x98} }, 156968cf782SDevin Heitmueller {0x064c, {0x00, 0x00} }, 157968cf782SDevin Heitmueller {0x064d, {0x63, 0xc3} }, 158968cf782SDevin Heitmueller {0x064e, {0x04, 0x04} }, 159968cf782SDevin Heitmueller {0x064f, {0x20, 0x20} }, 160968cf782SDevin Heitmueller {0x0650, {0x00, 0x00} }, 161968cf782SDevin Heitmueller {0x0651, {0x40, 0x40} }, 162968cf782SDevin Heitmueller {0x0652, {0x01, 0x01} }, 163968cf782SDevin Heitmueller }; 16462899a28SDevin Heitmueller #define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\ 16562899a28SDevin Heitmueller / sizeof(struct au8522_register_config)) 166968cf782SDevin Heitmueller 167968cf782SDevin Heitmueller static inline struct au8522_state *to_state(struct v4l2_subdev *sd) 168968cf782SDevin Heitmueller { 169968cf782SDevin Heitmueller return container_of(sd, struct au8522_state, sd); 170968cf782SDevin Heitmueller } 171968cf782SDevin Heitmueller 17265c88209SMauro Carvalho Chehab static void setup_decoder_defaults(struct au8522_state *state, bool is_svideo) 173968cf782SDevin Heitmueller { 174968cf782SDevin Heitmueller int i; 175968cf782SDevin Heitmueller int filter_coef_type; 176968cf782SDevin Heitmueller 177968cf782SDevin Heitmueller /* Provide reasonable defaults for picture tuning values */ 178968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07); 179968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed); 180968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79); 181968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80); 182968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80); 183968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00); 184968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00); 185968cf782SDevin Heitmueller 186968cf782SDevin Heitmueller /* Other decoder registers */ 187968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00); 188968cf782SDevin Heitmueller 18965c88209SMauro Carvalho Chehab if (is_svideo) 190968cf782SDevin Heitmueller au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04); 19165c88209SMauro Carvalho Chehab else 192968cf782SDevin Heitmueller au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00); 193968cf782SDevin Heitmueller 194968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_PGA_REG012H, 195968cf782SDevin Heitmueller AU8522_TVDEC_PGA_REG012H_CVBS); 196968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H, 197968cf782SDevin Heitmueller AU8522_TVDEC_COMB_MODE_REG015H_CVBS); 198968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H, 199968cf782SDevin Heitmueller AU8522_TVDED_DBG_MODE_REG060H_CVBS); 200f2fd7ce6SMauro Carvalho Chehab 201f2fd7ce6SMauro Carvalho Chehab if (state->std == V4L2_STD_PAL_M) { 202f2fd7ce6SMauro Carvalho Chehab au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H, 203f2fd7ce6SMauro Carvalho Chehab AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 | 204f2fd7ce6SMauro Carvalho Chehab AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 | 205f2fd7ce6SMauro Carvalho Chehab AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO); 206f2fd7ce6SMauro Carvalho Chehab au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H, 207f2fd7ce6SMauro Carvalho Chehab AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_PAL_M); 208f2fd7ce6SMauro Carvalho Chehab } else { 209f2fd7ce6SMauro Carvalho Chehab /* NTSC */ 210968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H, 211a307cfa5SDevin Heitmueller AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 | 212a307cfa5SDevin Heitmueller AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 | 213a307cfa5SDevin Heitmueller AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN); 214968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H, 215a307cfa5SDevin Heitmueller AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC); 216f2fd7ce6SMauro Carvalho Chehab } 217968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H, 218968cf782SDevin Heitmueller AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS); 219968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H, 220968cf782SDevin Heitmueller AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS); 221968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H, 222968cf782SDevin Heitmueller AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS); 223968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H, 224968cf782SDevin Heitmueller AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS); 225968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H, 226968cf782SDevin Heitmueller AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS); 227968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H, 228968cf782SDevin Heitmueller AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS); 229968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H, 230968cf782SDevin Heitmueller AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS); 231968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH, 232968cf782SDevin Heitmueller AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS); 233968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH, 234968cf782SDevin Heitmueller AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS); 23565c88209SMauro Carvalho Chehab if (is_svideo) { 236301c9f26SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH, 237301c9f26SDevin Heitmueller AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO); 238301c9f26SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH, 239301c9f26SDevin Heitmueller AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO); 240301c9f26SDevin Heitmueller } else { 241968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH, 242968cf782SDevin Heitmueller AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS); 243968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH, 244968cf782SDevin Heitmueller AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS); 245301c9f26SDevin Heitmueller } 246968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH, 247968cf782SDevin Heitmueller AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS); 248968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH, 249968cf782SDevin Heitmueller AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS); 250968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H, 251968cf782SDevin Heitmueller AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS); 252968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS); 253968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS); 254968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H, 255968cf782SDevin Heitmueller AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS); 256968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS); 257968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS); 258968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H, 259968cf782SDevin Heitmueller AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS); 260968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H, 261968cf782SDevin Heitmueller AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS); 262968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H, 263968cf782SDevin Heitmueller AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS); 264968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH, 265968cf782SDevin Heitmueller AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS); 266968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH, 267968cf782SDevin Heitmueller AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS); 268968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H, 269968cf782SDevin Heitmueller AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS); 270968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H, 271968cf782SDevin Heitmueller AU8522_TOREGAAGC_REG0E5H_CVBS); 272968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS); 273968cf782SDevin Heitmueller 274b3b2d5b6SGustavo A. R. Silva /* 275b3b2d5b6SGustavo A. R. Silva * Despite what the table says, for the HVR-950q we still need 276b3b2d5b6SGustavo A. R. Silva * to be in CVBS mode for the S-Video input (reason unknown). 277b3b2d5b6SGustavo A. R. Silva */ 278968cf782SDevin Heitmueller /* filter_coef_type = 3; */ 279968cf782SDevin Heitmueller filter_coef_type = 5; 280968cf782SDevin Heitmueller 281968cf782SDevin Heitmueller /* Load the Video Decoder Filter Coefficients */ 282968cf782SDevin Heitmueller for (i = 0; i < NUM_FILTER_COEF; i++) { 283968cf782SDevin Heitmueller au8522_writereg(state, filter_coef[i].reg_name, 284968cf782SDevin Heitmueller filter_coef[i].reg_val[filter_coef_type]); 285968cf782SDevin Heitmueller } 286968cf782SDevin Heitmueller 287968cf782SDevin Heitmueller /* It's not clear what these registers are for, but they are always 288968cf782SDevin Heitmueller set to the same value regardless of what mode we're in */ 289968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG42EH, 0x87); 290968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG42FH, 0xa2); 291968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG430H, 0xbf); 292968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG431H, 0xcb); 293968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG432H, 0xa1); 294968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG433H, 0x41); 295968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG434H, 0x88); 296968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG435H, 0xc2); 297968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG436H, 0x3c); 298968cf782SDevin Heitmueller } 299968cf782SDevin Heitmueller 30036469316SMauro Carvalho Chehab static void au8522_setup_cvbs_mode(struct au8522_state *state, u8 input_mode) 301968cf782SDevin Heitmueller { 302968cf782SDevin Heitmueller /* here we're going to try the pre-programmed route */ 303968cf782SDevin Heitmueller au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, 304968cf782SDevin Heitmueller AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS); 305968cf782SDevin Heitmueller 306d2c194ceSDevin Heitmueller /* PGA in automatic mode */ 307968cf782SDevin Heitmueller au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); 308d2c194ceSDevin Heitmueller 309d2c194ceSDevin Heitmueller /* Enable clamping control */ 310d2c194ceSDevin Heitmueller au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00); 311968cf782SDevin Heitmueller 31236469316SMauro Carvalho Chehab au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode); 313968cf782SDevin Heitmueller 31465c88209SMauro Carvalho Chehab setup_decoder_defaults(state, false); 315968cf782SDevin Heitmueller 316968cf782SDevin Heitmueller au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 317968cf782SDevin Heitmueller AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); 318968cf782SDevin Heitmueller } 319968cf782SDevin Heitmueller 32036469316SMauro Carvalho Chehab static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state, 32136469316SMauro Carvalho Chehab u8 input_mode) 322968cf782SDevin Heitmueller { 323968cf782SDevin Heitmueller /* here we're going to try the pre-programmed route */ 324968cf782SDevin Heitmueller au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, 325968cf782SDevin Heitmueller AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS); 326968cf782SDevin Heitmueller 327d2c194ceSDevin Heitmueller /* It's not clear why we have to have the PGA in automatic mode while 328d2c194ceSDevin Heitmueller enabling clamp control, but it's what Windows does */ 329968cf782SDevin Heitmueller au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); 330968cf782SDevin Heitmueller 331968cf782SDevin Heitmueller /* Enable clamping control */ 332968cf782SDevin Heitmueller au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e); 333968cf782SDevin Heitmueller 334d2c194ceSDevin Heitmueller /* Disable automatic PGA (since the CVBS is coming from the tuner) */ 335968cf782SDevin Heitmueller au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10); 336968cf782SDevin Heitmueller 337968cf782SDevin Heitmueller /* Set input mode to CVBS on channel 4 with SIF audio input enabled */ 33836469316SMauro Carvalho Chehab au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode); 339968cf782SDevin Heitmueller 34065c88209SMauro Carvalho Chehab setup_decoder_defaults(state, false); 341968cf782SDevin Heitmueller 342968cf782SDevin Heitmueller au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 343968cf782SDevin Heitmueller AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); 344968cf782SDevin Heitmueller } 345968cf782SDevin Heitmueller 34636469316SMauro Carvalho Chehab static void au8522_setup_svideo_mode(struct au8522_state *state, 34736469316SMauro Carvalho Chehab u8 input_mode) 348968cf782SDevin Heitmueller { 349968cf782SDevin Heitmueller au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H, 350968cf782SDevin Heitmueller AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO); 351968cf782SDevin Heitmueller 352968cf782SDevin Heitmueller /* Set input to Y on Channe1, C on Channel 3 */ 35336469316SMauro Carvalho Chehab au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode); 354968cf782SDevin Heitmueller 355d2c194ceSDevin Heitmueller /* PGA in automatic mode */ 356d2c194ceSDevin Heitmueller au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00); 357d2c194ceSDevin Heitmueller 358d2c194ceSDevin Heitmueller /* Enable clamping control */ 359968cf782SDevin Heitmueller au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00); 360968cf782SDevin Heitmueller 36165c88209SMauro Carvalho Chehab setup_decoder_defaults(state, true); 362968cf782SDevin Heitmueller 363968cf782SDevin Heitmueller au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 364968cf782SDevin Heitmueller AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS); 365968cf782SDevin Heitmueller } 366968cf782SDevin Heitmueller 367968cf782SDevin Heitmueller /* ----------------------------------------------------------------------- */ 368968cf782SDevin Heitmueller 369968cf782SDevin Heitmueller static void disable_audio_input(struct au8522_state *state) 370968cf782SDevin Heitmueller { 371968cf782SDevin Heitmueller au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00); 372968cf782SDevin Heitmueller au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00); 373968cf782SDevin Heitmueller au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00); 374968cf782SDevin Heitmueller 375968cf782SDevin Heitmueller au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04); 376968cf782SDevin Heitmueller au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02); 377968cf782SDevin Heitmueller 378968cf782SDevin Heitmueller au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 3792428a2edSDevin Heitmueller AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO); 380968cf782SDevin Heitmueller } 381968cf782SDevin Heitmueller 382968cf782SDevin Heitmueller /* 0=disable, 1=SIF */ 383d289cdf0SMauro Carvalho Chehab static void set_audio_input(struct au8522_state *state) 384968cf782SDevin Heitmueller { 385d289cdf0SMauro Carvalho Chehab int aud_input = state->aud_input; 386968cf782SDevin Heitmueller int i; 387968cf782SDevin Heitmueller 388968cf782SDevin Heitmueller /* Note that this function needs to be used in conjunction with setting 389968cf782SDevin Heitmueller the input routing via register 0x81 */ 390968cf782SDevin Heitmueller 391968cf782SDevin Heitmueller if (aud_input == AU8522_AUDIO_NONE) { 392968cf782SDevin Heitmueller disable_audio_input(state); 393968cf782SDevin Heitmueller return; 394968cf782SDevin Heitmueller } 395968cf782SDevin Heitmueller 396968cf782SDevin Heitmueller if (aud_input != AU8522_AUDIO_SIF) { 397968cf782SDevin Heitmueller /* The caller asked for a mode we don't currently support */ 39862899a28SDevin Heitmueller printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n", 399968cf782SDevin Heitmueller aud_input); 400968cf782SDevin Heitmueller return; 401968cf782SDevin Heitmueller } 402968cf782SDevin Heitmueller 403968cf782SDevin Heitmueller /* Load the Audio Decoder Filter Coefficients */ 404968cf782SDevin Heitmueller for (i = 0; i < NUM_LPFILTER_COEF; i++) { 405968cf782SDevin Heitmueller au8522_writereg(state, lpfilter_coef[i].reg_name, 406968cf782SDevin Heitmueller lpfilter_coef[i].reg_val[0]); 407968cf782SDevin Heitmueller } 408968cf782SDevin Heitmueller 409427de05cSDevin Heitmueller /* Set the volume */ 410968cf782SDevin Heitmueller au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F); 411968cf782SDevin Heitmueller au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F); 412968cf782SDevin Heitmueller au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff); 413427de05cSDevin Heitmueller 414427de05cSDevin Heitmueller /* Not sure what this does */ 415968cf782SDevin Heitmueller au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO); 416427de05cSDevin Heitmueller 417427de05cSDevin Heitmueller /* Setup the audio mode to stereo DBX */ 418968cf782SDevin Heitmueller au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82); 419968cf782SDevin Heitmueller msleep(70); 420427de05cSDevin Heitmueller 421427de05cSDevin Heitmueller /* Start the audio processing module */ 422427de05cSDevin Heitmueller au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d); 423427de05cSDevin Heitmueller 424427de05cSDevin Heitmueller /* Set the audio frequency to 48 KHz */ 425968cf782SDevin Heitmueller au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03); 426427de05cSDevin Heitmueller 427427de05cSDevin Heitmueller /* Set the I2S parameters (WS, LSB, mode, sample rate */ 428968cf782SDevin Heitmueller au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2); 429427de05cSDevin Heitmueller 430427de05cSDevin Heitmueller /* Enable the I2S output */ 431427de05cSDevin Heitmueller au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09); 432968cf782SDevin Heitmueller } 433968cf782SDevin Heitmueller 434968cf782SDevin Heitmueller /* ----------------------------------------------------------------------- */ 435968cf782SDevin Heitmueller 4365a4bdb4bSHans Verkuil static int au8522_s_ctrl(struct v4l2_ctrl *ctrl) 437968cf782SDevin Heitmueller { 4385a4bdb4bSHans Verkuil struct au8522_state *state = 4395a4bdb4bSHans Verkuil container_of(ctrl->handler, struct au8522_state, hdl); 440968cf782SDevin Heitmueller 441968cf782SDevin Heitmueller switch (ctrl->id) { 442968cf782SDevin Heitmueller case V4L2_CID_BRIGHTNESS: 443968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 4445a4bdb4bSHans Verkuil ctrl->val - 128); 445968cf782SDevin Heitmueller break; 446968cf782SDevin Heitmueller case V4L2_CID_CONTRAST: 447968cf782SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 4485a4bdb4bSHans Verkuil ctrl->val); 449968cf782SDevin Heitmueller break; 450968cf782SDevin Heitmueller case V4L2_CID_SATURATION: 45136a91879SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 4525a4bdb4bSHans Verkuil ctrl->val); 45336a91879SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 4545a4bdb4bSHans Verkuil ctrl->val); 45536a91879SDevin Heitmueller break; 456968cf782SDevin Heitmueller case V4L2_CID_HUE: 45736a91879SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 4585a4bdb4bSHans Verkuil ctrl->val >> 8); 45936a91879SDevin Heitmueller au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 4605a4bdb4bSHans Verkuil ctrl->val & 0xFF); 46136a91879SDevin Heitmueller break; 462968cf782SDevin Heitmueller default: 463968cf782SDevin Heitmueller return -EINVAL; 464968cf782SDevin Heitmueller } 465968cf782SDevin Heitmueller 466968cf782SDevin Heitmueller return 0; 467968cf782SDevin Heitmueller } 468968cf782SDevin Heitmueller 469968cf782SDevin Heitmueller /* ----------------------------------------------------------------------- */ 470968cf782SDevin Heitmueller 471968cf782SDevin Heitmueller #ifdef CONFIG_VIDEO_ADV_DEBUG 472968cf782SDevin Heitmueller static int au8522_g_register(struct v4l2_subdev *sd, 473968cf782SDevin Heitmueller struct v4l2_dbg_register *reg) 474968cf782SDevin Heitmueller { 475968cf782SDevin Heitmueller struct au8522_state *state = to_state(sd); 476968cf782SDevin Heitmueller 477968cf782SDevin Heitmueller reg->val = au8522_readreg(state, reg->reg & 0xffff); 478968cf782SDevin Heitmueller return 0; 479968cf782SDevin Heitmueller } 480968cf782SDevin Heitmueller 481968cf782SDevin Heitmueller static int au8522_s_register(struct v4l2_subdev *sd, 482977ba3b1SHans Verkuil const struct v4l2_dbg_register *reg) 483968cf782SDevin Heitmueller { 484968cf782SDevin Heitmueller struct au8522_state *state = to_state(sd); 485968cf782SDevin Heitmueller 486968cf782SDevin Heitmueller au8522_writereg(state, reg->reg, reg->val & 0xff); 487968cf782SDevin Heitmueller return 0; 488968cf782SDevin Heitmueller } 489968cf782SDevin Heitmueller #endif 490968cf782SDevin Heitmueller 49136469316SMauro Carvalho Chehab static void au8522_video_set(struct au8522_state *state) 49236469316SMauro Carvalho Chehab { 49336469316SMauro Carvalho Chehab u8 input_mode; 49436469316SMauro Carvalho Chehab 49538fe3510SMauro Carvalho Chehab au8522_writereg(state, 0xa4, 1 << 5); 49636469316SMauro Carvalho Chehab 49736469316SMauro Carvalho Chehab switch (state->vid_input) { 49836469316SMauro Carvalho Chehab case AU8522_COMPOSITE_CH1: 49936469316SMauro Carvalho Chehab input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH1; 50036469316SMauro Carvalho Chehab au8522_setup_cvbs_mode(state, input_mode); 50136469316SMauro Carvalho Chehab break; 50236469316SMauro Carvalho Chehab case AU8522_COMPOSITE_CH2: 50336469316SMauro Carvalho Chehab input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH2; 50436469316SMauro Carvalho Chehab au8522_setup_cvbs_mode(state, input_mode); 50536469316SMauro Carvalho Chehab break; 50636469316SMauro Carvalho Chehab case AU8522_COMPOSITE_CH3: 50736469316SMauro Carvalho Chehab input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH3; 50836469316SMauro Carvalho Chehab au8522_setup_cvbs_mode(state, input_mode); 50936469316SMauro Carvalho Chehab break; 51036469316SMauro Carvalho Chehab case AU8522_COMPOSITE_CH4: 51136469316SMauro Carvalho Chehab input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4; 51236469316SMauro Carvalho Chehab au8522_setup_cvbs_mode(state, input_mode); 51336469316SMauro Carvalho Chehab break; 51436469316SMauro Carvalho Chehab case AU8522_SVIDEO_CH13: 51536469316SMauro Carvalho Chehab input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13; 51636469316SMauro Carvalho Chehab au8522_setup_svideo_mode(state, input_mode); 51736469316SMauro Carvalho Chehab break; 51836469316SMauro Carvalho Chehab case AU8522_SVIDEO_CH24: 51936469316SMauro Carvalho Chehab input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24; 52036469316SMauro Carvalho Chehab au8522_setup_svideo_mode(state, input_mode); 52136469316SMauro Carvalho Chehab break; 52236469316SMauro Carvalho Chehab default: 52336469316SMauro Carvalho Chehab case AU8522_COMPOSITE_CH4_SIF: 52436469316SMauro Carvalho Chehab input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF; 52536469316SMauro Carvalho Chehab au8522_setup_cvbs_tuner_mode(state, input_mode); 52636469316SMauro Carvalho Chehab break; 52736469316SMauro Carvalho Chehab } 52836469316SMauro Carvalho Chehab } 52936469316SMauro Carvalho Chehab 53038fe3510SMauro Carvalho Chehab static int au8522_s_stream(struct v4l2_subdev *sd, int enable) 53138fe3510SMauro Carvalho Chehab { 53238fe3510SMauro Carvalho Chehab struct au8522_state *state = to_state(sd); 53338fe3510SMauro Carvalho Chehab 53438fe3510SMauro Carvalho Chehab if (enable) { 53538fe3510SMauro Carvalho Chehab /* 53638fe3510SMauro Carvalho Chehab * Clear out any state associated with the digital side of the 53738fe3510SMauro Carvalho Chehab * chip, so that when it gets powered back up it won't think 53838fe3510SMauro Carvalho Chehab * that it is already tuned 53938fe3510SMauro Carvalho Chehab */ 54038fe3510SMauro Carvalho Chehab state->current_frequency = 0; 54138fe3510SMauro Carvalho Chehab 54238fe3510SMauro Carvalho Chehab au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 54338fe3510SMauro Carvalho Chehab 0x01); 544c9f5ccc2SMauro Carvalho Chehab msleep(10); 54538fe3510SMauro Carvalho Chehab 54638fe3510SMauro Carvalho Chehab au8522_video_set(state); 547d289cdf0SMauro Carvalho Chehab set_audio_input(state); 548d289cdf0SMauro Carvalho Chehab 549d289cdf0SMauro Carvalho Chehab state->operational_mode = AU8522_ANALOG_MODE; 55038fe3510SMauro Carvalho Chehab } else { 55138fe3510SMauro Carvalho Chehab /* This does not completely power down the device 55238fe3510SMauro Carvalho Chehab (it only reduces it from around 140ma to 80ma) */ 55338fe3510SMauro Carvalho Chehab au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 55438fe3510SMauro Carvalho Chehab 1 << 5); 55538fe3510SMauro Carvalho Chehab state->operational_mode = AU8522_SUSPEND_MODE; 55638fe3510SMauro Carvalho Chehab } 55738fe3510SMauro Carvalho Chehab return 0; 55838fe3510SMauro Carvalho Chehab } 55938fe3510SMauro Carvalho Chehab 560968cf782SDevin Heitmueller static int au8522_s_video_routing(struct v4l2_subdev *sd, 5615325b427SHans Verkuil u32 input, u32 output, u32 config) 562968cf782SDevin Heitmueller { 563968cf782SDevin Heitmueller struct au8522_state *state = to_state(sd); 564968cf782SDevin Heitmueller 56536469316SMauro Carvalho Chehab switch (input) { 56636469316SMauro Carvalho Chehab case AU8522_COMPOSITE_CH1: 56736469316SMauro Carvalho Chehab case AU8522_SVIDEO_CH13: 56836469316SMauro Carvalho Chehab case AU8522_COMPOSITE_CH4_SIF: 56936469316SMauro Carvalho Chehab state->vid_input = input; 57036469316SMauro Carvalho Chehab break; 57136469316SMauro Carvalho Chehab default: 57262899a28SDevin Heitmueller printk(KERN_ERR "au8522 mode not currently supported\n"); 573968cf782SDevin Heitmueller return -EINVAL; 574968cf782SDevin Heitmueller } 57538fe3510SMauro Carvalho Chehab 57638fe3510SMauro Carvalho Chehab if (state->operational_mode == AU8522_ANALOG_MODE) 57736469316SMauro Carvalho Chehab au8522_video_set(state); 57838fe3510SMauro Carvalho Chehab 579968cf782SDevin Heitmueller return 0; 580968cf782SDevin Heitmueller } 581968cf782SDevin Heitmueller 582f2fd7ce6SMauro Carvalho Chehab static int au8522_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 583f2fd7ce6SMauro Carvalho Chehab { 584f2fd7ce6SMauro Carvalho Chehab struct au8522_state *state = to_state(sd); 585f2fd7ce6SMauro Carvalho Chehab 586f2fd7ce6SMauro Carvalho Chehab if ((std & (V4L2_STD_PAL_M | V4L2_STD_NTSC_M)) == 0) 587f2fd7ce6SMauro Carvalho Chehab return -EINVAL; 588f2fd7ce6SMauro Carvalho Chehab 589f2fd7ce6SMauro Carvalho Chehab state->std = std; 590f2fd7ce6SMauro Carvalho Chehab 591f2fd7ce6SMauro Carvalho Chehab if (state->operational_mode == AU8522_ANALOG_MODE) 592f2fd7ce6SMauro Carvalho Chehab au8522_video_set(state); 593f2fd7ce6SMauro Carvalho Chehab 594f2fd7ce6SMauro Carvalho Chehab return 0; 595f2fd7ce6SMauro Carvalho Chehab } 596f2fd7ce6SMauro Carvalho Chehab 597968cf782SDevin Heitmueller static int au8522_s_audio_routing(struct v4l2_subdev *sd, 5985325b427SHans Verkuil u32 input, u32 output, u32 config) 599968cf782SDevin Heitmueller { 600968cf782SDevin Heitmueller struct au8522_state *state = to_state(sd); 601d289cdf0SMauro Carvalho Chehab 602d289cdf0SMauro Carvalho Chehab state->aud_input = input; 603d289cdf0SMauro Carvalho Chehab 604d289cdf0SMauro Carvalho Chehab if (state->operational_mode == AU8522_ANALOG_MODE) 605d289cdf0SMauro Carvalho Chehab set_audio_input(state); 606d289cdf0SMauro Carvalho Chehab 607968cf782SDevin Heitmueller return 0; 608968cf782SDevin Heitmueller } 609968cf782SDevin Heitmueller 610968cf782SDevin Heitmueller static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) 611968cf782SDevin Heitmueller { 612968cf782SDevin Heitmueller int val = 0; 613968cf782SDevin Heitmueller struct au8522_state *state = to_state(sd); 614968cf782SDevin Heitmueller u8 lock_status; 615b01052abSDevin Heitmueller u8 pll_status; 616968cf782SDevin Heitmueller 617968cf782SDevin Heitmueller /* Interrogate the decoder to see if we are getting a real signal */ 618968cf782SDevin Heitmueller lock_status = au8522_readreg(state, 0x00); 619b01052abSDevin Heitmueller pll_status = au8522_readreg(state, 0x7e); 620b01052abSDevin Heitmueller if ((lock_status == 0xa2) && (pll_status & 0x10)) 621d749fb66SDevin Heitmueller vt->signal = 0xffff; 622968cf782SDevin Heitmueller else 623968cf782SDevin Heitmueller vt->signal = 0x00; 624968cf782SDevin Heitmueller 625968cf782SDevin Heitmueller vt->capability |= 626968cf782SDevin Heitmueller V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | 627968cf782SDevin Heitmueller V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; 628968cf782SDevin Heitmueller 629968cf782SDevin Heitmueller val = V4L2_TUNER_SUB_MONO; 630968cf782SDevin Heitmueller vt->rxsubchans = val; 631968cf782SDevin Heitmueller vt->audmode = V4L2_TUNER_MODE_STEREO; 632968cf782SDevin Heitmueller return 0; 633968cf782SDevin Heitmueller } 634968cf782SDevin Heitmueller 635968cf782SDevin Heitmueller /* ----------------------------------------------------------------------- */ 636968cf782SDevin Heitmueller 637968cf782SDevin Heitmueller static const struct v4l2_subdev_core_ops au8522_core_ops = { 6385a4bdb4bSHans Verkuil .log_status = v4l2_ctrl_subdev_log_status, 639968cf782SDevin Heitmueller #ifdef CONFIG_VIDEO_ADV_DEBUG 640968cf782SDevin Heitmueller .g_register = au8522_g_register, 641968cf782SDevin Heitmueller .s_register = au8522_s_register, 642968cf782SDevin Heitmueller #endif 643968cf782SDevin Heitmueller }; 644968cf782SDevin Heitmueller 645968cf782SDevin Heitmueller static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = { 646968cf782SDevin Heitmueller .g_tuner = au8522_g_tuner, 647968cf782SDevin Heitmueller }; 648968cf782SDevin Heitmueller 649968cf782SDevin Heitmueller static const struct v4l2_subdev_audio_ops au8522_audio_ops = { 650968cf782SDevin Heitmueller .s_routing = au8522_s_audio_routing, 651968cf782SDevin Heitmueller }; 652968cf782SDevin Heitmueller 653968cf782SDevin Heitmueller static const struct v4l2_subdev_video_ops au8522_video_ops = { 654968cf782SDevin Heitmueller .s_routing = au8522_s_video_routing, 655968cf782SDevin Heitmueller .s_stream = au8522_s_stream, 656f2fd7ce6SMauro Carvalho Chehab .s_std = au8522_s_std, 657968cf782SDevin Heitmueller }; 658968cf782SDevin Heitmueller 659968cf782SDevin Heitmueller static const struct v4l2_subdev_ops au8522_ops = { 660968cf782SDevin Heitmueller .core = &au8522_core_ops, 661968cf782SDevin Heitmueller .tuner = &au8522_tuner_ops, 662968cf782SDevin Heitmueller .audio = &au8522_audio_ops, 663968cf782SDevin Heitmueller .video = &au8522_video_ops, 664968cf782SDevin Heitmueller }; 665968cf782SDevin Heitmueller 6665a4bdb4bSHans Verkuil static const struct v4l2_ctrl_ops au8522_ctrl_ops = { 6675a4bdb4bSHans Verkuil .s_ctrl = au8522_s_ctrl, 6685a4bdb4bSHans Verkuil }; 6695a4bdb4bSHans Verkuil 670968cf782SDevin Heitmueller /* ----------------------------------------------------------------------- */ 671968cf782SDevin Heitmueller 672968cf782SDevin Heitmueller static int au8522_probe(struct i2c_client *client, 673968cf782SDevin Heitmueller const struct i2c_device_id *did) 674968cf782SDevin Heitmueller { 675968cf782SDevin Heitmueller struct au8522_state *state; 6765a4bdb4bSHans Verkuil struct v4l2_ctrl_handler *hdl; 677968cf782SDevin Heitmueller struct v4l2_subdev *sd; 678968cf782SDevin Heitmueller int instance; 679bed69196SRafael Lourenço de Lima Chehab #ifdef CONFIG_MEDIA_CONTROLLER 680bed69196SRafael Lourenço de Lima Chehab int ret; 681bed69196SRafael Lourenço de Lima Chehab #endif 682968cf782SDevin Heitmueller 683968cf782SDevin Heitmueller /* Check if the adapter supports the needed features */ 684968cf782SDevin Heitmueller if (!i2c_check_functionality(client->adapter, 685968cf782SDevin Heitmueller I2C_FUNC_SMBUS_BYTE_DATA)) { 686968cf782SDevin Heitmueller return -EIO; 687968cf782SDevin Heitmueller } 688968cf782SDevin Heitmueller 689968cf782SDevin Heitmueller /* allocate memory for the internal state */ 690968cf782SDevin Heitmueller instance = au8522_get_state(&state, client->adapter, client->addr); 691968cf782SDevin Heitmueller switch (instance) { 692968cf782SDevin Heitmueller case 0: 69362899a28SDevin Heitmueller printk(KERN_ERR "au8522_decoder allocation failed\n"); 694968cf782SDevin Heitmueller return -EIO; 695968cf782SDevin Heitmueller case 1: 696968cf782SDevin Heitmueller /* new demod instance */ 69762899a28SDevin Heitmueller printk(KERN_INFO "au8522_decoder creating new instance...\n"); 698968cf782SDevin Heitmueller break; 699968cf782SDevin Heitmueller default: 700968cf782SDevin Heitmueller /* existing demod instance */ 70162899a28SDevin Heitmueller printk(KERN_INFO "au8522_decoder attach existing instance.\n"); 702968cf782SDevin Heitmueller break; 703968cf782SDevin Heitmueller } 704968cf782SDevin Heitmueller 705aa37763fSMauro Carvalho Chehab state->config.demod_address = 0x8e >> 1; 706968cf782SDevin Heitmueller state->i2c = client->adapter; 707968cf782SDevin Heitmueller 708968cf782SDevin Heitmueller sd = &state->sd; 709968cf782SDevin Heitmueller v4l2_i2c_subdev_init(sd, client, &au8522_ops); 710bed69196SRafael Lourenço de Lima Chehab #if defined(CONFIG_MEDIA_CONTROLLER) 711bed69196SRafael Lourenço de Lima Chehab 71244fd653bSMauro Carvalho Chehab state->pads[AU8522_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; 71344fd653bSMauro Carvalho Chehab state->pads[AU8522_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG; 71444fd653bSMauro Carvalho Chehab state->pads[AU8522_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; 71544fd653bSMauro Carvalho Chehab state->pads[AU8522_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV; 71644fd653bSMauro Carvalho Chehab state->pads[AU8522_PAD_AUDIO_OUT].flags = MEDIA_PAD_FL_SOURCE; 71744fd653bSMauro Carvalho Chehab state->pads[AU8522_PAD_AUDIO_OUT].sig_type = PAD_SIGNAL_AUDIO; 7184ca72efaSMauro Carvalho Chehab sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 719bed69196SRafael Lourenço de Lima Chehab 720ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads), 72118095107SMauro Carvalho Chehab state->pads); 722bed69196SRafael Lourenço de Lima Chehab if (ret < 0) { 723bed69196SRafael Lourenço de Lima Chehab v4l_info(client, "failed to initialize media entity!\n"); 724bed69196SRafael Lourenço de Lima Chehab return ret; 725bed69196SRafael Lourenço de Lima Chehab } 726bed69196SRafael Lourenço de Lima Chehab #endif 727968cf782SDevin Heitmueller 7285a4bdb4bSHans Verkuil hdl = &state->hdl; 7295a4bdb4bSHans Verkuil v4l2_ctrl_handler_init(hdl, 4); 7305a4bdb4bSHans Verkuil v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops, 7315a4bdb4bSHans Verkuil V4L2_CID_BRIGHTNESS, 0, 255, 1, 109); 7325a4bdb4bSHans Verkuil v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops, 7335a4bdb4bSHans Verkuil V4L2_CID_CONTRAST, 0, 255, 1, 7345a4bdb4bSHans Verkuil AU8522_TVDEC_CONTRAST_REG00BH_CVBS); 7355a4bdb4bSHans Verkuil v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops, 7365a4bdb4bSHans Verkuil V4L2_CID_SATURATION, 0, 255, 1, 128); 7375a4bdb4bSHans Verkuil v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops, 7385a4bdb4bSHans Verkuil V4L2_CID_HUE, -32768, 32767, 1, 0); 7395a4bdb4bSHans Verkuil sd->ctrl_handler = hdl; 7405a4bdb4bSHans Verkuil if (hdl->error) { 7415a4bdb4bSHans Verkuil int err = hdl->error; 7425a4bdb4bSHans Verkuil 7435a4bdb4bSHans Verkuil v4l2_ctrl_handler_free(hdl); 744aa37763fSMauro Carvalho Chehab au8522_release_state(state); 7455a4bdb4bSHans Verkuil return err; 7465a4bdb4bSHans Verkuil } 7475a4bdb4bSHans Verkuil 748968cf782SDevin Heitmueller state->c = client; 749f2fd7ce6SMauro Carvalho Chehab state->std = V4L2_STD_NTSC_M; 750968cf782SDevin Heitmueller state->vid_input = AU8522_COMPOSITE_CH1; 751968cf782SDevin Heitmueller state->aud_input = AU8522_AUDIO_NONE; 752968cf782SDevin Heitmueller state->id = 8522; 753968cf782SDevin Heitmueller state->rev = 0; 754968cf782SDevin Heitmueller 755968cf782SDevin Heitmueller /* Jam open the i2c gate to the tuner */ 756968cf782SDevin Heitmueller au8522_writereg(state, 0x106, 1); 757968cf782SDevin Heitmueller 758968cf782SDevin Heitmueller return 0; 759968cf782SDevin Heitmueller } 760968cf782SDevin Heitmueller 761968cf782SDevin Heitmueller static int au8522_remove(struct i2c_client *client) 762968cf782SDevin Heitmueller { 763968cf782SDevin Heitmueller struct v4l2_subdev *sd = i2c_get_clientdata(client); 764968cf782SDevin Heitmueller v4l2_device_unregister_subdev(sd); 7655a4bdb4bSHans Verkuil v4l2_ctrl_handler_free(sd->ctrl_handler); 766968cf782SDevin Heitmueller au8522_release_state(to_state(sd)); 767968cf782SDevin Heitmueller return 0; 768968cf782SDevin Heitmueller } 769968cf782SDevin Heitmueller 770968cf782SDevin Heitmueller static const struct i2c_device_id au8522_id[] = { 771968cf782SDevin Heitmueller {"au8522", 0}, 772968cf782SDevin Heitmueller {} 773968cf782SDevin Heitmueller }; 774968cf782SDevin Heitmueller 775968cf782SDevin Heitmueller MODULE_DEVICE_TABLE(i2c, au8522_id); 776968cf782SDevin Heitmueller 777978cff6bSHans Verkuil static struct i2c_driver au8522_driver = { 778978cff6bSHans Verkuil .driver = { 779968cf782SDevin Heitmueller .name = "au8522", 780978cff6bSHans Verkuil }, 781968cf782SDevin Heitmueller .probe = au8522_probe, 782968cf782SDevin Heitmueller .remove = au8522_remove, 783968cf782SDevin Heitmueller .id_table = au8522_id, 784968cf782SDevin Heitmueller }; 785978cff6bSHans Verkuil 786c6e8d86fSAxel Lin module_i2c_driver(au8522_driver); 787