cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

saa717x.c (32459B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * saa717x - Philips SAA717xHL video decoder driver
      4 *
      5 * Based on the saa7115 driver
      6 *
      7 * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
      8 *    - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
      9 *
     10 * Changes by T.Adachi (tadachi@tadachi-net.com)
     11 *    - support audio, video scaler etc, and checked the initialize sequence.
     12 *
     13 * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
     14 *
     15 * Note: this is a reversed engineered driver based on captures from
     16 * the I2C bus under Windows. This chip is very similar to the saa7134,
     17 * though. Unfortunately, this driver is currently only working for NTSC.
     18 */
     19
     20#include <linux/module.h>
     21#include <linux/kernel.h>
     22#include <linux/slab.h>
     23#include <linux/sched.h>
     24
     25#include <linux/videodev2.h>
     26#include <linux/i2c.h>
     27#include <media/v4l2-device.h>
     28#include <media/v4l2-ctrls.h>
     29
     30MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
     31MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
     32MODULE_LICENSE("GPL");
     33
     34static int debug;
     35module_param(debug, int, 0644);
     36MODULE_PARM_DESC(debug, "Debug level (0-1)");
     37
     38/*
     39 * Generic i2c probe
     40 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
     41 */
     42
     43struct saa717x_state {
     44	struct v4l2_subdev sd;
     45	struct v4l2_ctrl_handler hdl;
     46	v4l2_std_id std;
     47	int input;
     48	int enable;
     49	int radio;
     50	int playback;
     51	int audio;
     52	int tuner_audio_mode;
     53	int audio_main_mute;
     54	int audio_main_vol_r;
     55	int audio_main_vol_l;
     56	u16 audio_main_bass;
     57	u16 audio_main_treble;
     58	u16 audio_main_volume;
     59	u16 audio_main_balance;
     60	int audio_input;
     61};
     62
     63static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
     64{
     65	return container_of(sd, struct saa717x_state, sd);
     66}
     67
     68static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
     69{
     70	return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd;
     71}
     72
     73/* ----------------------------------------------------------------------- */
     74
     75/* for audio mode */
     76#define TUNER_AUDIO_MONO	0  /* LL */
     77#define TUNER_AUDIO_STEREO	1  /* LR */
     78#define TUNER_AUDIO_LANG1	2  /* LL */
     79#define TUNER_AUDIO_LANG2	3  /* RR */
     80
     81#define SAA717X_NTSC_WIDTH	(704)
     82#define SAA717X_NTSC_HEIGHT	(480)
     83
     84/* ----------------------------------------------------------------------- */
     85
     86static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
     87{
     88	struct i2c_client *client = v4l2_get_subdevdata(sd);
     89	struct i2c_adapter *adap = client->adapter;
     90	int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
     91	unsigned char mm1[6];
     92	struct i2c_msg msg;
     93
     94	msg.flags = 0;
     95	msg.addr = client->addr;
     96	mm1[0] = (reg >> 8) & 0xff;
     97	mm1[1] = reg & 0xff;
     98
     99	if (fw_addr) {
    100		mm1[4] = (value >> 16) & 0xff;
    101		mm1[3] = (value >> 8) & 0xff;
    102		mm1[2] = value & 0xff;
    103	} else {
    104		mm1[2] = value & 0xff;
    105	}
    106	msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
    107	msg.buf = mm1;
    108	v4l2_dbg(2, debug, sd, "wrote:  reg 0x%03x=%08x\n", reg, value);
    109	return i2c_transfer(adap, &msg, 1) == 1;
    110}
    111
    112static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
    113{
    114	while (data[0] || data[1]) {
    115		saa717x_write(sd, data[0], data[1]);
    116		data += 2;
    117	}
    118}
    119
    120static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
    121{
    122	struct i2c_client *client = v4l2_get_subdevdata(sd);
    123	struct i2c_adapter *adap = client->adapter;
    124	int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
    125	unsigned char mm1[2];
    126	unsigned char mm2[4] = { 0, 0, 0, 0 };
    127	struct i2c_msg msgs[2];
    128	u32 value;
    129
    130	msgs[0].flags = 0;
    131	msgs[1].flags = I2C_M_RD;
    132	msgs[0].addr = msgs[1].addr = client->addr;
    133	mm1[0] = (reg >> 8) & 0xff;
    134	mm1[1] = reg & 0xff;
    135	msgs[0].len = 2;
    136	msgs[0].buf = mm1;
    137	msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
    138	msgs[1].buf = mm2;
    139	i2c_transfer(adap, msgs, 2);
    140
    141	if (fw_addr)
    142		value = (mm2[2] << 16)  | (mm2[1] << 8) | mm2[0];
    143	else
    144		value = mm2[0];
    145
    146	v4l2_dbg(2, debug, sd, "read:  reg 0x%03x=0x%08x\n", reg, value);
    147	return value;
    148}
    149
    150/* ----------------------------------------------------------------------- */
    151
    152static u32 reg_init_initialize[] =
    153{
    154	/* from linux driver */
    155	0x101, 0x008, /* Increment delay */
    156
    157	0x103, 0x000, /* Analog input control 2 */
    158	0x104, 0x090, /* Analog input control 3 */
    159	0x105, 0x090, /* Analog input control 4 */
    160	0x106, 0x0eb, /* Horizontal sync start */
    161	0x107, 0x0e0, /* Horizontal sync stop */
    162	0x109, 0x055, /* Luminance control */
    163
    164	0x10f, 0x02a, /* Chroma gain control */
    165	0x110, 0x000, /* Chroma control 2 */
    166
    167	0x114, 0x045, /* analog/ADC */
    168
    169	0x118, 0x040, /* RAW data gain */
    170	0x119, 0x080, /* RAW data offset */
    171
    172	0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
    173	0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
    174	0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
    175	0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
    176
    177	0x049, 0x000, /* VBI vertical input window start (H) TASK A */
    178
    179	0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
    180	0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
    181
    182	0x064, 0x080, /* Lumina brightness TASK A */
    183	0x065, 0x040, /* Luminance contrast TASK A */
    184	0x066, 0x040, /* Chroma saturation TASK A */
    185	/* 067H: Reserved */
    186	0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
    187	0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
    188	0x06a, 0x000, /* VBI phase offset TASK A */
    189
    190	0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
    191	0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
    192
    193	0x072, 0x000, /* Vertical filter mode TASK A */
    194
    195	0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
    196	0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
    197	0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
    198	0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
    199
    200	0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
    201
    202	0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
    203	0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
    204
    205	0x0a4, 0x080, /* Lumina brightness TASK B */
    206	0x0a5, 0x040, /* Luminance contrast TASK B */
    207	0x0a6, 0x040, /* Chroma saturation TASK B */
    208	/* 0A7H reserved */
    209	0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
    210	0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
    211	0x0aa, 0x000, /* VBI phase offset TASK B */
    212
    213	0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
    214	0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
    215
    216	0x0b2, 0x000, /* Vertical filter mode TASK B */
    217
    218	0x00c, 0x000, /* Start point GREEN path */
    219	0x00d, 0x000, /* Start point BLUE path */
    220	0x00e, 0x000, /* Start point RED path */
    221
    222	0x010, 0x010, /* GREEN path gamma curve --- */
    223	0x011, 0x020,
    224	0x012, 0x030,
    225	0x013, 0x040,
    226	0x014, 0x050,
    227	0x015, 0x060,
    228	0x016, 0x070,
    229	0x017, 0x080,
    230	0x018, 0x090,
    231	0x019, 0x0a0,
    232	0x01a, 0x0b0,
    233	0x01b, 0x0c0,
    234	0x01c, 0x0d0,
    235	0x01d, 0x0e0,
    236	0x01e, 0x0f0,
    237	0x01f, 0x0ff, /* --- GREEN path gamma curve */
    238
    239	0x020, 0x010, /* BLUE path gamma curve --- */
    240	0x021, 0x020,
    241	0x022, 0x030,
    242	0x023, 0x040,
    243	0x024, 0x050,
    244	0x025, 0x060,
    245	0x026, 0x070,
    246	0x027, 0x080,
    247	0x028, 0x090,
    248	0x029, 0x0a0,
    249	0x02a, 0x0b0,
    250	0x02b, 0x0c0,
    251	0x02c, 0x0d0,
    252	0x02d, 0x0e0,
    253	0x02e, 0x0f0,
    254	0x02f, 0x0ff, /* --- BLUE path gamma curve */
    255
    256	0x030, 0x010, /* RED path gamma curve --- */
    257	0x031, 0x020,
    258	0x032, 0x030,
    259	0x033, 0x040,
    260	0x034, 0x050,
    261	0x035, 0x060,
    262	0x036, 0x070,
    263	0x037, 0x080,
    264	0x038, 0x090,
    265	0x039, 0x0a0,
    266	0x03a, 0x0b0,
    267	0x03b, 0x0c0,
    268	0x03c, 0x0d0,
    269	0x03d, 0x0e0,
    270	0x03e, 0x0f0,
    271	0x03f, 0x0ff, /* --- RED path gamma curve */
    272
    273	0x109, 0x085, /* Luminance control  */
    274
    275	/**** from app start ****/
    276	0x584, 0x000, /* AGC gain control */
    277	0x585, 0x000, /* Program count */
    278	0x586, 0x003, /* Status reset */
    279	0x588, 0x0ff, /* Number of audio samples (L) */
    280	0x589, 0x00f, /* Number of audio samples (M) */
    281	0x58a, 0x000, /* Number of audio samples (H) */
    282	0x58b, 0x000, /* Audio select */
    283	0x58c, 0x010, /* Audio channel assign1 */
    284	0x58d, 0x032, /* Audio channel assign2 */
    285	0x58e, 0x054, /* Audio channel assign3 */
    286	0x58f, 0x023, /* Audio format */
    287	0x590, 0x000, /* SIF control */
    288
    289	0x595, 0x000, /* ?? */
    290	0x596, 0x000, /* ?? */
    291	0x597, 0x000, /* ?? */
    292
    293	0x464, 0x00, /* Digital input crossbar1 */
    294
    295	0x46c, 0xbbbb10, /* Digital output selection1-3 */
    296	0x470, 0x101010, /* Digital output selection4-6 */
    297
    298	0x478, 0x00, /* Sound feature control */
    299
    300	0x474, 0x18, /* Softmute control */
    301
    302	0x454, 0x0425b9, /* Sound Easy programming(reset) */
    303	0x454, 0x042539, /* Sound Easy programming(reset) */
    304
    305
    306	/**** common setting( of DVD play, including scaler commands) ****/
    307	0x042, 0x003, /* Data path configuration for VBI (TASK A) */
    308
    309	0x082, 0x003, /* Data path configuration for VBI (TASK B) */
    310
    311	0x108, 0x0f8, /* Sync control */
    312	0x2a9, 0x0fd, /* ??? */
    313	0x102, 0x089, /* select video input "mode 9" */
    314	0x111, 0x000, /* Mode/delay control */
    315
    316	0x10e, 0x00a, /* Chroma control 1 */
    317
    318	0x594, 0x002, /* SIF, analog I/O select */
    319
    320	0x454, 0x0425b9, /* Sound  */
    321	0x454, 0x042539,
    322
    323	0x111, 0x000,
    324	0x10e, 0x00a,
    325	0x464, 0x000,
    326	0x300, 0x000,
    327	0x301, 0x006,
    328	0x302, 0x000,
    329	0x303, 0x006,
    330	0x308, 0x040,
    331	0x309, 0x000,
    332	0x30a, 0x000,
    333	0x30b, 0x000,
    334	0x000, 0x002,
    335	0x001, 0x000,
    336	0x002, 0x000,
    337	0x003, 0x000,
    338	0x004, 0x033,
    339	0x040, 0x01d,
    340	0x041, 0x001,
    341	0x042, 0x004,
    342	0x043, 0x000,
    343	0x080, 0x01e,
    344	0x081, 0x001,
    345	0x082, 0x004,
    346	0x083, 0x000,
    347	0x190, 0x018,
    348	0x115, 0x000,
    349	0x116, 0x012,
    350	0x117, 0x018,
    351	0x04a, 0x011,
    352	0x08a, 0x011,
    353	0x04b, 0x000,
    354	0x08b, 0x000,
    355	0x048, 0x000,
    356	0x088, 0x000,
    357	0x04e, 0x012,
    358	0x08e, 0x012,
    359	0x058, 0x012,
    360	0x098, 0x012,
    361	0x059, 0x000,
    362	0x099, 0x000,
    363	0x05a, 0x003,
    364	0x09a, 0x003,
    365	0x05b, 0x001,
    366	0x09b, 0x001,
    367	0x054, 0x008,
    368	0x094, 0x008,
    369	0x055, 0x000,
    370	0x095, 0x000,
    371	0x056, 0x0c7,
    372	0x096, 0x0c7,
    373	0x057, 0x002,
    374	0x097, 0x002,
    375	0x0ff, 0x0ff,
    376	0x060, 0x001,
    377	0x0a0, 0x001,
    378	0x061, 0x000,
    379	0x0a1, 0x000,
    380	0x062, 0x000,
    381	0x0a2, 0x000,
    382	0x063, 0x000,
    383	0x0a3, 0x000,
    384	0x070, 0x000,
    385	0x0b0, 0x000,
    386	0x071, 0x004,
    387	0x0b1, 0x004,
    388	0x06c, 0x0e9,
    389	0x0ac, 0x0e9,
    390	0x06d, 0x003,
    391	0x0ad, 0x003,
    392	0x05c, 0x0d0,
    393	0x09c, 0x0d0,
    394	0x05d, 0x002,
    395	0x09d, 0x002,
    396	0x05e, 0x0f2,
    397	0x09e, 0x0f2,
    398	0x05f, 0x000,
    399	0x09f, 0x000,
    400	0x074, 0x000,
    401	0x0b4, 0x000,
    402	0x075, 0x000,
    403	0x0b5, 0x000,
    404	0x076, 0x000,
    405	0x0b6, 0x000,
    406	0x077, 0x000,
    407	0x0b7, 0x000,
    408	0x195, 0x008,
    409	0x0ff, 0x0ff,
    410	0x108, 0x0f8,
    411	0x111, 0x000,
    412	0x10e, 0x00a,
    413	0x2a9, 0x0fd,
    414	0x464, 0x001,
    415	0x454, 0x042135,
    416	0x598, 0x0e7,
    417	0x599, 0x07d,
    418	0x59a, 0x018,
    419	0x59c, 0x066,
    420	0x59d, 0x090,
    421	0x59e, 0x001,
    422	0x584, 0x000,
    423	0x585, 0x000,
    424	0x586, 0x003,
    425	0x588, 0x0ff,
    426	0x589, 0x00f,
    427	0x58a, 0x000,
    428	0x58b, 0x000,
    429	0x58c, 0x010,
    430	0x58d, 0x032,
    431	0x58e, 0x054,
    432	0x58f, 0x023,
    433	0x590, 0x000,
    434	0x595, 0x000,
    435	0x596, 0x000,
    436	0x597, 0x000,
    437	0x464, 0x000,
    438	0x46c, 0xbbbb10,
    439	0x470, 0x101010,
    440
    441
    442	0x478, 0x000,
    443	0x474, 0x018,
    444	0x454, 0x042135,
    445	0x598, 0x0e7,
    446	0x599, 0x07d,
    447	0x59a, 0x018,
    448	0x59c, 0x066,
    449	0x59d, 0x090,
    450	0x59e, 0x001,
    451	0x584, 0x000,
    452	0x585, 0x000,
    453	0x586, 0x003,
    454	0x588, 0x0ff,
    455	0x589, 0x00f,
    456	0x58a, 0x000,
    457	0x58b, 0x000,
    458	0x58c, 0x010,
    459	0x58d, 0x032,
    460	0x58e, 0x054,
    461	0x58f, 0x023,
    462	0x590, 0x000,
    463	0x595, 0x000,
    464	0x596, 0x000,
    465	0x597, 0x000,
    466	0x464, 0x000,
    467	0x46c, 0xbbbb10,
    468	0x470, 0x101010,
    469
    470	0x478, 0x000,
    471	0x474, 0x018,
    472	0x454, 0x042135,
    473	0x598, 0x0e7,
    474	0x599, 0x07d,
    475	0x59a, 0x018,
    476	0x59c, 0x066,
    477	0x59d, 0x090,
    478	0x59e, 0x001,
    479	0x584, 0x000,
    480	0x585, 0x000,
    481	0x586, 0x003,
    482	0x588, 0x0ff,
    483	0x589, 0x00f,
    484	0x58a, 0x000,
    485	0x58b, 0x000,
    486	0x58c, 0x010,
    487	0x58d, 0x032,
    488	0x58e, 0x054,
    489	0x58f, 0x023,
    490	0x590, 0x000,
    491	0x595, 0x000,
    492	0x596, 0x000,
    493	0x597, 0x000,
    494	0x464, 0x000,
    495	0x46c, 0xbbbb10,
    496	0x470, 0x101010,
    497	0x478, 0x000,
    498	0x474, 0x018,
    499	0x454, 0x042135,
    500	0x193, 0x000,
    501	0x300, 0x000,
    502	0x301, 0x006,
    503	0x302, 0x000,
    504	0x303, 0x006,
    505	0x308, 0x040,
    506	0x309, 0x000,
    507	0x30a, 0x000,
    508	0x30b, 0x000,
    509	0x000, 0x002,
    510	0x001, 0x000,
    511	0x002, 0x000,
    512	0x003, 0x000,
    513	0x004, 0x033,
    514	0x040, 0x01d,
    515	0x041, 0x001,
    516	0x042, 0x004,
    517	0x043, 0x000,
    518	0x080, 0x01e,
    519	0x081, 0x001,
    520	0x082, 0x004,
    521	0x083, 0x000,
    522	0x190, 0x018,
    523	0x115, 0x000,
    524	0x116, 0x012,
    525	0x117, 0x018,
    526	0x04a, 0x011,
    527	0x08a, 0x011,
    528	0x04b, 0x000,
    529	0x08b, 0x000,
    530	0x048, 0x000,
    531	0x088, 0x000,
    532	0x04e, 0x012,
    533	0x08e, 0x012,
    534	0x058, 0x012,
    535	0x098, 0x012,
    536	0x059, 0x000,
    537	0x099, 0x000,
    538	0x05a, 0x003,
    539	0x09a, 0x003,
    540	0x05b, 0x001,
    541	0x09b, 0x001,
    542	0x054, 0x008,
    543	0x094, 0x008,
    544	0x055, 0x000,
    545	0x095, 0x000,
    546	0x056, 0x0c7,
    547	0x096, 0x0c7,
    548	0x057, 0x002,
    549	0x097, 0x002,
    550	0x060, 0x001,
    551	0x0a0, 0x001,
    552	0x061, 0x000,
    553	0x0a1, 0x000,
    554	0x062, 0x000,
    555	0x0a2, 0x000,
    556	0x063, 0x000,
    557	0x0a3, 0x000,
    558	0x070, 0x000,
    559	0x0b0, 0x000,
    560	0x071, 0x004,
    561	0x0b1, 0x004,
    562	0x06c, 0x0e9,
    563	0x0ac, 0x0e9,
    564	0x06d, 0x003,
    565	0x0ad, 0x003,
    566	0x05c, 0x0d0,
    567	0x09c, 0x0d0,
    568	0x05d, 0x002,
    569	0x09d, 0x002,
    570	0x05e, 0x0f2,
    571	0x09e, 0x0f2,
    572	0x05f, 0x000,
    573	0x09f, 0x000,
    574	0x074, 0x000,
    575	0x0b4, 0x000,
    576	0x075, 0x000,
    577	0x0b5, 0x000,
    578	0x076, 0x000,
    579	0x0b6, 0x000,
    580	0x077, 0x000,
    581	0x0b7, 0x000,
    582	0x195, 0x008,
    583	0x598, 0x0e7,
    584	0x599, 0x07d,
    585	0x59a, 0x018,
    586	0x59c, 0x066,
    587	0x59d, 0x090,
    588	0x59e, 0x001,
    589	0x584, 0x000,
    590	0x585, 0x000,
    591	0x586, 0x003,
    592	0x588, 0x0ff,
    593	0x589, 0x00f,
    594	0x58a, 0x000,
    595	0x58b, 0x000,
    596	0x58c, 0x010,
    597	0x58d, 0x032,
    598	0x58e, 0x054,
    599	0x58f, 0x023,
    600	0x590, 0x000,
    601	0x595, 0x000,
    602	0x596, 0x000,
    603	0x597, 0x000,
    604	0x464, 0x000,
    605	0x46c, 0xbbbb10,
    606	0x470, 0x101010,
    607	0x478, 0x000,
    608	0x474, 0x018,
    609	0x454, 0x042135,
    610	0x193, 0x0a6,
    611	0x108, 0x0f8,
    612	0x042, 0x003,
    613	0x082, 0x003,
    614	0x454, 0x0425b9,
    615	0x454, 0x042539,
    616	0x193, 0x000,
    617	0x193, 0x0a6,
    618	0x464, 0x000,
    619
    620	0, 0
    621};
    622
    623/* Tuner */
    624static u32 reg_init_tuner_input[] = {
    625	0x108, 0x0f8, /* Sync control */
    626	0x111, 0x000, /* Mode/delay control */
    627	0x10e, 0x00a, /* Chroma control 1 */
    628	0, 0
    629};
    630
    631/* Composite */
    632static u32 reg_init_composite_input[] = {
    633	0x108, 0x0e8, /* Sync control */
    634	0x111, 0x000, /* Mode/delay control */
    635	0x10e, 0x04a, /* Chroma control 1 */
    636	0, 0
    637};
    638
    639/* S-Video */
    640static u32 reg_init_svideo_input[] = {
    641	0x108, 0x0e8, /* Sync control */
    642	0x111, 0x000, /* Mode/delay control */
    643	0x10e, 0x04a, /* Chroma control 1 */
    644	0, 0
    645};
    646
    647static u32 reg_set_audio_template[4][2] =
    648{
    649	{ /* for MONO
    650		tadachi 6/29 DMA audio output select?
    651		Register 0x46c
    652		7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
    653		0: MAIN left,  1: MAIN right
    654		2: AUX1 left,  3: AUX1 right
    655		4: AUX2 left,  5: AUX2 right
    656		6: DPL left,   7: DPL  right
    657		8: DPL center, 9: DPL surround
    658		A: monitor output, B: digital sense */
    659		0xbbbb00,
    660
    661		/* tadachi 6/29 DAC and I2S output select?
    662		   Register 0x470
    663		   7-4:DAC right ch. 3-0:DAC left ch.
    664		   I2S1 right,left  I2S2 right,left */
    665		0x00,
    666	},
    667	{ /* for STEREO */
    668		0xbbbb10, 0x101010,
    669	},
    670	{ /* for LANG1 */
    671		0xbbbb00, 0x00,
    672	},
    673	{ /* for LANG2/SAP */
    674		0xbbbb11, 0x111111,
    675	}
    676};
    677
    678
    679/* Get detected audio flags (from saa7134 driver) */
    680static void get_inf_dev_status(struct v4l2_subdev *sd,
    681		int *dual_flag, int *stereo_flag)
    682{
    683	u32 reg_data3;
    684
    685	static char *stdres[0x20] = {
    686		[0x00] = "no standard detected",
    687		[0x01] = "B/G (in progress)",
    688		[0x02] = "D/K (in progress)",
    689		[0x03] = "M (in progress)",
    690
    691		[0x04] = "B/G A2",
    692		[0x05] = "B/G NICAM",
    693		[0x06] = "D/K A2 (1)",
    694		[0x07] = "D/K A2 (2)",
    695		[0x08] = "D/K A2 (3)",
    696		[0x09] = "D/K NICAM",
    697		[0x0a] = "L NICAM",
    698		[0x0b] = "I NICAM",
    699
    700		[0x0c] = "M Korea",
    701		[0x0d] = "M BTSC ",
    702		[0x0e] = "M EIAJ",
    703
    704		[0x0f] = "FM radio / IF 10.7 / 50 deemp",
    705		[0x10] = "FM radio / IF 10.7 / 75 deemp",
    706		[0x11] = "FM radio / IF sel / 50 deemp",
    707		[0x12] = "FM radio / IF sel / 75 deemp",
    708
    709		[0x13 ... 0x1e] = "unknown",
    710		[0x1f] = "??? [in progress]",
    711	};
    712
    713
    714	*dual_flag = *stereo_flag = 0;
    715
    716	/* (demdec status: 0x528) */
    717
    718	/* read current status */
    719	reg_data3 = saa717x_read(sd, 0x0528);
    720
    721	v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
    722		reg_data3, stdres[reg_data3 & 0x1f],
    723		(reg_data3 & 0x000020) ? ",stereo" : "",
    724		(reg_data3 & 0x000040) ? ",dual"   : "");
    725	v4l2_dbg(1, debug, sd, "detailed status: "
    726		"%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
    727		(reg_data3 & 0x000080) ? " A2/EIAJ pilot tone "     : "",
    728		(reg_data3 & 0x000100) ? " A2/EIAJ dual "           : "",
    729		(reg_data3 & 0x000200) ? " A2/EIAJ stereo "         : "",
    730		(reg_data3 & 0x000400) ? " A2/EIAJ noise mute "     : "",
    731
    732		(reg_data3 & 0x000800) ? " BTSC/FM radio pilot "    : "",
    733		(reg_data3 & 0x001000) ? " SAP carrier "            : "",
    734		(reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
    735		(reg_data3 & 0x004000) ? " SAP noise mute "         : "",
    736		(reg_data3 & 0x008000) ? " VDSP "                   : "",
    737
    738		(reg_data3 & 0x010000) ? " NICST "                  : "",
    739		(reg_data3 & 0x020000) ? " NICDU "                  : "",
    740		(reg_data3 & 0x040000) ? " NICAM muted "            : "",
    741		(reg_data3 & 0x080000) ? " NICAM reserve sound "    : "",
    742
    743		(reg_data3 & 0x100000) ? " init done "              : "");
    744
    745	if (reg_data3 & 0x000220) {
    746		v4l2_dbg(1, debug, sd, "ST!!!\n");
    747		*stereo_flag = 1;
    748	}
    749
    750	if (reg_data3 & 0x000140) {
    751		v4l2_dbg(1, debug, sd, "DUAL!!!\n");
    752		*dual_flag = 1;
    753	}
    754}
    755
    756/* regs write to set audio mode */
    757static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
    758{
    759	v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
    760			audio_mode);
    761
    762	saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
    763	saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
    764}
    765
    766/* write regs to set audio volume, bass and treble */
    767static int set_audio_regs(struct v4l2_subdev *sd,
    768		struct saa717x_state *decoder)
    769{
    770	u8 mute = 0xac; /* -84 dB */
    771	u32 val;
    772	unsigned int work_l, work_r;
    773
    774	/* set SIF analog I/O select */
    775	saa717x_write(sd, 0x0594, decoder->audio_input);
    776	v4l2_dbg(1, debug, sd, "set audio input %d\n",
    777			decoder->audio_input);
    778
    779	/* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
    780	work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
    781	work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
    782	decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
    783	decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
    784
    785	/* set main volume */
    786	/* main volume L[7-0],R[7-0],0x00  24=24dB,-83dB, -84(mute) */
    787	/*    def:0dB->6dB(MPG600GR) */
    788	/* if mute is on, set mute */
    789	if (decoder->audio_main_mute) {
    790		val = mute | (mute << 8);
    791	} else {
    792		val = (u8)decoder->audio_main_vol_l |
    793			((u8)decoder->audio_main_vol_r << 8);
    794	}
    795
    796	saa717x_write(sd, 0x480, val);
    797
    798	/* set bass and treble */
    799	val = decoder->audio_main_bass & 0x1f;
    800	val |= (decoder->audio_main_treble & 0x1f) << 5;
    801	saa717x_write(sd, 0x488, val);
    802	return 0;
    803}
    804
    805/********** scaling staff ***********/
    806static void set_h_prescale(struct v4l2_subdev *sd,
    807		int task, int prescale)
    808{
    809	static const struct {
    810		int xpsc;
    811		int xacl;
    812		int xc2_1;
    813		int xdcg;
    814		int vpfy;
    815	} vals[] = {
    816		/* XPSC XACL XC2_1 XDCG VPFY */
    817		{    1,   0,    0,    0,   0 },
    818		{    2,   2,    1,    2,   2 },
    819		{    3,   4,    1,    3,   2 },
    820		{    4,   8,    1,    4,   2 },
    821		{    5,   8,    1,    4,   2 },
    822		{    6,   8,    1,    4,   3 },
    823		{    7,   8,    1,    4,   3 },
    824		{    8,  15,    0,    4,   3 },
    825		{    9,  15,    0,    4,   3 },
    826		{   10,  16,    1,    5,   3 },
    827	};
    828	static const int count = ARRAY_SIZE(vals);
    829	int i, task_shift;
    830
    831	task_shift = task * 0x40;
    832	for (i = 0; i < count; i++)
    833		if (vals[i].xpsc == prescale)
    834			break;
    835	if (i == count)
    836		return;
    837
    838	/* horizontal prescaling */
    839	saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
    840	/* accumulation length */
    841	saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
    842	/* level control */
    843	saa717x_write(sd, 0x62 + task_shift,
    844			(vals[i].xc2_1 << 3) | vals[i].xdcg);
    845	/*FIR prefilter control */
    846	saa717x_write(sd, 0x63 + task_shift,
    847			(vals[i].vpfy << 2) | vals[i].vpfy);
    848}
    849
    850/********** scaling staff ***********/
    851static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
    852{
    853	int task_shift;
    854
    855	task_shift = task * 0x40;
    856	/* Vertical scaling ratio (LOW) */
    857	saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
    858	/* Vertical scaling ratio (HI) */
    859	saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
    860}
    861
    862static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl)
    863{
    864	struct v4l2_subdev *sd = to_sd(ctrl);
    865	struct saa717x_state *state = to_state(sd);
    866
    867	switch (ctrl->id) {
    868	case V4L2_CID_BRIGHTNESS:
    869		saa717x_write(sd, 0x10a, ctrl->val);
    870		return 0;
    871
    872	case V4L2_CID_CONTRAST:
    873		saa717x_write(sd, 0x10b, ctrl->val);
    874		return 0;
    875
    876	case V4L2_CID_SATURATION:
    877		saa717x_write(sd, 0x10c, ctrl->val);
    878		return 0;
    879
    880	case V4L2_CID_HUE:
    881		saa717x_write(sd, 0x10d, ctrl->val);
    882		return 0;
    883
    884	case V4L2_CID_AUDIO_MUTE:
    885		state->audio_main_mute = ctrl->val;
    886		break;
    887
    888	case V4L2_CID_AUDIO_VOLUME:
    889		state->audio_main_volume = ctrl->val;
    890		break;
    891
    892	case V4L2_CID_AUDIO_BALANCE:
    893		state->audio_main_balance = ctrl->val;
    894		break;
    895
    896	case V4L2_CID_AUDIO_TREBLE:
    897		state->audio_main_treble = ctrl->val;
    898		break;
    899
    900	case V4L2_CID_AUDIO_BASS:
    901		state->audio_main_bass = ctrl->val;
    902		break;
    903
    904	default:
    905		return 0;
    906	}
    907	set_audio_regs(sd, state);
    908	return 0;
    909}
    910
    911static int saa717x_s_video_routing(struct v4l2_subdev *sd,
    912				   u32 input, u32 output, u32 config)
    913{
    914	struct saa717x_state *decoder = to_state(sd);
    915	int is_tuner = input & 0x80;  /* tuner input flag */
    916
    917	input &= 0x7f;
    918
    919	v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", input);
    920	/* inputs from 0-9 are available*/
    921	/* saa717x have mode0-mode9 but mode5 is reserved. */
    922	if (input > 9 || input == 5)
    923		return -EINVAL;
    924
    925	if (decoder->input != input) {
    926		int input_line = input;
    927
    928		decoder->input = input_line;
    929		v4l2_dbg(1, debug, sd,  "now setting %s input %d\n",
    930				input_line >= 6 ? "S-Video" : "Composite",
    931				input_line);
    932
    933		/* select mode */
    934		saa717x_write(sd, 0x102,
    935				(saa717x_read(sd, 0x102) & 0xf0) |
    936				input_line);
    937
    938		/* bypass chrominance trap for modes 6..9 */
    939		saa717x_write(sd, 0x109,
    940				(saa717x_read(sd, 0x109) & 0x7f) |
    941				(input_line < 6 ? 0x0 : 0x80));
    942
    943		/* change audio_mode */
    944		if (is_tuner) {
    945			/* tuner */
    946			set_audio_mode(sd, decoder->tuner_audio_mode);
    947		} else {
    948			/* Force to STEREO mode if Composite or
    949			 * S-Video were chosen */
    950			set_audio_mode(sd, TUNER_AUDIO_STEREO);
    951		}
    952		/* change initialize procedure (Composite/S-Video) */
    953		if (is_tuner)
    954			saa717x_write_regs(sd, reg_init_tuner_input);
    955		else if (input_line >= 6)
    956			saa717x_write_regs(sd, reg_init_svideo_input);
    957		else
    958			saa717x_write_regs(sd, reg_init_composite_input);
    959	}
    960
    961	return 0;
    962}
    963
    964#ifdef CONFIG_VIDEO_ADV_DEBUG
    965static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
    966{
    967	reg->val = saa717x_read(sd, reg->reg);
    968	reg->size = 1;
    969	return 0;
    970}
    971
    972static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
    973{
    974	u16 addr = reg->reg & 0xffff;
    975	u8 val = reg->val & 0xff;
    976
    977	saa717x_write(sd, addr, val);
    978	return 0;
    979}
    980#endif
    981
    982static int saa717x_set_fmt(struct v4l2_subdev *sd,
    983		struct v4l2_subdev_state *sd_state,
    984		struct v4l2_subdev_format *format)
    985{
    986	struct v4l2_mbus_framefmt *fmt = &format->format;
    987	int prescale, h_scale, v_scale;
    988
    989	v4l2_dbg(1, debug, sd, "decoder set size\n");
    990
    991	if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED)
    992		return -EINVAL;
    993
    994	/* FIXME need better bounds checking here */
    995	if (fmt->width < 1 || fmt->width > 1440)
    996		return -EINVAL;
    997	if (fmt->height < 1 || fmt->height > 960)
    998		return -EINVAL;
    999
   1000	fmt->field = V4L2_FIELD_INTERLACED;
   1001	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
   1002
   1003	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
   1004		return 0;
   1005
   1006	/* scaling setting */
   1007	/* NTSC and interlace only */
   1008	prescale = SAA717X_NTSC_WIDTH / fmt->width;
   1009	if (prescale == 0)
   1010		prescale = 1;
   1011	h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width;
   1012	/* interlace */
   1013	v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height;
   1014
   1015	/* Horizontal prescaling etc */
   1016	set_h_prescale(sd, 0, prescale);
   1017	set_h_prescale(sd, 1, prescale);
   1018
   1019	/* Horizontal scaling increment */
   1020	/* TASK A */
   1021	saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
   1022	saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
   1023	/* TASK B */
   1024	saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
   1025	saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
   1026
   1027	/* Vertical prescaling etc */
   1028	set_v_scale(sd, 0, v_scale);
   1029	set_v_scale(sd, 1, v_scale);
   1030
   1031	/* set video output size */
   1032	/* video number of pixels at output */
   1033	/* TASK A */
   1034	saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF));
   1035	saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF));
   1036	/* TASK B */
   1037	saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF));
   1038	saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF));
   1039
   1040	/* video number of lines at output */
   1041	/* TASK A */
   1042	saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF));
   1043	saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF));
   1044	/* TASK B */
   1045	saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF));
   1046	saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF));
   1047	return 0;
   1048}
   1049
   1050static int saa717x_s_radio(struct v4l2_subdev *sd)
   1051{
   1052	struct saa717x_state *decoder = to_state(sd);
   1053
   1054	decoder->radio = 1;
   1055	return 0;
   1056}
   1057
   1058static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
   1059{
   1060	struct saa717x_state *decoder = to_state(sd);
   1061
   1062	v4l2_dbg(1, debug, sd, "decoder set norm ");
   1063	v4l2_dbg(1, debug, sd, "(not yet implemented)\n");
   1064
   1065	decoder->radio = 0;
   1066	decoder->std = std;
   1067	return 0;
   1068}
   1069
   1070static int saa717x_s_audio_routing(struct v4l2_subdev *sd,
   1071				   u32 input, u32 output, u32 config)
   1072{
   1073	struct saa717x_state *decoder = to_state(sd);
   1074
   1075	if (input < 3) { /* FIXME! --tadachi */
   1076		decoder->audio_input = input;
   1077		v4l2_dbg(1, debug, sd,
   1078				"set decoder audio input to %d\n",
   1079				decoder->audio_input);
   1080		set_audio_regs(sd, decoder);
   1081		return 0;
   1082	}
   1083	return -ERANGE;
   1084}
   1085
   1086static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
   1087{
   1088	struct saa717x_state *decoder = to_state(sd);
   1089
   1090	v4l2_dbg(1, debug, sd, "decoder %s output\n",
   1091			enable ? "enable" : "disable");
   1092	decoder->enable = enable;
   1093	saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
   1094	return 0;
   1095}
   1096
   1097/* change audio mode */
   1098static int saa717x_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
   1099{
   1100	struct saa717x_state *decoder = to_state(sd);
   1101	int audio_mode;
   1102	char *mes[4] = {
   1103		"MONO", "STEREO", "LANG1", "LANG2/SAP"
   1104	};
   1105
   1106	audio_mode = TUNER_AUDIO_STEREO;
   1107
   1108	switch (vt->audmode) {
   1109		case V4L2_TUNER_MODE_MONO:
   1110			audio_mode = TUNER_AUDIO_MONO;
   1111			break;
   1112		case V4L2_TUNER_MODE_STEREO:
   1113			audio_mode = TUNER_AUDIO_STEREO;
   1114			break;
   1115		case V4L2_TUNER_MODE_LANG2:
   1116			audio_mode = TUNER_AUDIO_LANG2;
   1117			break;
   1118		case V4L2_TUNER_MODE_LANG1:
   1119			audio_mode = TUNER_AUDIO_LANG1;
   1120			break;
   1121	}
   1122
   1123	v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
   1124			mes[audio_mode]);
   1125	decoder->tuner_audio_mode = audio_mode;
   1126	/* The registers are not changed here. */
   1127	/* See DECODER_ENABLE_OUTPUT section. */
   1128	set_audio_mode(sd, decoder->tuner_audio_mode);
   1129	return 0;
   1130}
   1131
   1132static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
   1133{
   1134	struct saa717x_state *decoder = to_state(sd);
   1135	int dual_f, stereo_f;
   1136
   1137	if (decoder->radio)
   1138		return 0;
   1139	get_inf_dev_status(sd, &dual_f, &stereo_f);
   1140
   1141	v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
   1142			stereo_f, dual_f);
   1143
   1144	/* mono */
   1145	if ((dual_f == 0) && (stereo_f == 0)) {
   1146		vt->rxsubchans = V4L2_TUNER_SUB_MONO;
   1147		v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
   1148	}
   1149
   1150	/* stereo */
   1151	if (stereo_f == 1) {
   1152		if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
   1153				vt->audmode == V4L2_TUNER_MODE_LANG1) {
   1154			vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
   1155			v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
   1156		} else {
   1157			vt->rxsubchans = V4L2_TUNER_SUB_MONO;
   1158			v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
   1159		}
   1160	}
   1161
   1162	/* dual */
   1163	if (dual_f == 1) {
   1164		if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
   1165			vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
   1166			v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
   1167		} else {
   1168			vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
   1169			v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
   1170		}
   1171	}
   1172	return 0;
   1173}
   1174
   1175static int saa717x_log_status(struct v4l2_subdev *sd)
   1176{
   1177	struct saa717x_state *state = to_state(sd);
   1178
   1179	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
   1180	return 0;
   1181}
   1182
   1183/* ----------------------------------------------------------------------- */
   1184
   1185static const struct v4l2_ctrl_ops saa717x_ctrl_ops = {
   1186	.s_ctrl = saa717x_s_ctrl,
   1187};
   1188
   1189static const struct v4l2_subdev_core_ops saa717x_core_ops = {
   1190#ifdef CONFIG_VIDEO_ADV_DEBUG
   1191	.g_register = saa717x_g_register,
   1192	.s_register = saa717x_s_register,
   1193#endif
   1194	.log_status = saa717x_log_status,
   1195};
   1196
   1197static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
   1198	.g_tuner = saa717x_g_tuner,
   1199	.s_tuner = saa717x_s_tuner,
   1200	.s_radio = saa717x_s_radio,
   1201};
   1202
   1203static const struct v4l2_subdev_video_ops saa717x_video_ops = {
   1204	.s_std = saa717x_s_std,
   1205	.s_routing = saa717x_s_video_routing,
   1206	.s_stream = saa717x_s_stream,
   1207};
   1208
   1209static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
   1210	.s_routing = saa717x_s_audio_routing,
   1211};
   1212
   1213static const struct v4l2_subdev_pad_ops saa717x_pad_ops = {
   1214	.set_fmt = saa717x_set_fmt,
   1215};
   1216
   1217static const struct v4l2_subdev_ops saa717x_ops = {
   1218	.core = &saa717x_core_ops,
   1219	.tuner = &saa717x_tuner_ops,
   1220	.audio = &saa717x_audio_ops,
   1221	.video = &saa717x_video_ops,
   1222	.pad = &saa717x_pad_ops,
   1223};
   1224
   1225/* ----------------------------------------------------------------------- */
   1226
   1227
   1228/* i2c implementation */
   1229
   1230/* ----------------------------------------------------------------------- */
   1231static int saa717x_probe(struct i2c_client *client,
   1232			 const struct i2c_device_id *did)
   1233{
   1234	struct saa717x_state *decoder;
   1235	struct v4l2_ctrl_handler *hdl;
   1236	struct v4l2_subdev *sd;
   1237	u8 id = 0;
   1238	char *p = "";
   1239
   1240	/* Check if the adapter supports the needed features */
   1241	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
   1242		return -EIO;
   1243
   1244	decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
   1245	if (decoder == NULL)
   1246		return -ENOMEM;
   1247
   1248	sd = &decoder->sd;
   1249	v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
   1250
   1251	if (saa717x_write(sd, 0x5a4, 0xfe) &&
   1252			saa717x_write(sd, 0x5a5, 0x0f) &&
   1253			saa717x_write(sd, 0x5a6, 0x00) &&
   1254			saa717x_write(sd, 0x5a7, 0x01))
   1255		id = saa717x_read(sd, 0x5a0);
   1256	if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
   1257		v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
   1258		return -ENODEV;
   1259	}
   1260	if (id == 0xc2)
   1261		p = "saa7173";
   1262	else if (id == 0x32)
   1263		p = "saa7174A";
   1264	else if (id == 0x6c)
   1265		p = "saa7174HL";
   1266	else
   1267		p = "saa7171";
   1268	v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
   1269			client->addr << 1, client->adapter->name);
   1270
   1271	hdl = &decoder->hdl;
   1272	v4l2_ctrl_handler_init(hdl, 9);
   1273	/* add in ascending ID order */
   1274	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1275			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
   1276	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1277			V4L2_CID_CONTRAST, 0, 255, 1, 68);
   1278	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1279			V4L2_CID_SATURATION, 0, 255, 1, 64);
   1280	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1281			V4L2_CID_HUE, -128, 127, 1, 0);
   1282	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1283			V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000);
   1284	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1285			V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
   1286	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1287			V4L2_CID_AUDIO_BASS, -16, 15, 1, 0);
   1288	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1289			V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0);
   1290	v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
   1291			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
   1292	sd->ctrl_handler = hdl;
   1293	if (hdl->error) {
   1294		int err = hdl->error;
   1295
   1296		v4l2_ctrl_handler_free(hdl);
   1297		return err;
   1298	}
   1299
   1300	decoder->std = V4L2_STD_NTSC;
   1301	decoder->input = -1;
   1302	decoder->enable = 1;
   1303
   1304	/* FIXME!! */
   1305	decoder->playback = 0;	/* initially capture mode used */
   1306	decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
   1307
   1308	decoder->audio_input = 2; /* FIXME!! */
   1309
   1310	decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
   1311	/* set volume, bass and treble */
   1312	decoder->audio_main_vol_l = 6;
   1313	decoder->audio_main_vol_r = 6;
   1314
   1315	v4l2_dbg(1, debug, sd, "writing init values\n");
   1316
   1317	/* FIXME!! */
   1318	saa717x_write_regs(sd, reg_init_initialize);
   1319
   1320	v4l2_ctrl_handler_setup(hdl);
   1321
   1322	set_current_state(TASK_INTERRUPTIBLE);
   1323	schedule_timeout(2*HZ);
   1324	return 0;
   1325}
   1326
   1327static int saa717x_remove(struct i2c_client *client)
   1328{
   1329	struct v4l2_subdev *sd = i2c_get_clientdata(client);
   1330
   1331	v4l2_device_unregister_subdev(sd);
   1332	v4l2_ctrl_handler_free(sd->ctrl_handler);
   1333	return 0;
   1334}
   1335
   1336/* ----------------------------------------------------------------------- */
   1337
   1338static const struct i2c_device_id saa717x_id[] = {
   1339	{ "saa717x", 0 },
   1340	{ }
   1341};
   1342MODULE_DEVICE_TABLE(i2c, saa717x_id);
   1343
   1344static struct i2c_driver saa717x_driver = {
   1345	.driver = {
   1346		.name	= "saa717x",
   1347	},
   1348	.probe		= saa717x_probe,
   1349	.remove		= saa717x_remove,
   1350	.id_table	= saa717x_id,
   1351};
   1352
   1353module_i2c_driver(saa717x_driver);