msp3400-kthreads.c revision d312a46e5340be6a89c662ac483230c0737148c9
17e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/*
27e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * Programming the mspx4xx sound processor family
37e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil *
47e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org>
57e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil *
67e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * This program is free software; you can redistribute it and/or
77e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * modify it under the terms of the GNU General Public License
87e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * as published by the Free Software Foundation; either version 2
97e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * of the License, or (at your option) any later version.
107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil *
117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * This program is distributed in the hope that it will be useful,
127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * but WITHOUT ANY WARRANTY; without even the implied warranty of
137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * GNU General Public License for more details.
157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil *
167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * You should have received a copy of the GNU General Public License
177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * along with this program; if not, write to the Free Software
187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil */
207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/kernel.h>
237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/module.h>
247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/slab.h>
257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/i2c.h>
267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/videodev.h>
277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/videodev2.h>
287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <media/v4l2-common.h>
297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <media/audiochip.h>
307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/kthread.h>
317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/suspend.h>
327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include "msp3400.h"
337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* this one uses the automatic sound standard detection of newer msp34xx
357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil   chip versions */
367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct {
377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int retval;
387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int main, second;
397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	char *name;
407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil} msp_modelist[] = {
417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0000, 0, 0, "could not detect sound standard" },
427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0001, 0, 0, "autodetect start" },
437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72  M Dual FM-Stereo" },
447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74  B/G Dual FM-Stereo" },
457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25  D/K1 Dual FM-Stereo" },
467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74  D/K2 Dual FM-Stereo" },
477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  D/K FM-Mono (HDEV3)" },
487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },
497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },
507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },
517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },
527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },
537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },
547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },
557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },
567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7  FM-Stereo Radio" },
577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  SAT-Mono" },
587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20  SAT-Stereo" },
597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2  SAT ADR" },
607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{     -1, 0, 0, NULL }, /* EOF */
617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct msp3400c_init_data_dem {
647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int fir1[6];
657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int fir2[6];
667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int cdo1;
677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int cdo2;
687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int ad_cv;
697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int mode_reg;
707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int dsp_src;
717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int dsp_matrix;
727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil} msp3400c_init_data[] = {
737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{	/* AM (for carrier detect / msp3400) */
747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{75, 19, 36, 35, 39, 40},
757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{75, 19, 36, 35, 39, 40},
767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0500, 0x0020, 0x3000
787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* AM (for carrier detect / msp3410) */
797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-1, -1, -8, 2, 59, 126},
807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-1, -1, -8, 2, 59, 126},
817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0100, 0x0020, 0x3000
837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* FM Radio */
847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-8, -8, 4, 6, 78, 107},
857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-8, -8, 4, 6, 78, 107},
867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0480, 0x0020, 0x3000
887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* Terrestial FM-mono + FM-stereo */
897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{3, 18, 27, 48, 66, 72},
907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{3, 18, 27, 48, 66, 72},
917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0480, 0x0030, 0x3000
937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* Sat FM-mono */
947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{ 1, 9, 14, 24, 33, 37},
957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{ 3, 18, 27, 48, 66, 72},
967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00c6, 0x0480, 0x0000, 0x3000
987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-2, -8, -10, 10, 50, 86},
1007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{3, 18, 27, 48, 66, 72},
1017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
1027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0040, 0x0120, 0x3000
1037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* NICAM/FM -- I (6.0/6.552) */
1047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{2, 4, -6, -4, 40, 94},
1057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{3, 18, 27, 48, 66, 72},
1067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
1077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0040, 0x0120, 0x3000
1087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* NICAM/AM -- L (6.5/5.85) */
1097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-2, -8, -10, 10, 50, 86},
1107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-4, -12, -9, 23, 79, 126},
1117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
1127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00c6, 0x0140, 0x0120, 0x7c03
1137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},
1147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstruct msp3400c_carrier_detect {
1177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int   cdo;
1187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	char *name;
1197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = {
1227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* main carrier */
1237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(4.5),        "4.5   NTSC"                   },
1247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(5.5),        "5.5   PAL B/G"                },
1257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(6.0),        "6.0   PAL I"                  },
1267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(6.5),        "6.5   PAL D/K + SAT + SECAM"  }
1277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = {
1307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* PAL B/G */
1317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(5.7421875),  "5.742 PAL B/G FM-stereo"     },
1327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(5.85),       "5.85  PAL B/G NICAM"         }
1337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = {
1367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* PAL SAT / SECAM */
1377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(5.85),       "5.85  PAL D/K + SECAM NICAM" },
1387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(6.2578125),  "6.25  PAL D/K1 FM-stereo" },
1397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(6.7421875),  "6.74  PAL D/K2 FM-stereo" },
1407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
1417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(7.20),       "7.20  PAL SAT FM-stereo s"   },
1427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(7.38),       "7.38  PAL SAT FM-stereo b"   },
1437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* ------------------------------------------------------------------------ */
1467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilconst char *msp_standard_mode_name(int mode)
1487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
1497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int i;
1507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (i = 0; msp_modelist[i].name != NULL; i++)
1527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (msp_modelist[i].retval == mode)
1537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			return msp_modelist[i].name;
1547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return "unknown";
1557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
1567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilvoid msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
1587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
1597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0093, cdo1 & 0xfff);
1607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x009b, cdo1 >> 12);
1617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
1627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x00ab, cdo2 >> 12);
1637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
1647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
1657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilvoid msp3400c_setmode(struct i2c_client *client, int type)
1677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
1687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
1697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int i;
1707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "setmode: %d\n", type);
1727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->mode       = type;
1737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->audmode    = V4L2_TUNER_MODE_MONO;
1747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->rxsubchans = V4L2_TUNER_SUB_MONO;
1757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv);
1777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (i = 5; i >= 0; i--)               /* fir 1 */
1797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]);
1807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
1827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0005, 0x0040);
1837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0005, 0x0000);
1847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (i = 5; i >= 0; i--)
1857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]);
1867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg);
1887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1,
1907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			    msp3400c_init_data[type].cdo2);
1917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
1937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (dolby) {
1957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
1967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
1977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
1987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	} else {
1997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src);
2007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src);
2017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
2027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
2037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
2047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);
2057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2067560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil	if (state->has_nicam) {
2077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* nicam prescale */
2087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */
2097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
2107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
2117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* turn on/off nicam + stereo */
2137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilvoid msp3400c_setstereo(struct i2c_client *client, int mode)
2147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
215d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil	static char *strmode[] = { "mono", "stereo", "lang2", "lang1" };
2167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
2177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int nicam = 0;		/* channel source: FM/AM or nicam */
2187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int src = 0;
2197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->opmode == OPMODE_AUTOSELECT) {
2217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* this method would break everything, let's make sure
2227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 * it's never called
2237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 */
2247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "setstereo called with mode=%d instead of set_source (ignored)\n",
2257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		     mode);
2267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return;
2277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
2287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* switch demodulator */
2307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	switch (state->mode) {
2317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_TERRA:
2327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "FM setstereo: %s\n", strmode[mode]);
233d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		msp3400c_setcarrier(client, state->second, state->main);
2347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (mode) {
2357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_STEREO:
2367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x000e, 0x3001);
2377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_MONO:
2397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG1:
2407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG2:
2417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x000e, 0x3000);
2427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
2447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_SAT:
2467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "SAT setstereo: %s\n", strmode[mode]);
2477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (mode) {
2487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_MONO:
2497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
2507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_STEREO:
2527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
2537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG1:
2557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
2567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG2:
2587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
2597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
2617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM1:
2637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM2:
2647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_AM_NICAM:
2657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "NICAM setstereo: %s\n",strmode[mode]);
2667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp3400c_setcarrier(client,state->second,state->main);
2677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->nicam_on)
2687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			nicam=0x0100;
2697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_BTSC:
2717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "BTSC setstereo: %s\n",strmode[mode]);
2727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		nicam=0x0300;
2737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_EXTERN:
2757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "extern setstereo: %s\n",strmode[mode]);
2767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		nicam = 0x0200;
2777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_RADIO:
2797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "FM-Radio setstereo: %s\n",strmode[mode]);
2807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	default:
2827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "mono setstereo\n");
2837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return;
2847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
2857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* switch audio */
287d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil	switch (mode) {
2887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_STEREO:
2897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		src = 0x0020 | nicam;
2907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_MONO:
2927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->mode == MSP_MODE_AM_NICAM) {
2937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "switching to AM mono\n");
2947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* AM mono decoding is handled by tuner, not MSP chip */
2957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* SCART switching control register */
2967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_scart(client, SCART_MONO, 0);
2977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			src = 0x0200;
2987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
3007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_LANG1:
3017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		src = 0x0000 | nicam;
3027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_LANG2:
3047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		src = 0x0010 | nicam;
3057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "setstereo final source/matrix = 0x%x\n", src);
3087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (dolby) {
3107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0008, 0x0520);
3117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0009, 0x0620);
3127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x000a, src);
3137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x000b, src);
3147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	} else {
3157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0008, src);
3167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0009, src);
3177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x000a, src);
3187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x000b, src);
319d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		msp_write_dsp(client, 0x000c, src);
320d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		if (state->has_scart23_in_scart2_out)
321d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil			msp_write_dsp(client, 0x0041, src);
3227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
3247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic void msp3400c_print_mode(struct i2c_client *client)
3267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
3277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
3287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->main == state->second) {
3307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "mono sound carrier: %d.%03d MHz\n",
3317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->main / 910000, (state->main / 910) % 1000);
3327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	} else {
3337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "main sound carrier: %d.%03d MHz\n",
3347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->main / 910000, (state->main / 910) % 1000);
3357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
3377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "NICAM/FM carrier  : %d.%03d MHz\n",
3387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second/910) % 1000);
3397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_AM_NICAM)
3407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "NICAM/AM carrier  : %d.%03d MHz\n",
3417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second / 910) % 1000);
3427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
3437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "FM-stereo carrier : %d.%03d MHz\n",
3447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second / 910) % 1000);
3457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
3477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* ----------------------------------------------------------------------- */
3497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint autodetect_stereo(struct i2c_client *client)
3517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
3527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
3537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int val;
3547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int rxsubchans = state->rxsubchans;
3557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int newnicam   = state->nicam_on;
3567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int update = 0;
3577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	switch (state->mode) {
3597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_TERRA:
3607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val = msp_read_dsp(client, 0x18);
3617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val > 32767)
3627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val -= 65536;
3637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "stereo detect register: %d\n", val);
3647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val > 4096) {
3657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
3667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else if (val < -4096) {
3677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
3687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
3697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_MONO;
3707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
3717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		newnicam = 0;
3727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM1:
3747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM2:
3757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_AM_NICAM:
3767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val = msp_read_dem(client, 0x23);
3777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "nicam sync=%d, mode=%d\n",
3787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val & 1, (val & 0x1e) >> 1);
3797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val & 1) {
3817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* nicam synced */
3827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			switch ((val & 0x1e) >> 1)  {
3837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 0:
3847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 8:
3857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				rxsubchans = V4L2_TUNER_SUB_STEREO;
3867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
3877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 1:
3887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 9:
3897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				rxsubchans = V4L2_TUNER_SUB_MONO
3907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					| V4L2_TUNER_SUB_LANG1;
3917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
3927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 2:
3937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 10:
3947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				rxsubchans = V4L2_TUNER_SUB_MONO
3957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					| V4L2_TUNER_SUB_LANG1
3967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					| V4L2_TUNER_SUB_LANG2;
3977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
3987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			default:
3997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				rxsubchans = V4L2_TUNER_SUB_MONO;
4007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
4027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			newnicam = 1;
4037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
4047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			newnicam = 0;
4057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_MONO;
4067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
4077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
4087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_BTSC:
4097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val = msp_read_dem(client, 0x200);
4107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
4117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val,
4127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			(val & 0x0002) ? "no"     : "yes",
4137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			(val & 0x0004) ? "no"     : "yes",
4147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			(val & 0x0040) ? "stereo" : "mono",
4157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			(val & 0x0080) ? ", nicam 2nd mono" : "",
4167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			(val & 0x0100) ? ", bilingual/SAP"  : "");
4177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		rxsubchans = V4L2_TUNER_SUB_MONO;
4187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
4197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
4207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
4217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (rxsubchans != state->rxsubchans) {
4237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		update = 1;
4247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "watch: rxsubchans %d => %d\n",
4257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans,rxsubchans);
4267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->rxsubchans = rxsubchans;
4277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (newnicam != state->nicam_on) {
4297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		update = 1;
4307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "watch: nicam %d => %d\n",
4317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on,newnicam);
4327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->nicam_on = newnicam;
4337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return update;
4357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
4367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/*
4387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * A kernel thread for msp3400 control -- we don't want to block the
4397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * in the ioctl while doing the sound carrier & stereo detect
4407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil */
4417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* stereo/multilang monitoring */
4427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic void watch_stereo(struct i2c_client *client)
4437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
4447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
4457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (autodetect_stereo(client)) {
447d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
4487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
449d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1)
4507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
4517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		else
4527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
4537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (once)
4567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
4577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
4587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp3400c_thread(void *data)
4607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
4617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
4627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
4637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp3400c_carrier_detect *cd;
4647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int count, max1,max2,val1,val2, val,this;
4657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "msp3400 daemon started\n");
4687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
4697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "msp3400 thread: sleep\n");
4707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state, -1);
4717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "msp3400 thread: wakeup\n");
4727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
4747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "thread: restart scan\n");
4757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
4767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
4777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
4787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4797560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil		if (state->radio || MSP_MODE_EXTERN == state->mode) {
4807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* no carrier scan, just unmute */
4817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "thread: no carrier scan\n");
4827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_audio(client);
4837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
4847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
4857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* mute */
4877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_set_mute(client);
4887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
4897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val1 = val2 = 0;
4907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		max1 = max2 = -1;
4917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
4927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* some time for the tuner to sync */
4947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (msp_sleep(state,200))
4957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			goto restart;
4967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* carrier detect pass #1 -- main carrier */
4987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		cd = msp3400c_carrier_detect_main;
4997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		count = ARRAY_SIZE(msp3400c_carrier_detect_main);
5007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5017560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil		if (amsound && (state->std & V4L2_STD_SECAM)) {
5027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetect doesn't work well with AM ... */
5037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			max1 = 3;
5047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
5057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "AM sound override\n");
5067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (this = 0; this < count; this++) {
5097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
5107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state,100))
5117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
5127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dsp(client, 0x1b);
5137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val > 32767)
5147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val -= 65536;
5157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val1 < val)
5167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val1 = val, max1 = this;
5177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
5187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* carrier detect pass #2 -- second (stereo) carrier */
5217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (max1) {
5227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 1: /* 5.5 */
5237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = msp3400c_carrier_detect_55;
5247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = ARRAY_SIZE(msp3400c_carrier_detect_55);
5257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 3: /* 6.5 */
5277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = msp3400c_carrier_detect_65;
5287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = ARRAY_SIZE(msp3400c_carrier_detect_65);
5297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0: /* 4.5 */
5317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 2: /* 6.0 */
5327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		default:
5337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = NULL;
5347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
5357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5387560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil		if (amsound && (state->std & V4L2_STD_SECAM)) {
5397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetect doesn't work well with AM ... */
5407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = NULL;
5417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
5427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			max2 = 0;
5437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (this = 0; this < count; this++) {
5457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
5467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state,100))
5477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
5487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dsp(client, 0x1b);
5497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val > 32767)
5507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val -= 65536;
5517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val2 < val)
5527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val2 = val, max2 = this;
5537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
5547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* program the msp3400 according to the results */
5577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->main   = msp3400c_carrier_detect_main[max1].cdo;
5587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (max1) {
5597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 1: /* 5.5 */
5607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (max2 == 0) {
5617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* B/G FM-stereo */
5627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_55[max2].cdo;
5637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
5647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 0;
5657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
5667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5677560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			} else if (max2 == 1 && state->has_nicam) {
5687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* B/G NICAM */
5697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_55[max2].cdo;
5707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
5717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 1;
5727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setcarrier(client, state->second, state->main);
5737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			} else {
5757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto no_second;
5767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
5777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 2: /* 6.0 */
5797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* PAL I NICAM */
5807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->second = MSP_CARRIER(6.552);
5817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
5827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
5837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, state->second, state->main);
5847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
5857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 3: /* 6.5 */
5877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (max2 == 1 || max2 == 2) {
5887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* D/K FM-stereo */
5897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
5907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setmode(client, MSP_MODE_FM_TERRA);
5917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 0;
5927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
5937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5947560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			} else if (max2 == 0 && (state->std & V4L2_STD_SECAM)) {
5957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* L NICAM or AM-mono */
5967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
5977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setmode(client, MSP_MODE_AM_NICAM);
5987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 0;
5997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
6007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setcarrier(client, state->second, state->main);
6017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* volume prescale for SCART (AM mono input) */
6027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp_write_dsp(client, 0x000d, 0x1900);
6037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
6047560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			} else if (max2 == 0 && state->has_nicam) {
6057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* D/K NICAM */
6067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
6077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
6087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 1;
6097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp3400c_setcarrier(client, state->second, state->main);
6107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
6117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			} else {
6127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto no_second;
6137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
6147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0: /* 4.5 */
6167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		default:
6177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		no_second:
6187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->second = msp3400c_carrier_detect_main[max1].cdo;
6197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setmode(client, MSP_MODE_FM_TERRA);
6207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 0;
6217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, state->second, state->main);
6227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_MONO;
6237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
6247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* unmute */
6287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_set_audio(client);
6297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (debug)
6317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_print_mode(client);
6327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* monitor tv audio mode */
6347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		while (state->watch_stereo) {
6357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state,5000))
6367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
6377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			watch_stereo(client);
6387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
6407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "thread: exit\n");
6417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
6427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
6437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp3410d_thread(void *data)
6467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
6477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
6487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
649d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil	int val, i, std;
6507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "msp3410 daemon started\n");
6527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
6547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "msp3410 thread: sleep\n");
6557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state,-1);
6567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "msp3410 thread: wakeup\n");
6577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
6597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "thread: restart scan\n");
6607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
6617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
6627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->mode == MSP_MODE_EXTERN) {
6657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* no carrier scan needed, just unmute */
6667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "thread: no carrier scan\n");
6677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_audio(client);
6687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
6697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* put into sane state (and mute) */
6727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_reset(client);
6737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* some time for the tuner to sync */
6757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (msp_sleep(state,200))
6767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			goto restart;
6777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* start autodetect */
679d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		std = 1;
680d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		if (state->std & V4L2_STD_NTSC)
681d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil			std = 0x20;
682d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		else
683d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil			msp_write_dem(client, 0x20, std);
6847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
6857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (debug)
6877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "setting mode: %s (0x%04x)\n",
6887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			       msp_standard_mode_name(std), std);
6897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (std != 1) {
6917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* programmed some specific mode */
6927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = std;
6937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
6947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* triggered autodetect */
6957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			for (;;) {
696d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil				if (msp_sleep(state, 100))
6977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					goto restart;
6987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* check results */
7007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val = msp_read_dem(client, 0x7e);
7017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				if (val < 0x07ff)
7027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					break;
7037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				v4l_dbg(1, client, "detection still in progress\n");
7047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
7057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (i = 0; msp_modelist[i].name != NULL; i++)
7077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_modelist[i].retval == val)
7087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
7097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "current mode: %s (0x%04x)\n",
7107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_standard_mode_name(val), val);
7117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->main   = msp_modelist[i].main;
7127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->second = msp_modelist[i].second;
7137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7147560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil		if (amsound && (state->std & V4L2_STD_SECAM) && (val != 0x0009)) {
7157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetection has failed, let backup */
7167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "autodetection failed,"
7177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				" switching to backup mode: %s (0x%04x)\n",
7187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				msp_modelist[8].name ? msp_modelist[8].name : "unknown",val);
7197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = 0x0009;
7207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dem(client, 0x20, val);
7217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* set various prescales */
7247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0d, 0x1900); /* scart */
7257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x0e, 0x2403); /* FM */
7267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
7277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* set stereo */
7297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (val) {
7307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0008: /* B/G NICAM */
7317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x000a: /* I NICAM */
7327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val == 0x0008)
7337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->mode = MSP_MODE_FM_NICAM1;
7347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			else
7357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->mode = MSP_MODE_FM_NICAM2;
7367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* just turn on stereo */
7377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
7387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
7397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
7417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0009:
7437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->mode = MSP_MODE_AM_NICAM;
7447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_MONO;
7457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
7467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
7477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0020: /* BTSC */
7507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* just turn on stereo */
7517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->mode = MSP_MODE_BTSC;
7527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
7537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 0;
7547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
7567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0040: /* FM radio */
7587560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			state->mode = MSP_MODE_FM_RADIO;
7597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
7607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->audmode = V4L2_TUNER_MODE_STEREO;
7617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 0;
7627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 0;
7637560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			/* not needed in theory if we have radio, but
7647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			   short programming enables carrier mute */
7657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setmode(client,MSP_MODE_FM_RADIO);
7667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
7677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					    MSP_CARRIER(10.7));
7687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* scart routing */
7697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_scart(client,SCART_IN2,0);
7707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* msp34xx does radio decoding */
7717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x08, 0x0020);
7727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x09, 0x0020);
7737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x0b, 0x0020);
7747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0003:
7767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0004:
7777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0005:
7787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->mode   = MSP_MODE_FM_TERRA;
7797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_MONO;
7807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->audmode = V4L2_TUNER_MODE_MONO;
7817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 0;
7827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* unmute, restore misc registers */
7877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_set_audio(client);
7887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dsp(client, 0x13, state->acb);
7897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dem(client, 0x40, state->i2s_mode);
7907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* monitor tv audio mode */
7927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		while (state->watch_stereo) {
7937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state,5000))
7947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
7957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			watch_stereo(client);
7967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
7987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "thread: exit\n");
7997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
8007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
8017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* ----------------------------------------------------------------------- */
8037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* msp34xxG + (autoselect no-thread)                                          */
8057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* this one uses both automatic standard detection and automatic sound     */
8067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* select which are available in the newer G versions                      */
8077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* struct msp: only norm, acb and source are really used in this mode      */
8087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
8107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * the value for source is the same as bit 15:8 of DSP registers 0x08,
8117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
8127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil *
8137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * this function replaces msp3400c_setstereo
8147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil */
8157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic void msp34xxg_set_source(struct i2c_client *client, int source)
8167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
8177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* fix matrix mode to stereo and let the msp choose what
8207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 * to output according to 'source', as recommended
8217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 * for MONO (source==0) downmixing set bit[7:0] to 0x30
8227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 */
8237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
8247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "set source to %d (0x%x)\n", source, value);
8267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* Loudspeaker Output */
8277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dsp(client, 0x08, value);
8287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* SCART1 DA Output */
8297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dsp(client, 0x0a, value);
8307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* Quasi-peak detector */
8317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dsp(client, 0x0c, value);
8327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/*
8337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 * set identification threshold. Personally, I
8347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 * I set it to a higher value that the default
8357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 * of 0x190 to ignore noisy stereo signals.
8367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 * this needs tuning. (recommended range 0x00a0-0x03c0)
8377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 * 0x7f0 = forced mono mode
8387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	 */
8397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* a2 threshold for stereo/bilingual */
8407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x22, stereo_threshold);
8417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->source = source;
8427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
8437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* (re-)initialize the msp34xxg, according to the current norm in state->norm
8457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * return 0 if it worked, -1 if it failed
8467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil */
8477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic int msp34xxg_reset(struct i2c_client *client)
8487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
8497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int modus, std;
8517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (msp_reset(client))
8537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return -1;
8547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* make sure that input/output is muted (paranoid mode) */
8567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* ACB, mute DSP input, mute SCART 1 */
8577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (msp_write_dsp(client, 0x13, 0x0f20))
8587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return -1;
8597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x40, state->i2s_mode);
8617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* step-by-step initialisation, as described in the manual */
8637560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil	modus = msp_modus(client);
8647560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil	if (state->radio)
8657560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil		std = 0x40;
8667560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil	else
8677560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil		std = (state->std & V4L2_STD_NTSC) ? 0x20 : 1;
8687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	modus &= ~0x03; /* STATUS_CHANGE = 0 */
8697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION = 1 */
8707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (msp_write_dem(client, 0x30, modus))
8717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return -1;
8727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (msp_write_dem(client, 0x20, std))
8737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return -1;
8747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* write the dsps that may have an influence on
8767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	   standard/audio autodetection right now */
8777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp34xxg_set_source(client, state->source);
8787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* AM/FM Prescale [15:8] 75khz deviation */
8807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (msp_write_dsp(client, 0x0e, 0x3000))
8817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return -1;
8827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* NICAM Prescale 9db gain (as recommended) */
8847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (msp_write_dsp(client, 0x10, 0x5a00))
8857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return -1;
8867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
8887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
8897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp34xxg_thread(void *data)
8917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
8927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
8937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int val, std, i;
8957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "msp34xxg daemon started\n");
8977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->source = 1; /* default */
8997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
9007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "msp34xxg thread: sleep\n");
9017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state, -1);
9027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(2, client, "msp34xxg thread: wakeup\n");
9037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
9057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "thread: restart scan\n");
9067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
9077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
9087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
9097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* setup the chip*/
9117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp34xxg_reset(client);
9127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		std = standard;
9137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (std != 0x01)
9147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			goto unmute;
9157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* watch autodetect */
9177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "triggered autodetect, waiting for result\n");
9187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (i = 0; i < 10; i++) {
9197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state, 100))
9207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
9217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* check results */
9237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dem(client, 0x7e);
9247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val < 0x07ff) {
9257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				std = val;
9267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
9277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
9287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(2, client, "detection still in progress\n");
9297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
9307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (std == 1) {
9317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			v4l_dbg(1, client, "detection still in progress after 10 tries. giving up.\n");
9327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
9337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
9347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	unmute:
9367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->mode = std;
9377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		v4l_dbg(1, client, "current mode: %s (0x%04x)\n",
9387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_standard_mode_name(std), std);
9397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* unmute: dispatch sound to scart output, set scart volume */
9417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_set_audio(client);
9427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* restore ACB */
9447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (msp_write_dsp(client, 0x13, state->acb))
9457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			return -1;
9467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_write_dem(client, 0x40, state->i2s_mode);
9487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
9497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "thread: exit\n");
9507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
9517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
9527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilvoid msp34xxg_detect_stereo(struct i2c_client *client)
9547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
9557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
9567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int status = msp_read_dem(client, 0x0200);
9587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int is_bilingual = status & 0x100;
9597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int is_stereo = status & 0x40;
9607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->rxsubchans = 0;
9627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (is_stereo)
9637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->rxsubchans |= V4L2_TUNER_SUB_STEREO;
9647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	else
9657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->rxsubchans |= V4L2_TUNER_SUB_MONO;
9667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (is_bilingual) {
9677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
9687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* I'm supposed to check whether it's SAP or not
9697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 * and set only LANG2/SAP in this case. Yet, the MSP
9707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 * does a lot of work to hide this and handle everything
9717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 * the same way. I don't want to work around it so unless
9727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 * this is a problem, I'll handle SAP just like lang1/lang2.
9737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 */
9747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
9757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	v4l_dbg(1, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
9767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		status, is_stereo, is_bilingual, state->rxsubchans);
9777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
9787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilvoid msp34xxg_set_audmode(struct i2c_client *client, int audmode)
9807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
9817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
9827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int source;
9837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	switch (audmode) {
9857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_MONO:
9867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		source = 0; /* mono only */
9877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
9887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_STEREO:
9897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
9907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* problem: that could also mean 2 (scart input) */
9917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
9927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_LANG1:
9937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		source = 3; /* stereo or A */
9947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
9957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_LANG2:
9967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		source = 4; /* stereo or B */
9977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
9987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	default:
9997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		audmode = 0;
10007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		source  = 1;
10017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
10027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
10037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->audmode = audmode;
10047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp34xxg_set_source(client, source);
10057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
10067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1007