18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Auvitek AU8522 QAM/8VSB demodulator driver and video decoder
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
68c2ecf20Sopenharmony_ci * Copyright (C) 2005-2008 Auvitek International, Ltd.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci/* Developer notes:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Enough is implemented here for CVBS and S-Video inputs, but the actual
128c2ecf20Sopenharmony_ci *  analog demodulator code isn't implemented (not needed for xc5000 since it
138c2ecf20Sopenharmony_ci *  has its own demodulator and outputs CVBS)
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
208c2ecf20Sopenharmony_ci#include <linux/i2c.h>
218c2ecf20Sopenharmony_ci#include <linux/delay.h>
228c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
238c2ecf20Sopenharmony_ci#include <media/v4l2-device.h>
248c2ecf20Sopenharmony_ci#include "au8522.h"
258c2ecf20Sopenharmony_ci#include "au8522_priv.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Devin Heitmueller");
288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic int au8522_analog_debug;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cimodule_param_named(analog_debug, au8522_analog_debug, int, 0644);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(analog_debug,
368c2ecf20Sopenharmony_ci		 "Analog debugging messages [0=Off (default) 1=On]");
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct au8522_register_config {
398c2ecf20Sopenharmony_ci	u16 reg_name;
408c2ecf20Sopenharmony_ci	u8 reg_val[8];
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* Video Decoder Filter Coefficients
458c2ecf20Sopenharmony_ci   The values are as follows from left to right
468c2ecf20Sopenharmony_ci   0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
478c2ecf20Sopenharmony_ci*/
488c2ecf20Sopenharmony_cistatic const struct au8522_register_config filter_coef[] = {
498c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
508c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
518c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
528c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} },
538c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} },
548c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} },
558c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} },
568c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} },
578c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} },
588c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} },
598c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} },
608c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} },
618c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} },
628c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} },
638c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} },
648c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} },
658c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} },
668c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} },
678c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} },
688c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} },
698c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} },
708c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} },
718c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} },
728c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} },
738c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} },
748c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} },
758c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} },
768c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} },
778c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} },
788c2ecf20Sopenharmony_ci	{AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} },
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci};
818c2ecf20Sopenharmony_ci#define NUM_FILTER_COEF (sizeof(filter_coef)\
828c2ecf20Sopenharmony_ci			 / sizeof(struct au8522_register_config))
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* Registers 0x060b through 0x0652 are the LP Filter coefficients
868c2ecf20Sopenharmony_ci   The values are as follows from left to right
878c2ecf20Sopenharmony_ci   0="SIF" 1="ATVRF/ATVRF13"
888c2ecf20Sopenharmony_ci   Note: the "ATVRF/ATVRF13" mode has never been tested
898c2ecf20Sopenharmony_ci*/
908c2ecf20Sopenharmony_cistatic const struct au8522_register_config lpfilter_coef[] = {
918c2ecf20Sopenharmony_ci	{0x060b, {0x21, 0x0b} },
928c2ecf20Sopenharmony_ci	{0x060c, {0xad, 0xad} },
938c2ecf20Sopenharmony_ci	{0x060d, {0x70, 0xf0} },
948c2ecf20Sopenharmony_ci	{0x060e, {0xea, 0xe9} },
958c2ecf20Sopenharmony_ci	{0x060f, {0xdd, 0xdd} },
968c2ecf20Sopenharmony_ci	{0x0610, {0x08, 0x64} },
978c2ecf20Sopenharmony_ci	{0x0611, {0x60, 0x60} },
988c2ecf20Sopenharmony_ci	{0x0612, {0xf8, 0xb2} },
998c2ecf20Sopenharmony_ci	{0x0613, {0x01, 0x02} },
1008c2ecf20Sopenharmony_ci	{0x0614, {0xe4, 0xb4} },
1018c2ecf20Sopenharmony_ci	{0x0615, {0x19, 0x02} },
1028c2ecf20Sopenharmony_ci	{0x0616, {0xae, 0x2e} },
1038c2ecf20Sopenharmony_ci	{0x0617, {0xee, 0xc5} },
1048c2ecf20Sopenharmony_ci	{0x0618, {0x56, 0x56} },
1058c2ecf20Sopenharmony_ci	{0x0619, {0x30, 0x58} },
1068c2ecf20Sopenharmony_ci	{0x061a, {0xf9, 0xf8} },
1078c2ecf20Sopenharmony_ci	{0x061b, {0x24, 0x64} },
1088c2ecf20Sopenharmony_ci	{0x061c, {0x07, 0x07} },
1098c2ecf20Sopenharmony_ci	{0x061d, {0x30, 0x30} },
1108c2ecf20Sopenharmony_ci	{0x061e, {0xa9, 0xed} },
1118c2ecf20Sopenharmony_ci	{0x061f, {0x09, 0x0b} },
1128c2ecf20Sopenharmony_ci	{0x0620, {0x42, 0xc2} },
1138c2ecf20Sopenharmony_ci	{0x0621, {0x1d, 0x2a} },
1148c2ecf20Sopenharmony_ci	{0x0622, {0xd6, 0x56} },
1158c2ecf20Sopenharmony_ci	{0x0623, {0x95, 0x8b} },
1168c2ecf20Sopenharmony_ci	{0x0624, {0x2b, 0x2b} },
1178c2ecf20Sopenharmony_ci	{0x0625, {0x30, 0x24} },
1188c2ecf20Sopenharmony_ci	{0x0626, {0x3e, 0x3e} },
1198c2ecf20Sopenharmony_ci	{0x0627, {0x62, 0xe2} },
1208c2ecf20Sopenharmony_ci	{0x0628, {0xe9, 0xf5} },
1218c2ecf20Sopenharmony_ci	{0x0629, {0x99, 0x19} },
1228c2ecf20Sopenharmony_ci	{0x062a, {0xd4, 0x11} },
1238c2ecf20Sopenharmony_ci	{0x062b, {0x03, 0x04} },
1248c2ecf20Sopenharmony_ci	{0x062c, {0xb5, 0x85} },
1258c2ecf20Sopenharmony_ci	{0x062d, {0x1e, 0x20} },
1268c2ecf20Sopenharmony_ci	{0x062e, {0x2a, 0xea} },
1278c2ecf20Sopenharmony_ci	{0x062f, {0xd7, 0xd2} },
1288c2ecf20Sopenharmony_ci	{0x0630, {0x15, 0x15} },
1298c2ecf20Sopenharmony_ci	{0x0631, {0xa3, 0xa9} },
1308c2ecf20Sopenharmony_ci	{0x0632, {0x1f, 0x1f} },
1318c2ecf20Sopenharmony_ci	{0x0633, {0xf9, 0xd1} },
1328c2ecf20Sopenharmony_ci	{0x0634, {0xc0, 0xc3} },
1338c2ecf20Sopenharmony_ci	{0x0635, {0x4d, 0x8d} },
1348c2ecf20Sopenharmony_ci	{0x0636, {0x21, 0x31} },
1358c2ecf20Sopenharmony_ci	{0x0637, {0x83, 0x83} },
1368c2ecf20Sopenharmony_ci	{0x0638, {0x08, 0x8c} },
1378c2ecf20Sopenharmony_ci	{0x0639, {0x19, 0x19} },
1388c2ecf20Sopenharmony_ci	{0x063a, {0x45, 0xa5} },
1398c2ecf20Sopenharmony_ci	{0x063b, {0xef, 0xec} },
1408c2ecf20Sopenharmony_ci	{0x063c, {0x8a, 0x8a} },
1418c2ecf20Sopenharmony_ci	{0x063d, {0xf4, 0xf6} },
1428c2ecf20Sopenharmony_ci	{0x063e, {0x8f, 0x8f} },
1438c2ecf20Sopenharmony_ci	{0x063f, {0x44, 0x0c} },
1448c2ecf20Sopenharmony_ci	{0x0640, {0xef, 0xf0} },
1458c2ecf20Sopenharmony_ci	{0x0641, {0x66, 0x66} },
1468c2ecf20Sopenharmony_ci	{0x0642, {0xcc, 0xd2} },
1478c2ecf20Sopenharmony_ci	{0x0643, {0x41, 0x41} },
1488c2ecf20Sopenharmony_ci	{0x0644, {0x63, 0x93} },
1498c2ecf20Sopenharmony_ci	{0x0645, {0x8e, 0x8e} },
1508c2ecf20Sopenharmony_ci	{0x0646, {0xa2, 0x42} },
1518c2ecf20Sopenharmony_ci	{0x0647, {0x7b, 0x7b} },
1528c2ecf20Sopenharmony_ci	{0x0648, {0x04, 0x04} },
1538c2ecf20Sopenharmony_ci	{0x0649, {0x00, 0x00} },
1548c2ecf20Sopenharmony_ci	{0x064a, {0x40, 0x40} },
1558c2ecf20Sopenharmony_ci	{0x064b, {0x8c, 0x98} },
1568c2ecf20Sopenharmony_ci	{0x064c, {0x00, 0x00} },
1578c2ecf20Sopenharmony_ci	{0x064d, {0x63, 0xc3} },
1588c2ecf20Sopenharmony_ci	{0x064e, {0x04, 0x04} },
1598c2ecf20Sopenharmony_ci	{0x064f, {0x20, 0x20} },
1608c2ecf20Sopenharmony_ci	{0x0650, {0x00, 0x00} },
1618c2ecf20Sopenharmony_ci	{0x0651, {0x40, 0x40} },
1628c2ecf20Sopenharmony_ci	{0x0652, {0x01, 0x01} },
1638c2ecf20Sopenharmony_ci};
1648c2ecf20Sopenharmony_ci#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\
1658c2ecf20Sopenharmony_ci			   / sizeof(struct au8522_register_config))
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic inline struct au8522_state *to_state(struct v4l2_subdev *sd)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	return container_of(sd, struct au8522_state, sd);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic void setup_decoder_defaults(struct au8522_state *state, bool is_svideo)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	int i;
1758c2ecf20Sopenharmony_ci	int filter_coef_type;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Provide reasonable defaults for picture tuning values */
1788c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
1798c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
1808c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
1818c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
1828c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
1838c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
1848c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* Other decoder registers */
1878c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (is_svideo)
1908c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
1918c2ecf20Sopenharmony_ci	else
1928c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
1958c2ecf20Sopenharmony_ci			AU8522_TVDEC_PGA_REG012H_CVBS);
1968c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H,
1978c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
1988c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
1998c2ecf20Sopenharmony_ci			AU8522_TVDED_DBG_MODE_REG060H_CVBS);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (state->std == V4L2_STD_PAL_M) {
2028c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
2038c2ecf20Sopenharmony_ci				AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
2048c2ecf20Sopenharmony_ci				AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
2058c2ecf20Sopenharmony_ci				AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO);
2068c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
2078c2ecf20Sopenharmony_ci				AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_PAL_M);
2088c2ecf20Sopenharmony_ci	} else {
2098c2ecf20Sopenharmony_ci		/* NTSC */
2108c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
2118c2ecf20Sopenharmony_ci				AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
2128c2ecf20Sopenharmony_ci				AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
2138c2ecf20Sopenharmony_ci				AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
2148c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
2158c2ecf20Sopenharmony_ci				AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
2188c2ecf20Sopenharmony_ci			AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
2198c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
2208c2ecf20Sopenharmony_ci			AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS);
2218c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H,
2228c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS);
2238c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H,
2248c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS);
2258c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H,
2268c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS);
2278c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H,
2288c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS);
2298c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H,
2308c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS);
2318c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH,
2328c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
2338c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
2348c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
2358c2ecf20Sopenharmony_ci	if (is_svideo) {
2368c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
2378c2ecf20Sopenharmony_ci				AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
2388c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
2398c2ecf20Sopenharmony_ci				AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO);
2408c2ecf20Sopenharmony_ci	} else {
2418c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
2428c2ecf20Sopenharmony_ci				AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
2438c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
2448c2ecf20Sopenharmony_ci				AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
2478c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
2488c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
2498c2ecf20Sopenharmony_ci			AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS);
2508c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H,
2518c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS);
2528c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS);
2538c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS);
2548c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H,
2558c2ecf20Sopenharmony_ci			AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS);
2568c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS);
2578c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS);
2588c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H,
2598c2ecf20Sopenharmony_ci			AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS);
2608c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H,
2618c2ecf20Sopenharmony_ci			AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS);
2628c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H,
2638c2ecf20Sopenharmony_ci			AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS);
2648c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH,
2658c2ecf20Sopenharmony_ci			AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS);
2668c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH,
2678c2ecf20Sopenharmony_ci			AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS);
2688c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H,
2698c2ecf20Sopenharmony_ci			AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS);
2708c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H,
2718c2ecf20Sopenharmony_ci			AU8522_TOREGAAGC_REG0E5H_CVBS);
2728c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/*
2758c2ecf20Sopenharmony_ci	 * Despite what the table says, for the HVR-950q we still need
2768c2ecf20Sopenharmony_ci	 * to be in CVBS mode for the S-Video input (reason unknown).
2778c2ecf20Sopenharmony_ci	 */
2788c2ecf20Sopenharmony_ci	/* filter_coef_type = 3; */
2798c2ecf20Sopenharmony_ci	filter_coef_type = 5;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	/* Load the Video Decoder Filter Coefficients */
2828c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_FILTER_COEF; i++) {
2838c2ecf20Sopenharmony_ci		au8522_writereg(state, filter_coef[i].reg_name,
2848c2ecf20Sopenharmony_ci				filter_coef[i].reg_val[filter_coef_type]);
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/* It's not clear what these registers are for, but they are always
2888c2ecf20Sopenharmony_ci	   set to the same value regardless of what mode we're in */
2898c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG42EH, 0x87);
2908c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG42FH, 0xa2);
2918c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG430H, 0xbf);
2928c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG431H, 0xcb);
2938c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG432H, 0xa1);
2948c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG433H, 0x41);
2958c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG434H, 0x88);
2968c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG435H, 0xc2);
2978c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG436H, 0x3c);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic void au8522_setup_cvbs_mode(struct au8522_state *state, u8 input_mode)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	/* here we're going to try the pre-programmed route */
3038c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
3048c2ecf20Sopenharmony_ci			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* PGA in automatic mode */
3078c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	/* Enable clamping control */
3108c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	setup_decoder_defaults(state, false);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
3178c2ecf20Sopenharmony_ci			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic void au8522_setup_cvbs_tuner_mode(struct au8522_state *state,
3218c2ecf20Sopenharmony_ci					 u8 input_mode)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	/* here we're going to try the pre-programmed route */
3248c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
3258c2ecf20Sopenharmony_ci			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* It's not clear why we have to have the PGA in automatic mode while
3288c2ecf20Sopenharmony_ci	   enabling clamp control, but it's what Windows does */
3298c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* Enable clamping control */
3328c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* Disable automatic PGA (since the CVBS is coming from the tuner) */
3358c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* Set input mode to CVBS on channel 4 with SIF audio input enabled */
3388c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	setup_decoder_defaults(state, false);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
3438c2ecf20Sopenharmony_ci			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void au8522_setup_svideo_mode(struct au8522_state *state,
3478c2ecf20Sopenharmony_ci				     u8 input_mode)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
3508c2ecf20Sopenharmony_ci			AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* Set input to Y on Channe1, C on Channel 3 */
3538c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/* PGA in automatic mode */
3568c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/* Enable clamping control */
3598c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	setup_decoder_defaults(state, true);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
3648c2ecf20Sopenharmony_ci			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void disable_audio_input(struct au8522_state *state)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
3728c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
3738c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
3768c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
3798c2ecf20Sopenharmony_ci			AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci/* 0=disable, 1=SIF */
3838c2ecf20Sopenharmony_cistatic void set_audio_input(struct au8522_state *state)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	int aud_input = state->aud_input;
3868c2ecf20Sopenharmony_ci	int i;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	/* Note that this function needs to be used in conjunction with setting
3898c2ecf20Sopenharmony_ci	   the input routing via register 0x81 */
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if (aud_input == AU8522_AUDIO_NONE) {
3928c2ecf20Sopenharmony_ci		disable_audio_input(state);
3938c2ecf20Sopenharmony_ci		return;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (aud_input != AU8522_AUDIO_SIF) {
3978c2ecf20Sopenharmony_ci		/* The caller asked for a mode we don't currently support */
3988c2ecf20Sopenharmony_ci		printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n",
3998c2ecf20Sopenharmony_ci		       aud_input);
4008c2ecf20Sopenharmony_ci		return;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* Load the Audio Decoder Filter Coefficients */
4048c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_LPFILTER_COEF; i++) {
4058c2ecf20Sopenharmony_ci		au8522_writereg(state, lpfilter_coef[i].reg_name,
4068c2ecf20Sopenharmony_ci				lpfilter_coef[i].reg_val[0]);
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* Set the volume */
4108c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
4118c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
4128c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* Not sure what this does */
4158c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/* Setup the audio mode to stereo DBX */
4188c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82);
4198c2ecf20Sopenharmony_ci	msleep(70);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	/* Start the audio processing module */
4228c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* Set the audio frequency to 48 KHz */
4258c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/* Set the I2S parameters (WS, LSB, mode, sample rate */
4288c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* Enable the I2S output */
4318c2ecf20Sopenharmony_ci	au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09);
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int au8522_s_ctrl(struct v4l2_ctrl *ctrl)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	struct au8522_state *state =
4398c2ecf20Sopenharmony_ci		container_of(ctrl->handler, struct au8522_state, hdl);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	switch (ctrl->id) {
4428c2ecf20Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
4438c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
4448c2ecf20Sopenharmony_ci				ctrl->val - 128);
4458c2ecf20Sopenharmony_ci		break;
4468c2ecf20Sopenharmony_ci	case V4L2_CID_CONTRAST:
4478c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
4488c2ecf20Sopenharmony_ci				ctrl->val);
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci	case V4L2_CID_SATURATION:
4518c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
4528c2ecf20Sopenharmony_ci				ctrl->val);
4538c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
4548c2ecf20Sopenharmony_ci				ctrl->val);
4558c2ecf20Sopenharmony_ci		break;
4568c2ecf20Sopenharmony_ci	case V4L2_CID_HUE:
4578c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
4588c2ecf20Sopenharmony_ci				ctrl->val >> 8);
4598c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
4608c2ecf20Sopenharmony_ci				ctrl->val & 0xFF);
4618c2ecf20Sopenharmony_ci		break;
4628c2ecf20Sopenharmony_ci	default:
4638c2ecf20Sopenharmony_ci		return -EINVAL;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return 0;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
4728c2ecf20Sopenharmony_cistatic int au8522_g_register(struct v4l2_subdev *sd,
4738c2ecf20Sopenharmony_ci			     struct v4l2_dbg_register *reg)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct au8522_state *state = to_state(sd);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	reg->val = au8522_readreg(state, reg->reg & 0xffff);
4788c2ecf20Sopenharmony_ci	return 0;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic int au8522_s_register(struct v4l2_subdev *sd,
4828c2ecf20Sopenharmony_ci			     const struct v4l2_dbg_register *reg)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct au8522_state *state = to_state(sd);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	au8522_writereg(state, reg->reg, reg->val & 0xff);
4878c2ecf20Sopenharmony_ci	return 0;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci#endif
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic void au8522_video_set(struct au8522_state *state)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	u8 input_mode;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	au8522_writereg(state, 0xa4, 1 << 5);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	switch (state->vid_input) {
4988c2ecf20Sopenharmony_ci	case AU8522_COMPOSITE_CH1:
4998c2ecf20Sopenharmony_ci		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH1;
5008c2ecf20Sopenharmony_ci		au8522_setup_cvbs_mode(state, input_mode);
5018c2ecf20Sopenharmony_ci		break;
5028c2ecf20Sopenharmony_ci	case AU8522_COMPOSITE_CH2:
5038c2ecf20Sopenharmony_ci		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH2;
5048c2ecf20Sopenharmony_ci		au8522_setup_cvbs_mode(state, input_mode);
5058c2ecf20Sopenharmony_ci		break;
5068c2ecf20Sopenharmony_ci	case AU8522_COMPOSITE_CH3:
5078c2ecf20Sopenharmony_ci		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH3;
5088c2ecf20Sopenharmony_ci		au8522_setup_cvbs_mode(state, input_mode);
5098c2ecf20Sopenharmony_ci		break;
5108c2ecf20Sopenharmony_ci	case AU8522_COMPOSITE_CH4:
5118c2ecf20Sopenharmony_ci		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4;
5128c2ecf20Sopenharmony_ci		au8522_setup_cvbs_mode(state, input_mode);
5138c2ecf20Sopenharmony_ci		break;
5148c2ecf20Sopenharmony_ci	case AU8522_SVIDEO_CH13:
5158c2ecf20Sopenharmony_ci		input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13;
5168c2ecf20Sopenharmony_ci		au8522_setup_svideo_mode(state, input_mode);
5178c2ecf20Sopenharmony_ci		break;
5188c2ecf20Sopenharmony_ci	case AU8522_SVIDEO_CH24:
5198c2ecf20Sopenharmony_ci		input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24;
5208c2ecf20Sopenharmony_ci		au8522_setup_svideo_mode(state, input_mode);
5218c2ecf20Sopenharmony_ci		break;
5228c2ecf20Sopenharmony_ci	default:
5238c2ecf20Sopenharmony_ci	case AU8522_COMPOSITE_CH4_SIF:
5248c2ecf20Sopenharmony_ci		input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF;
5258c2ecf20Sopenharmony_ci		au8522_setup_cvbs_tuner_mode(state, input_mode);
5268c2ecf20Sopenharmony_ci		break;
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic int au8522_s_stream(struct v4l2_subdev *sd, int enable)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct au8522_state *state = to_state(sd);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (enable) {
5358c2ecf20Sopenharmony_ci		/*
5368c2ecf20Sopenharmony_ci		 * Clear out any state associated with the digital side of the
5378c2ecf20Sopenharmony_ci		 * chip, so that when it gets powered back up it won't think
5388c2ecf20Sopenharmony_ci		 * that it is already tuned
5398c2ecf20Sopenharmony_ci		 */
5408c2ecf20Sopenharmony_ci		state->current_frequency = 0;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
5438c2ecf20Sopenharmony_ci				0x01);
5448c2ecf20Sopenharmony_ci		msleep(10);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		au8522_video_set(state);
5478c2ecf20Sopenharmony_ci		set_audio_input(state);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		state->operational_mode = AU8522_ANALOG_MODE;
5508c2ecf20Sopenharmony_ci	} else {
5518c2ecf20Sopenharmony_ci		/* This does not completely power down the device
5528c2ecf20Sopenharmony_ci		   (it only reduces it from around 140ma to 80ma) */
5538c2ecf20Sopenharmony_ci		au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
5548c2ecf20Sopenharmony_ci				1 << 5);
5558c2ecf20Sopenharmony_ci		state->operational_mode = AU8522_SUSPEND_MODE;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci	return 0;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic int au8522_s_video_routing(struct v4l2_subdev *sd,
5618c2ecf20Sopenharmony_ci					u32 input, u32 output, u32 config)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	struct au8522_state *state = to_state(sd);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	switch (input) {
5668c2ecf20Sopenharmony_ci	case AU8522_COMPOSITE_CH1:
5678c2ecf20Sopenharmony_ci	case AU8522_SVIDEO_CH13:
5688c2ecf20Sopenharmony_ci	case AU8522_COMPOSITE_CH4_SIF:
5698c2ecf20Sopenharmony_ci		state->vid_input = input;
5708c2ecf20Sopenharmony_ci		break;
5718c2ecf20Sopenharmony_ci	default:
5728c2ecf20Sopenharmony_ci		printk(KERN_ERR "au8522 mode not currently supported\n");
5738c2ecf20Sopenharmony_ci		return -EINVAL;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (state->operational_mode == AU8522_ANALOG_MODE)
5778c2ecf20Sopenharmony_ci		au8522_video_set(state);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	return 0;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic int au8522_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	struct au8522_state *state = to_state(sd);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if ((std & (V4L2_STD_PAL_M | V4L2_STD_NTSC_M)) == 0)
5878c2ecf20Sopenharmony_ci		return -EINVAL;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	state->std = std;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (state->operational_mode == AU8522_ANALOG_MODE)
5928c2ecf20Sopenharmony_ci		au8522_video_set(state);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	return 0;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int au8522_s_audio_routing(struct v4l2_subdev *sd,
5988c2ecf20Sopenharmony_ci					u32 input, u32 output, u32 config)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	struct au8522_state *state = to_state(sd);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	state->aud_input = input;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	if (state->operational_mode == AU8522_ANALOG_MODE)
6058c2ecf20Sopenharmony_ci		set_audio_input(state);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	return 0;
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistatic int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	int val = 0;
6138c2ecf20Sopenharmony_ci	struct au8522_state *state = to_state(sd);
6148c2ecf20Sopenharmony_ci	u8 lock_status;
6158c2ecf20Sopenharmony_ci	u8 pll_status;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	/* Interrogate the decoder to see if we are getting a real signal */
6188c2ecf20Sopenharmony_ci	lock_status = au8522_readreg(state, 0x00);
6198c2ecf20Sopenharmony_ci	pll_status = au8522_readreg(state, 0x7e);
6208c2ecf20Sopenharmony_ci	if ((lock_status == 0xa2) && (pll_status & 0x10))
6218c2ecf20Sopenharmony_ci		vt->signal = 0xffff;
6228c2ecf20Sopenharmony_ci	else
6238c2ecf20Sopenharmony_ci		vt->signal = 0x00;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	vt->capability |=
6268c2ecf20Sopenharmony_ci		V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
6278c2ecf20Sopenharmony_ci		V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	val = V4L2_TUNER_SUB_MONO;
6308c2ecf20Sopenharmony_ci	vt->rxsubchans = val;
6318c2ecf20Sopenharmony_ci	vt->audmode = V4L2_TUNER_MODE_STEREO;
6328c2ecf20Sopenharmony_ci	return 0;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops au8522_core_ops = {
6388c2ecf20Sopenharmony_ci	.log_status = v4l2_ctrl_subdev_log_status,
6398c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
6408c2ecf20Sopenharmony_ci	.g_register = au8522_g_register,
6418c2ecf20Sopenharmony_ci	.s_register = au8522_s_register,
6428c2ecf20Sopenharmony_ci#endif
6438c2ecf20Sopenharmony_ci};
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_tuner_ops au8522_tuner_ops = {
6468c2ecf20Sopenharmony_ci	.g_tuner = au8522_g_tuner,
6478c2ecf20Sopenharmony_ci};
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_audio_ops au8522_audio_ops = {
6508c2ecf20Sopenharmony_ci	.s_routing = au8522_s_audio_routing,
6518c2ecf20Sopenharmony_ci};
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops au8522_video_ops = {
6548c2ecf20Sopenharmony_ci	.s_routing = au8522_s_video_routing,
6558c2ecf20Sopenharmony_ci	.s_stream = au8522_s_stream,
6568c2ecf20Sopenharmony_ci	.s_std = au8522_s_std,
6578c2ecf20Sopenharmony_ci};
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops au8522_ops = {
6608c2ecf20Sopenharmony_ci	.core = &au8522_core_ops,
6618c2ecf20Sopenharmony_ci	.tuner = &au8522_tuner_ops,
6628c2ecf20Sopenharmony_ci	.audio = &au8522_audio_ops,
6638c2ecf20Sopenharmony_ci	.video = &au8522_video_ops,
6648c2ecf20Sopenharmony_ci};
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops au8522_ctrl_ops = {
6678c2ecf20Sopenharmony_ci	.s_ctrl = au8522_s_ctrl,
6688c2ecf20Sopenharmony_ci};
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic int au8522_probe(struct i2c_client *client,
6738c2ecf20Sopenharmony_ci			const struct i2c_device_id *did)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	struct au8522_state *state;
6768c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler *hdl;
6778c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd;
6788c2ecf20Sopenharmony_ci	int instance;
6798c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER
6808c2ecf20Sopenharmony_ci	int ret;
6818c2ecf20Sopenharmony_ci#endif
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	/* Check if the adapter supports the needed features */
6848c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
6858c2ecf20Sopenharmony_ci				     I2C_FUNC_SMBUS_BYTE_DATA)) {
6868c2ecf20Sopenharmony_ci		return -EIO;
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	/* allocate memory for the internal state */
6908c2ecf20Sopenharmony_ci	instance = au8522_get_state(&state, client->adapter, client->addr);
6918c2ecf20Sopenharmony_ci	switch (instance) {
6928c2ecf20Sopenharmony_ci	case 0:
6938c2ecf20Sopenharmony_ci		printk(KERN_ERR "au8522_decoder allocation failed\n");
6948c2ecf20Sopenharmony_ci		return -EIO;
6958c2ecf20Sopenharmony_ci	case 1:
6968c2ecf20Sopenharmony_ci		/* new demod instance */
6978c2ecf20Sopenharmony_ci		printk(KERN_INFO "au8522_decoder creating new instance...\n");
6988c2ecf20Sopenharmony_ci		break;
6998c2ecf20Sopenharmony_ci	default:
7008c2ecf20Sopenharmony_ci		/* existing demod instance */
7018c2ecf20Sopenharmony_ci		printk(KERN_INFO "au8522_decoder attach existing instance.\n");
7028c2ecf20Sopenharmony_ci		break;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	state->config.demod_address = 0x8e >> 1;
7068c2ecf20Sopenharmony_ci	state->i2c = client->adapter;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	sd = &state->sd;
7098c2ecf20Sopenharmony_ci	v4l2_i2c_subdev_init(sd, client, &au8522_ops);
7108c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	state->pads[AU8522_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
7138c2ecf20Sopenharmony_ci	state->pads[AU8522_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
7148c2ecf20Sopenharmony_ci	state->pads[AU8522_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
7158c2ecf20Sopenharmony_ci	state->pads[AU8522_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
7168c2ecf20Sopenharmony_ci	state->pads[AU8522_PAD_AUDIO_OUT].flags = MEDIA_PAD_FL_SOURCE;
7178c2ecf20Sopenharmony_ci	state->pads[AU8522_PAD_AUDIO_OUT].sig_type = PAD_SIGNAL_AUDIO;
7188c2ecf20Sopenharmony_ci	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
7218c2ecf20Sopenharmony_ci				state->pads);
7228c2ecf20Sopenharmony_ci	if (ret < 0) {
7238c2ecf20Sopenharmony_ci		v4l_info(client, "failed to initialize media entity!\n");
7248c2ecf20Sopenharmony_ci		return ret;
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci#endif
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	hdl = &state->hdl;
7298c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 4);
7308c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
7318c2ecf20Sopenharmony_ci			V4L2_CID_BRIGHTNESS, 0, 255, 1, 109);
7328c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
7338c2ecf20Sopenharmony_ci			V4L2_CID_CONTRAST, 0, 255, 1,
7348c2ecf20Sopenharmony_ci			AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
7358c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
7368c2ecf20Sopenharmony_ci			V4L2_CID_SATURATION, 0, 255, 1, 128);
7378c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
7388c2ecf20Sopenharmony_ci			V4L2_CID_HUE, -32768, 32767, 1, 0);
7398c2ecf20Sopenharmony_ci	sd->ctrl_handler = hdl;
7408c2ecf20Sopenharmony_ci	if (hdl->error) {
7418c2ecf20Sopenharmony_ci		int err = hdl->error;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci		v4l2_ctrl_handler_free(hdl);
7448c2ecf20Sopenharmony_ci		au8522_release_state(state);
7458c2ecf20Sopenharmony_ci		return err;
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	state->c = client;
7498c2ecf20Sopenharmony_ci	state->std = V4L2_STD_NTSC_M;
7508c2ecf20Sopenharmony_ci	state->vid_input = AU8522_COMPOSITE_CH1;
7518c2ecf20Sopenharmony_ci	state->aud_input = AU8522_AUDIO_NONE;
7528c2ecf20Sopenharmony_ci	state->id = 8522;
7538c2ecf20Sopenharmony_ci	state->rev = 0;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	/* Jam open the i2c gate to the tuner */
7568c2ecf20Sopenharmony_ci	au8522_writereg(state, 0x106, 1);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	return 0;
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic int au8522_remove(struct i2c_client *client)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
7648c2ecf20Sopenharmony_ci	v4l2_device_unregister_subdev(sd);
7658c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(sd->ctrl_handler);
7668c2ecf20Sopenharmony_ci	au8522_release_state(to_state(sd));
7678c2ecf20Sopenharmony_ci	return 0;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic const struct i2c_device_id au8522_id[] = {
7718c2ecf20Sopenharmony_ci	{"au8522", 0},
7728c2ecf20Sopenharmony_ci	{}
7738c2ecf20Sopenharmony_ci};
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, au8522_id);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic struct i2c_driver au8522_driver = {
7788c2ecf20Sopenharmony_ci	.driver = {
7798c2ecf20Sopenharmony_ci		.name	= "au8522",
7808c2ecf20Sopenharmony_ci	},
7818c2ecf20Sopenharmony_ci	.probe		= au8522_probe,
7828c2ecf20Sopenharmony_ci	.remove		= au8522_remove,
7838c2ecf20Sopenharmony_ci	.id_table	= au8522_id,
7848c2ecf20Sopenharmony_ci};
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cimodule_i2c_driver(au8522_driver);
787