msp3400-kthreads.c revision 3bbe5a83996c0a669250d91421eef054f3a30595
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>
2949965a80a4c4f5cbe15fb3bb1f8f8b0ec4ef02bcHans Verkuil#include <media/msp3400.h>
307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/kthread.h>
317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil#include <linux/suspend.h>
3249965a80a4c4f5cbe15fb3bb1f8f8b0ec4ef02bcHans Verkuil#include "msp3400-driver.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;
405af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil} msp_stdlist[] = {
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)" },
48de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	{ 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), "6.5/5.74  D/K3 Dual FM-Stereo" },
497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85  B/G NICAM FM" },
507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  L NICAM AM" },
517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55  I NICAM FM" },
527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM" },
537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV2)" },
54de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	{ 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85  D/K NICAM FM (HDEV3)" },
557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Stereo" },
567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M BTSC-Mono + SAP" },
577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5  M EIA-J Japan Stereo" },
587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7  FM-Stereo Radio" },
597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5  SAT-Mono" },
607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20  SAT-Stereo" },
617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2  SAT ADR" },
627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{     -1, 0, 0, NULL }, /* EOF */
637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct msp3400c_init_data_dem {
667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int fir1[6];
677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int fir2[6];
687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int cdo1;
697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int cdo2;
707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int ad_cv;
717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int mode_reg;
727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int dsp_src;
737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int dsp_matrix;
747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil} msp3400c_init_data[] = {
757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{	/* AM (for carrier detect / msp3400) */
767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{75, 19, 36, 35, 39, 40},
777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{75, 19, 36, 35, 39, 40},
787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0500, 0x0020, 0x3000
807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* AM (for carrier detect / msp3410) */
817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-1, -1, -8, 2, 59, 126},
827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-1, -1, -8, 2, 59, 126},
837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0100, 0x0020, 0x3000
857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* FM Radio */
867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-8, -8, 4, 6, 78, 107},
877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-8, -8, 4, 6, 78, 107},
887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0480, 0x0020, 0x3000
907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* Terrestial FM-mono + FM-stereo */
917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{3, 18, 27, 48, 66, 72},
927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{3, 18, 27, 48, 66, 72},
937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0480, 0x0030, 0x3000
957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* Sat FM-mono */
967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{ 1, 9, 14, 24, 33, 37},
977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{ 3, 18, 27, 48, 66, 72},
987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00c6, 0x0480, 0x0000, 0x3000
1007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
1017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-2, -8, -10, 10, 50, 86},
1027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{3, 18, 27, 48, 66, 72},
1037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
1047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0040, 0x0120, 0x3000
1057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* NICAM/FM -- I (6.0/6.552) */
1067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{2, 4, -6, -4, 40, 94},
1077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{3, 18, 27, 48, 66, 72},
1087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
1097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		0x00d0, 0x0040, 0x0120, 0x3000
1107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},{	/* NICAM/AM -- L (6.5/5.85) */
1117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-2, -8, -10, 10, 50, 86},
1127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		{-4, -12, -9, 23, 79, 126},
1137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
1148a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		0x00c6, 0x0140, 0x0120, 0x7c00
1157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	},
1167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstruct msp3400c_carrier_detect {
1197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int   cdo;
1207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	char *name;
1217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = {
1247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* main carrier */
1257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(4.5),        "4.5   NTSC"                   },
1267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(5.5),        "5.5   PAL B/G"                },
1277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(6.0),        "6.0   PAL I"                  },
1287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(6.5),        "6.5   PAL D/K + SAT + SECAM"  }
1297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = {
1327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* PAL B/G */
1337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(5.7421875),  "5.742 PAL B/G FM-stereo"     },
1347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(5.85),       "5.85  PAL B/G NICAM"         }
1357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = {
1387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* PAL SAT / SECAM */
1397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(5.85),       "5.85  PAL D/K + SECAM NICAM" },
1407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(6.2578125),  "6.25  PAL D/K1 FM-stereo" },
1417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(6.7421875),  "6.74  PAL D/K2 FM-stereo" },
1427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
1437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(7.20),       "7.20  PAL SAT FM-stereo s"   },
1447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	{ MSP_CARRIER(7.38),       "7.38  PAL SAT FM-stereo b"   },
1457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil};
1467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* ------------------------------------------------------------------------ */
1487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1495af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuilconst char *msp_standard_std_name(int std)
1507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
1517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int i;
1527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1535af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil	for (i = 0; msp_stdlist[i].name != NULL; i++)
1545af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		if (msp_stdlist[i].retval == std)
1555af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			return msp_stdlist[i].name;
1567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return "unknown";
1577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
1587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
159044f324f6ea5d55391db62fca6a295b2651cb946Adrian Bunkstatic void msp_set_source(struct i2c_client *client, u16 src)
1608a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil{
1618a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
1628a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
1638a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	if (msp_dolby) {
1648a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
1658a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
1668a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	} else {
1678a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp_write_dsp(client, 0x0008, src);
1688a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp_write_dsp(client, 0x0009, src);
1698a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	}
1708a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp_write_dsp(client, 0x000a, src);
1718a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp_write_dsp(client, 0x000b, src);
1728a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp_write_dsp(client, 0x000c, src);
1730020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	if (state->has_scart2_out)
1748a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp_write_dsp(client, 0x0041, src);
1758a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil}
1768a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
1778a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuilvoid msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2)
1787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
1797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0093, cdo1 & 0xfff);
1807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x009b, cdo1 >> 12);
1817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
1827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x00ab, cdo2 >> 12);
1838a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */
1847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
1857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1868a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuilvoid msp3400c_set_mode(struct i2c_client *client, int mode)
1877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
1887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
1898a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
1902474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	int tuner = (state->routing.input >> 3) & 1;
1917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int i;
1927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1938a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode);
1948a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	state->mode = mode;
1957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->rxsubchans = V4L2_TUNER_SUB_MONO;
1967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1972474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp_write_dem(client, 0x00bb, data->ad_cv | (tuner ? 0x100 : 0));
1987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (i = 5; i >= 0; i--)               /* fir 1 */
2008a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp_write_dem(client, 0x0001, data->fir1[i]);
2017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
2037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0005, 0x0040);
2047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	msp_write_dem(client, 0x0005, 0x0000);
2057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (i = 5; i >= 0; i--)
2068a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp_write_dem(client, 0x0005, data->fir2[i]);
2077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2088a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp_write_dem(client, 0x0083, data->mode_reg);
2097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2108a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp3400c_set_carrier(client, data->cdo1, data->cdo2);
2117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2128a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp_set_source(client, data->dsp_src);
213de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	/* set prescales */
2147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
215de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	/* volume prescale for SCART (AM mono input) */
216de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dsp(client, 0x000d, 0x1900);
217de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dsp(client, 0x000e, data->dsp_matrix);
218de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	if (state->has_nicam) /* nicam prescale */
219de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dsp(client, 0x0010, 0x5a00);
2207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
2217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2228a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP,
2238a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil   nor do they support stereo BTSC. */
224044f324f6ea5d55391db62fca6a295b2651cb946Adrian Bunkstatic void msp3400c_set_audmode(struct i2c_client *client)
2257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
226301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil	static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" };
2277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
228301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil	char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
2298a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		strmode[state->audmode] : "unknown";
2308a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	int src = 0;	/* channel source: FM/AM, nicam or SCART */
2317061561e640c2947ab93c4e2a437327657c4482eHans Verkuil	int audmode = state->audmode;
2327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->opmode == OPMODE_AUTOSELECT) {
2347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* this method would break everything, let's make sure
2357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 * it's never called
2367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		 */
2378a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client,
2388a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			"set_audmode called with mode=%d instead of set_source (ignored)\n",
2398a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			state->audmode);
2407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return;
2417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
2427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
2430020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	/* Note: for the C and D revs no NTSC stereo + SAP is possible as
2440020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	   the hardware does not support SAP. So the rxsubchans combination
2450020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	   of STEREO | LANG2 does not occur. */
2460020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil
2470020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	/* switch to mono if only mono is available */
2480020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
2490020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		audmode = V4L2_TUNER_MODE_MONO;
2500020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	/* if bilingual */
2510020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
2520020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		/* and mono or stereo, then fallback to lang1 */
2530020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		if (audmode == V4L2_TUNER_MODE_MONO ||
2540020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		    audmode == V4L2_TUNER_MODE_STEREO)
2550020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil			audmode = V4L2_TUNER_MODE_LANG1;
2560020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	}
2570020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	/* if stereo, and audmode is not mono, then switch to stereo */
2580020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	else if (audmode != V4L2_TUNER_MODE_MONO)
2597061561e640c2947ab93c4e2a437327657c4482eHans Verkuil		audmode = V4L2_TUNER_MODE_STEREO;
2607061561e640c2947ab93c4e2a437327657c4482eHans Verkuil
2617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* switch demodulator */
2627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	switch (state->mode) {
2637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_TERRA:
2648a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr);
2657061561e640c2947ab93c4e2a437327657c4482eHans Verkuil		switch (audmode) {
2667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_STEREO:
2677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x000e, 0x3001);
2687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_MONO:
2707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG1:
2717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG2:
272301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil		case V4L2_TUNER_MODE_LANG1_LANG2:
2737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x000e, 0x3000);
2747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
2767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_SAT:
2788a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr);
2797061561e640c2947ab93c4e2a437327657c4482eHans Verkuil		switch (audmode) {
2807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_MONO:
2818a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
2827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_STEREO:
284301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil		case V4L2_TUNER_MODE_LANG1_LANG2:
2858a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
2867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG1:
2888a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
2897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG2:
2918a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
2927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
2947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM1:
2967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM2:
2977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_AM_NICAM:
2988a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
2997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->nicam_on)
3008a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			src = 0x0100;  /* NICAM */
3017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_BTSC:
3038a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
3047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_EXTERN:
3068a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
3078a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		src = 0x0200;  /* SCART */
3087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_RADIO:
3108a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr);
3117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	default:
3138a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
3147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return;
3157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* switch audio */
3180020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	v4l_dbg(1, msp_debug, client, "set audmode %d\n", audmode);
3197061561e640c2947ab93c4e2a437327657c4482eHans Verkuil	switch (audmode) {
3207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_STEREO:
321301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil	case V4L2_TUNER_MODE_LANG1_LANG2:
3228a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		src |= 0x0020;
3237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_MONO:
3257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->mode == MSP_MODE_AM_NICAM) {
326f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "switching to AM mono\n");
3277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* AM mono decoding is handled by tuner, not MSP chip */
3287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* SCART switching control register */
3297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_scart(client, SCART_MONO, 0);
3307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			src = 0x0200;
3317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
3327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
3338a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
3348a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			src = 0x0030;
3358a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		break;
3367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_LANG1:
3377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_LANG2:
3398a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		src |= 0x0010;
3407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3428a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
3437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3448a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp_set_source(client, src);
3457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
3467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic void msp3400c_print_mode(struct i2c_client *client)
3487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
3497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
3507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->main == state->second) {
352f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n",
3537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->main / 910000, (state->main / 910) % 1000);
3547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	} else {
355f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n",
3567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->main / 910000, (state->main / 910) % 1000);
3577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
359f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "NICAM/FM carrier  : %d.%03d MHz\n",
3607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second/910) % 1000);
3617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_AM_NICAM)
362f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "NICAM/AM carrier  : %d.%03d MHz\n",
3637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second / 910) % 1000);
3647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
365f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n",
3667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second / 910) % 1000);
3677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
3697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* ----------------------------------------------------------------------- */
3717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3728a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuilstatic int msp3400c_detect_stereo(struct i2c_client *client)
3737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
3747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
3757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int val;
3767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int rxsubchans = state->rxsubchans;
3778a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	int newnicam = state->nicam_on;
3787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int update = 0;
3797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	switch (state->mode) {
3817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_TERRA:
3827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val = msp_read_dsp(client, 0x18);
3837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val > 32767)
3847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val -= 65536;
385f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
3863bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		if (val > 8192) {
3878a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			rxsubchans = V4L2_TUNER_SUB_STEREO;
3887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else if (val < -4096) {
3897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
3907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
3917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_MONO;
3927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
3937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		newnicam = 0;
3947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM1:
3967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM2:
3977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_AM_NICAM:
3987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val = msp_read_dem(client, 0x23);
399f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "nicam sync=%d, mode=%d\n",
4007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val & 1, (val & 0x1e) >> 1);
4017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val & 1) {
4037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* nicam synced */
4047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			switch ((val & 0x1e) >> 1)  {
4057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 0:
4067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 8:
4077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				rxsubchans = V4L2_TUNER_SUB_STEREO;
4087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 1:
4107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 9:
4118a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				rxsubchans = V4L2_TUNER_SUB_MONO;
4127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 2:
4147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 10:
4158a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
4167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			default:
4187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				rxsubchans = V4L2_TUNER_SUB_MONO;
4197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
4217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			newnicam = 1;
4227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
4237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			newnicam = 0;
4247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_MONO;
4257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
4267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
4277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (rxsubchans != state->rxsubchans) {
4297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		update = 1;
4308a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
4318a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			state->rxsubchans, rxsubchans);
4327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->rxsubchans = rxsubchans;
4337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (newnicam != state->nicam_on) {
4357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		update = 1;
436f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n",
4378a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			state->nicam_on, newnicam);
4387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->nicam_on = newnicam;
4397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return update;
4417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
4427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/*
4447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * A kernel thread for msp3400 control -- we don't want to block the
4457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * in the ioctl while doing the sound carrier & stereo detect
4467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil */
4477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* stereo/multilang monitoring */
4487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic void watch_stereo(struct i2c_client *client)
4497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
4507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
4517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
452de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	if (msp_detect_stereo(client)) {
453de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_set_audmode(client);
4547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
456f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	if (msp_once)
4577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
4587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
4597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp3400c_thread(void *data)
4617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
4627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
4637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
4647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp3400c_carrier_detect *cd;
4658a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	int count, max1, max2, val1, val2, val, this;
4667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
468f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
4697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
470f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n");
4717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state, -1);
472f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
4737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
4758a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
4767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
4777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
4787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
4797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4807560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil		if (state->radio || MSP_MODE_EXTERN == state->mode) {
4817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* no carrier scan, just unmute */
482f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
4833bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			state->scan_in_progress = 0;
4847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_audio(client);
4857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
4867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
4877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4883bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* mute audio */
4893bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->scan_in_progress = 1;
4903bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		msp_set_audio(client);
4910020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil
492de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp3400c_set_mode(client, MSP_MODE_AM_DETECT);
4937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val1 = val2 = 0;
4947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		max1 = max2 = -1;
4957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
4968a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->nicam_on = 0;
4977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4983bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* wait for tuner to settle down after a channel change */
4998a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		if (msp_sleep(state, 200))
5007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			goto restart;
5017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* carrier detect pass #1 -- main carrier */
5037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		cd = msp3400c_carrier_detect_main;
5047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		count = ARRAY_SIZE(msp3400c_carrier_detect_main);
5057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
506f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
5077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetect doesn't work well with AM ... */
5087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			max1 = 3;
5097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
510f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "AM sound override\n");
5117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (this = 0; this < count; this++) {
5148a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
5157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state,100))
5167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
5177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dsp(client, 0x1b);
5187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val > 32767)
5197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val -= 65536;
5207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val1 < val)
5217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val1 = val, max1 = this;
522f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
5237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* carrier detect pass #2 -- second (stereo) carrier */
5267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (max1) {
5277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 1: /* 5.5 */
5287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = msp3400c_carrier_detect_55;
5297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = ARRAY_SIZE(msp3400c_carrier_detect_55);
5307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 3: /* 6.5 */
5327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = msp3400c_carrier_detect_65;
5337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = ARRAY_SIZE(msp3400c_carrier_detect_65);
5347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0: /* 4.5 */
5367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 2: /* 6.0 */
5377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		default:
5387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = NULL;
5397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
5407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
543f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
5447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetect doesn't work well with AM ... */
5457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = NULL;
5467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
5477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			max2 = 0;
5487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (this = 0; this < count; this++) {
5508a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
5517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state,100))
5527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
5537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dsp(client, 0x1b);
5547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val > 32767)
5557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val -= 65536;
5567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val2 < val)
5577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val2 = val, max2 = this;
558f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
5597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* program the msp3400 according to the results */
5628a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->main = msp3400c_carrier_detect_main[max1].cdo;
5637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (max1) {
5647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 1: /* 5.5 */
5657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (max2 == 0) {
5667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* B/G FM-stereo */
5677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_55[max2].cdo;
5688a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
5697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5707560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			} else if (max2 == 1 && state->has_nicam) {
5717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* B/G NICAM */
5727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_55[max2].cdo;
5738a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
5747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 1;
5757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			} else {
5777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto no_second;
5787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
5797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 2: /* 6.0 */
5817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* PAL I NICAM */
5827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->second = MSP_CARRIER(6.552);
5838a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_mode(client, MSP_MODE_FM_NICAM2);
5847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
5857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
5867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 3: /* 6.5 */
5887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (max2 == 1 || max2 == 2) {
5897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* D/K FM-stereo */
5907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
5918a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
5927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5935af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			} else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
5947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* L NICAM or AM-mono */
5957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
5968a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_AM_NICAM);
5977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5987560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			} else if (max2 == 0 && state->has_nicam) {
5997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* D/K NICAM */
6007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
6018a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
6027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 1;
6037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
6047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			} else {
6057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto no_second;
6067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
6077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0: /* 4.5 */
6097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		default:
6107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		no_second:
6117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->second = msp3400c_carrier_detect_main[max1].cdo;
6128a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
6137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6150020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		msp3400c_set_carrier(client, state->second, state->main);
6167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6173bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* unmute */
6183bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->scan_in_progress = 0;
6198a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp3400c_set_audmode(client);
6203bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		msp_set_audio(client);
6217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
622f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_debug)
6237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_print_mode(client);
6247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6258a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		/* monitor tv audio mode, the first time don't wait
6268a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		   so long to get a quick stereo/bilingual result */
6273bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		count = 3;
6287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		while (state->watch_stereo) {
6293bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			if (msp_sleep(state, count ? 1000 : 5000))
6307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
6310020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil			if (count) count--;
6323bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			watch_stereo(client);
6337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
635f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "thread: exit\n");
6367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
6377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
6387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp3410d_thread(void *data)
6417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
6427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
6437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
6440020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	int val, i, std, count;
6457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
646f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n");
6477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
649f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
6507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state,-1);
651f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
6527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
6548a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
6557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
6567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
6577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->mode == MSP_MODE_EXTERN) {
6607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* no carrier scan needed, just unmute */
661f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
6623bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			state->scan_in_progress = 0;
6637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_audio(client);
6647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
6657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6673bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* mute audio */
6683bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->scan_in_progress = 1;
6693bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		msp_set_audio(client);
6707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
671de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* start autodetect. Note: autodetect is not supported for
672de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		   NTSC-M and radio, hence we force the standard in those cases. */
6735af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		if (state->radio)
6745af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			std = 0x40;
675d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		else
6765af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
6777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
6788a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->nicam_on = 0;
6797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6803bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* wait for tuner to settle down after a channel change */
6813bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		if (msp_sleep(state, 200))
6823bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			goto restart;
6833bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil
684f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_debug)
6858a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
6865af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			       msp_standard_std_name(std), std);
6877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (std != 1) {
6897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* programmed some specific mode */
6907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = std;
6917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
6927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* triggered autodetect */
6935af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			msp_write_dem(client, 0x20, std);
6947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			for (;;) {
695d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil				if (msp_sleep(state, 100))
6967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					goto restart;
6977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* check results */
6997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val = msp_read_dem(client, 0x7e);
7007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				if (val < 0x07ff)
7017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					break;
7028a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				v4l_dbg(2, msp_debug, client, "detection still in progress\n");
7037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
7047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7055af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		for (i = 0; msp_stdlist[i].name != NULL; i++)
7065af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			if (msp_stdlist[i].retval == val)
7077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
708f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n",
7095af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			msp_standard_std_name(val), val);
7105af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		state->main   = msp_stdlist[i].main;
7115af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		state->second = msp_stdlist[i].second;
7125af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		state->std = val;
7133bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->rxsubchans = V4L2_TUNER_SUB_MONO;
7145af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil
715f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
7165af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil				(val != 0x0009)) {
7177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetection has failed, let backup */
718f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "autodetection failed,"
7195af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil				" switching to backup standard: %s (0x%04x)\n",
7205af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil				msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
721de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			state->std = val = 0x0009;
7227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dem(client, 0x20, val);
7237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* set stereo */
7267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (val) {
7277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0008: /* B/G NICAM */
7287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x000a: /* I NICAM */
729de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		case 0x000b: /* D/K NICAM */
730de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			if (val == 0x000a)
7317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->mode = MSP_MODE_FM_NICAM2;
732de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			else
733de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil				state->mode = MSP_MODE_FM_NICAM1;
7347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* just turn on stereo */
7357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
7367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0009:
7397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->mode = MSP_MODE_AM_NICAM;
7407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
7417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0020: /* BTSC */
7448a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			/* The pre-'G' models only have BTSC-mono */
7457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->mode = MSP_MODE_BTSC;
7467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0040: /* FM radio */
7487560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			state->mode = MSP_MODE_FM_RADIO;
7497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
7507560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			/* not needed in theory if we have radio, but
7517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			   short programming enables carrier mute */
7528a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
7538a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(10.7),
7547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					    MSP_CARRIER(10.7));
7557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
756de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		case 0x0002:
7577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0003:
7587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0004:
7597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0005:
7605af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			state->mode = MSP_MODE_FM_TERRA;
7617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
765de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* set various prescales */
766de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dsp(client, 0x0d, 0x1900); /* scart */
767de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dsp(client, 0x0e, 0x3000); /* FM */
768de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->has_nicam)
769de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
770de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
7715af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		if (state->has_i2s_conf)
7725af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			msp_write_dem(client, 0x40, state->i2s_mode);
7737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7743bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* unmute */
7758a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp3400c_set_audmode(client);
7763bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->scan_in_progress = 0;
7773bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		msp_set_audio(client);
7788a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
7798a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		/* monitor tv audio mode, the first time don't wait
7808a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		   so long to get a quick stereo/bilingual result */
7813bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		count = 3;
7827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		while (state->watch_stereo) {
7833bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			if (msp_sleep(state, count ? 1000 : 5000))
7848a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				goto restart;
7850020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil			if (count) count--;
7863bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			watch_stereo(client);
7877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
789f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "thread: exit\n");
7907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
7917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
7927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* ----------------------------------------------------------------------- */
7947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
795de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil/* msp34xxG + (autoselect no-thread)
796de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil * this one uses both automatic standard detection and automatic sound
797de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil * select which are available in the newer G versions
798de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil * struct msp: only norm, acb and source are really used in this mode
799de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil */
8007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8019a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuilstatic int msp34xxg_modus(struct i2c_client *client)
8029a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil{
8039a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8049a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil
8059a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->radio) {
8069a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected radio modus\n");
8079a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x0001;
8089a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8099a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil
8109a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std & V4L2_STD_PAL) {
8119a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected PAL modus\n");
8129a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x7001;
8139a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8149a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std == V4L2_STD_NTSC_M_JP) {
8159a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n");
8169a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x4001;
8179a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8189a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std == V4L2_STD_NTSC_M_KR) {
8199a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n");
8209a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x0001;
8219a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8229a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std & V4L2_STD_MN) {
8239a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n");
8249a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x2001;
8259a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8269a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std & V4L2_STD_SECAM) {
8279a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected SECAM modus\n");
8289a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x6001;
8299a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8309a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	return 0x0001;
8319a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil}
8329a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil
8332474ed444b475614ef795523076be7cc8437ae00Hans Verkuilstatic void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
8342474ed444b475614ef795523076be7cc8437ae00Hans Verkuil {
8352474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8362474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	int source, matrix;
8372474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8382474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	switch (state->audmode) {
8392474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	case V4L2_TUNER_MODE_MONO:
8402474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = 0; /* mono only */
8412474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		matrix = 0x30;
8422474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		break;
8432474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	case V4L2_TUNER_MODE_LANG2:
8442474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = 4; /* stereo or B */
8452474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		matrix = 0x10;
8462474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		break;
847301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil	case V4L2_TUNER_MODE_LANG1_LANG2:
8482474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = 1; /* stereo or A|B */
8492474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		matrix = 0x20;
8502474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		break;
8510020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	case V4L2_TUNER_MODE_STEREO:
8520020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	case V4L2_TUNER_MODE_LANG1:
8530020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	default:
8540020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		source = 3; /* stereo or A */
8550020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		matrix = 0x00;
8560020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		break;
8572474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	}
8582474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8592474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	if (in == MSP_DSP_OUT_TUNER)
8602474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = (source << 8) | 0x20;
8612474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	/* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14
8622474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	   instead of 11, 12, 13. So we add one for that msp version. */
8632474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	else if (in >= MSP_DSP_OUT_MAIN_AVC && state->has_dolby_pro_logic)
8642474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = ((in + 1) << 8) | matrix;
8652474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	else
8662474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = (in << 8) | matrix;
8672474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8682474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n",
8692474ed444b475614ef795523076be7cc8437ae00Hans Verkuil			in, source, reg);
8702474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp_write_dsp(client, reg, source);
8712474ed444b475614ef795523076be7cc8437ae00Hans Verkuil}
8722474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8732474ed444b475614ef795523076be7cc8437ae00Hans Verkuilstatic void msp34xxg_set_sources(struct i2c_client *client)
8742474ed444b475614ef795523076be7cc8437ae00Hans Verkuil{
8752474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8762474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	u32 in = state->routing.input;
8772474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8782474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf);
8792474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	/* quasi-peak detector is set to same input as the loudspeaker (MAIN) */
8802474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf);
8812474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf);
8822474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf);
8830020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	if (state->has_scart2_out)
8842474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf);
8852474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf);
8862474ed444b475614ef795523076be7cc8437ae00Hans Verkuil}
8872474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
888de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil/* (re-)initialize the msp34xxg */
889de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuilstatic void msp34xxg_reset(struct i2c_client *client)
8907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
8917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8922474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	int tuner = (state->routing.input >> 3) & 1;
893de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	int modus;
8947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
895de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	/* initialize std to 1 (autodetect) to signal that no standard is
896de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	   selected yet. */
897de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	state->std = 1;
898de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
899de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_reset(client);
9007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9015af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil	if (state->has_i2s_conf)
9025af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		msp_write_dem(client, 0x40, state->i2s_mode);
9037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* step-by-step initialisation, as described in the manual */
9059a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	modus = msp34xxg_modus(client);
9062474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	modus |= tuner ? 0x100 : 0;
907de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dem(client, 0x30, modus);
9087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* write the dsps that may have an influence on
9107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	   standard/audio autodetection right now */
9112474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_sources(client);
9127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
913de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dsp(client, 0x0d, 0x1900); /* scart */
914de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dsp(client, 0x0e, 0x3000); /* FM */
915de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	if (state->has_nicam)
916de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
9177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
918de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	/* set identification threshold. Personally, I
919de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * I set it to a higher value than the default
920de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * of 0x190 to ignore noisy stereo signals.
921de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * this needs tuning. (recommended range 0x00a0-0x03c0)
922de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * 0x7f0 = forced mono mode
923de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 *
924de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * a2 threshold for stereo/bilingual.
925de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * Note: this register is part of the Manual/Compatibility mode.
926de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * It is supported by all 'G'-family chips.
927de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 */
928de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dem(client, 0x22, msp_stereo_thresh);
9297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
9307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp34xxg_thread(void *data)
9327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
9337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
9347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
935de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	int val, i;
9367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
937f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
9387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
940f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n");
9417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state, -1);
942f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n");
9437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
945f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
9467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
9477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
9487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
9497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* setup the chip*/
9517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp34xxg_reset(client);
952de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		state->std = state->radio ? 0x40 : msp_standard;
953de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->std != 1)
9547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			goto unmute;
955de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* start autodetect */
956de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dem(client, 0x20, state->std);
9577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* watch autodetect */
959de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n");
9607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (i = 0; i < 10; i++) {
9617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state, 100))
9627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
9637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* check results */
9657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dem(client, 0x7e);
9667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val < 0x07ff) {
967de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil				state->std = val;
9687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
9697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
970f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(2, msp_debug, client, "detection still in progress\n");
9717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
972de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->std == 1) {
973f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n");
9747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
9757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
9767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	unmute:
978de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
979de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			msp_standard_std_name(state->std), state->std);
9807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* unmute: dispatch sound to scart output, set scart volume */
9827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_set_audio(client);
9837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* restore ACB */
9857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (msp_write_dsp(client, 0x13, state->acb))
9867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			return -1;
9877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
988de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* the periodic stereo/SAP check is only relevant for
989de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		   the 0x20 standard (BTSC) */
990de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->std != 0x20)
991de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			continue;
992de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
993de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		state->watch_stereo = 1;
994de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
995de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* monitor tv audio mode, the first time don't wait
996de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		   in order to get a quick stereo/SAP update */
997de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		watch_stereo(client);
998de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		while (state->watch_stereo) {
999de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			watch_stereo(client);
1000de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			if (msp_sleep(state, 5000))
1001de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil				goto restart;
1002de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		}
10037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
1004f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "thread: exit\n");
10057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
10067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
10077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1008de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuilstatic int msp34xxg_detect_stereo(struct i2c_client *client)
10097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
10107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
10117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int status = msp_read_dem(client, 0x0200);
10127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int is_bilingual = status & 0x100;
10137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int is_stereo = status & 0x40;
1014de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	int oldrx = state->rxsubchans;
10157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
10167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->rxsubchans = 0;
10177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (is_stereo)
10188a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->rxsubchans = V4L2_TUNER_SUB_STEREO;
10197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	else
10208a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->rxsubchans = V4L2_TUNER_SUB_MONO;
10217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (is_bilingual) {
1022de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->std == 0x20)
1023de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			state->rxsubchans |= V4L2_TUNER_SUB_SAP;
1024de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		else
1025de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
10267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
1027f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
10287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		status, is_stereo, is_bilingual, state->rxsubchans);
1029de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	return (oldrx != state->rxsubchans);
10307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
10317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1032044f324f6ea5d55391db62fca6a295b2651cb946Adrian Bunkstatic void msp34xxg_set_audmode(struct i2c_client *client)
10337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
10347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
10357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1036de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	if (state->std == 0x20) {
1037de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	       if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) &&
1038cc33668b1eed1eac43f00cec639066047323b01dMauro Carvalho Chehab		   (state->audmode == V4L2_TUNER_MODE_LANG1_LANG2 ||
1039de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		    state->audmode == V4L2_TUNER_MODE_LANG2)) {
1040de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			msp_write_dem(client, 0x20, 0x21);
1041de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	       } else {
1042de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			msp_write_dem(client, 0x20, 0x20);
1043de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	       }
1044de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	}
1045de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
10462474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_sources(client);
10477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
10487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
10498a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuilvoid msp_set_audmode(struct i2c_client *client)
10508a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil{
10518a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
10528a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
10538a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	switch (state->opmode) {
10548a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_MANUAL:
10558a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_AUTODETECT:
10568a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp3400c_set_audmode(client);
10578a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		break;
10588a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_AUTOSELECT:
10598a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp34xxg_set_audmode(client);
10608a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		break;
10618a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	}
10628a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil}
10638a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
1064de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuilint msp_detect_stereo(struct i2c_client *client)
10658a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil{
10668a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	struct msp_state *state  = i2c_get_clientdata(client);
10678a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
10688a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	switch (state->opmode) {
10698a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_MANUAL:
10708a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_AUTODETECT:
1071de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		return msp3400c_detect_stereo(client);
10728a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_AUTOSELECT:
1073de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		return msp34xxg_detect_stereo(client);
10748a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	}
1075de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	return 0;
10768a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil}
10778a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
1078