msp3400-kthreads.c revision 2eb606db1134ce860cc0cbf8b533b6315d182e21
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
2472eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil	if (state->mode != MSP_MODE_EXTERN) {
2482eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		/* switch to mono if only mono is available */
2492eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
2502eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			audmode = V4L2_TUNER_MODE_MONO;
2512eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		/* if bilingual */
2522eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
2532eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			/* and mono or stereo, then fallback to lang1 */
2542eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			if (audmode == V4L2_TUNER_MODE_MONO ||
2552eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			    audmode == V4L2_TUNER_MODE_STEREO)
2562eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil				audmode = V4L2_TUNER_MODE_LANG1;
2572eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		}
2582eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		/* if stereo, and audmode is not mono, then switch to stereo */
2592eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		else if (audmode != V4L2_TUNER_MODE_MONO)
2602eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			audmode = V4L2_TUNER_MODE_STEREO;
2610020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	}
2627061561e640c2947ab93c4e2a437327657c4482eHans Verkuil
2637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* switch demodulator */
2647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	switch (state->mode) {
2657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_TERRA:
2668a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr);
2677061561e640c2947ab93c4e2a437327657c4482eHans Verkuil		switch (audmode) {
2687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_STEREO:
2697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x000e, 0x3001);
2707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_MONO:
2727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG1:
2737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG2:
274301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil		case V4L2_TUNER_MODE_LANG1_LANG2:
2757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dsp(client, 0x000e, 0x3000);
2767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
2787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_SAT:
2808a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr);
2817061561e640c2947ab93c4e2a437327657c4482eHans Verkuil		switch (audmode) {
2827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_MONO:
2838a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
2847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_STEREO:
286301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil		case V4L2_TUNER_MODE_LANG1_LANG2:
2878a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
2887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG1:
2908a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
2917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case V4L2_TUNER_MODE_LANG2:
2938a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
2947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
2957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
2967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
2977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM1:
2987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM2:
2997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_AM_NICAM:
3008a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
3017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->nicam_on)
3028a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			src = 0x0100;  /* NICAM */
3037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_BTSC:
3058a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
3067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_EXTERN:
3088a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
3098a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		src = 0x0200;  /* SCART */
3107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_RADIO:
3128a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr);
3137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	default:
3158a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
3167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		return;
3177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* switch audio */
3200020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	v4l_dbg(1, msp_debug, client, "set audmode %d\n", audmode);
3217061561e640c2947ab93c4e2a437327657c4482eHans Verkuil	switch (audmode) {
3227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_STEREO:
323301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil	case V4L2_TUNER_MODE_LANG1_LANG2:
3248a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		src |= 0x0020;
3257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_MONO:
3277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->mode == MSP_MODE_AM_NICAM) {
328f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "switching to AM mono\n");
3297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* AM mono decoding is handled by tuner, not MSP chip */
3307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* SCART switching control register */
3317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_scart(client, SCART_MONO, 0);
3327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			src = 0x0200;
3337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
3347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
3358a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
3368a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			src = 0x0030;
3378a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		break;
3387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_LANG1:
3397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case V4L2_TUNER_MODE_LANG2:
3418a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		src |= 0x0010;
3427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3448a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
3457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3468a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	msp_set_source(client, src);
3477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
3487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic void msp3400c_print_mode(struct i2c_client *client)
3507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
3517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
3527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->main == state->second) {
354f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n",
3557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->main / 910000, (state->main / 910) % 1000);
3567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	} else {
357f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n",
3587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->main / 910000, (state->main / 910) % 1000);
3597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
361f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "NICAM/FM carrier  : %d.%03d MHz\n",
3627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second/910) % 1000);
3637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_AM_NICAM)
364f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "NICAM/AM carrier  : %d.%03d MHz\n",
3657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second / 910) % 1000);
3667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
367f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n",
3687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		       state->second / 910000, (state->second / 910) % 1000);
3697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
3707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
3717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* ----------------------------------------------------------------------- */
3737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3748a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuilstatic int msp3400c_detect_stereo(struct i2c_client *client)
3757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
3767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
3777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int val;
3787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int rxsubchans = state->rxsubchans;
3798a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	int newnicam = state->nicam_on;
3807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int update = 0;
3817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
3827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	switch (state->mode) {
3837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_TERRA:
3847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val = msp_read_dsp(client, 0x18);
3857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val > 32767)
3867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val -= 65536;
387f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
3883bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		if (val > 8192) {
3898a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			rxsubchans = V4L2_TUNER_SUB_STEREO;
3907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else if (val < -4096) {
3917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
3927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
3937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_MONO;
3947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
3957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		newnicam = 0;
3967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
3977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM1:
3987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_FM_NICAM2:
3997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	case MSP_MODE_AM_NICAM:
4007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val = msp_read_dem(client, 0x23);
401f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "nicam sync=%d, mode=%d\n",
4027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val & 1, (val & 0x1e) >> 1);
4037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (val & 1) {
4057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* nicam synced */
4067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			switch ((val & 0x1e) >> 1)  {
4077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 0:
4087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 8:
4097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				rxsubchans = V4L2_TUNER_SUB_STEREO;
4107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 1:
4127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 9:
4138a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				rxsubchans = V4L2_TUNER_SUB_MONO;
4147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 2:
4167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			case 10:
4178a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
4187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			default:
4207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				rxsubchans = V4L2_TUNER_SUB_MONO;
4217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
4227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
4237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			newnicam = 1;
4247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
4257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			newnicam = 0;
4267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			rxsubchans = V4L2_TUNER_SUB_MONO;
4277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
4287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		break;
4297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (rxsubchans != state->rxsubchans) {
4317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		update = 1;
4328a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
4338a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			state->rxsubchans, rxsubchans);
4347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->rxsubchans = rxsubchans;
4357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (newnicam != state->nicam_on) {
4377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		update = 1;
438f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n",
4398a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			state->nicam_on, newnicam);
4407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->nicam_on = newnicam;
4417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return update;
4437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
4447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/*
4467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * A kernel thread for msp3400 control -- we don't want to block the
4477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil * in the ioctl while doing the sound carrier & stereo detect
4487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil */
4497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* stereo/multilang monitoring */
4507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilstatic void watch_stereo(struct i2c_client *client)
4517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
4527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
4537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
454de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	if (msp_detect_stereo(client)) {
455de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_set_audmode(client);
4567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
4577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
458f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	if (msp_once)
4597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
4607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
4617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp3400c_thread(void *data)
4637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
4647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
4657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
4667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp3400c_carrier_detect *cd;
4678a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	int count, max1, max2, val1, val2, val, this;
4687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
470f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
4717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
472f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n");
4737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state, -1);
474f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
4757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
4778a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
4787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
4797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
4807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
4817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4827560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil		if (state->radio || MSP_MODE_EXTERN == state->mode) {
4837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* no carrier scan, just unmute */
484f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
4853bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			state->scan_in_progress = 0;
4862eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
4877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_audio(client);
4887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
4897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
4907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
4913bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* mute audio */
4923bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->scan_in_progress = 1;
4933bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		msp_set_audio(client);
4940020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil
495de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp3400c_set_mode(client, MSP_MODE_AM_DETECT);
4967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		val1 = val2 = 0;
4977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		max1 = max2 = -1;
4987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
4998a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->nicam_on = 0;
5007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5013bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* wait for tuner to settle down after a channel change */
5028a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		if (msp_sleep(state, 200))
5037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			goto restart;
5047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* carrier detect pass #1 -- main carrier */
5067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		cd = msp3400c_carrier_detect_main;
5077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		count = ARRAY_SIZE(msp3400c_carrier_detect_main);
5087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
509f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
5107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetect doesn't work well with AM ... */
5117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			max1 = 3;
5127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
513f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "AM sound override\n");
5147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (this = 0; this < count; this++) {
5178a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
5187e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state,100))
5197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
5207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dsp(client, 0x1b);
5217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val > 32767)
5227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val -= 65536;
5237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val1 < val)
5247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val1 = val, max1 = this;
525f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
5267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* carrier detect pass #2 -- second (stereo) carrier */
5297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (max1) {
5307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 1: /* 5.5 */
5317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = msp3400c_carrier_detect_55;
5327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = ARRAY_SIZE(msp3400c_carrier_detect_55);
5337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 3: /* 6.5 */
5357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = msp3400c_carrier_detect_65;
5367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = ARRAY_SIZE(msp3400c_carrier_detect_65);
5377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0: /* 4.5 */
5397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 2: /* 6.0 */
5407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		default:
5417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = NULL;
5427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
5437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
546f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_amsound && (state->v4l2_std & V4L2_STD_SECAM)) {
5477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetect doesn't work well with AM ... */
5487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			cd = NULL;
5497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			count = 0;
5507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			max2 = 0;
5517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (this = 0; this < count; this++) {
5538a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
5547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state,100))
5557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
5567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dsp(client, 0x1b);
5577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val > 32767)
5587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val -= 65536;
5597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val2 < val)
5607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val2 = val, max2 = this;
561f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
5627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
5637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
5647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* program the msp3400 according to the results */
5658a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->main = msp3400c_carrier_detect_main[max1].cdo;
5667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (max1) {
5677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 1: /* 5.5 */
5687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (max2 == 0) {
5697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* B/G FM-stereo */
5707e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_55[max2].cdo;
5718a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
5727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5737560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			} else if (max2 == 1 && state->has_nicam) {
5747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* B/G NICAM */
5757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_55[max2].cdo;
5768a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
5777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 1;
5787e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			} else {
5807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto no_second;
5817e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
5827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5837e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 2: /* 6.0 */
5847e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* PAL I NICAM */
5857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->second = MSP_CARRIER(6.552);
5868a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_mode(client, MSP_MODE_FM_NICAM2);
5877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
5887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
5897e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
5907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 3: /* 6.5 */
5917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (max2 == 1 || max2 == 2) {
5927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* D/K FM-stereo */
5937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
5948a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
5957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
5965af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			} else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
5977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* L NICAM or AM-mono */
5987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
5998a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_AM_NICAM);
6007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
6017560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			} else if (max2 == 0 && state->has_nicam) {
6027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* D/K NICAM */
6037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->second = msp3400c_carrier_detect_65[max2].cdo;
6048a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
6057e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->nicam_on = 1;
6067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->watch_stereo = 1;
6077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			} else {
6087e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto no_second;
6097e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
6107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0: /* 4.5 */
6127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		default:
6137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		no_second:
6147e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->second = msp3400c_carrier_detect_main[max1].cdo;
6158a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
6167e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6177e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6180020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		msp3400c_set_carrier(client, state->second, state->main);
6197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6203bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* unmute */
6213bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->scan_in_progress = 0;
6228a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp3400c_set_audmode(client);
6233bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		msp_set_audio(client);
6247e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
625f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_debug)
6267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp3400c_print_mode(client);
6277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6288a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		/* monitor tv audio mode, the first time don't wait
6298a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		   so long to get a quick stereo/bilingual result */
6303bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		count = 3;
6317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		while (state->watch_stereo) {
6323bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			if (msp_sleep(state, count ? 1000 : 5000))
6337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
6340020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil			if (count) count--;
6353bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			watch_stereo(client);
6367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
638f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "thread: exit\n");
6397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
6407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
6417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp3410d_thread(void *data)
6447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
6457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
6467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
6470020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	int val, i, std, count;
6487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
649f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n");
6507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
652f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
6537e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state,-1);
654f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
6557e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6567e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
6578a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
6587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
6597e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
6607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
6617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (state->mode == MSP_MODE_EXTERN) {
6637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* no carrier scan needed, just unmute */
664f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
6653bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			state->scan_in_progress = 0;
6667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_set_audio(client);
6677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
6687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
6697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6703bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* mute audio */
6713bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->scan_in_progress = 1;
6723bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		msp_set_audio(client);
6737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
674de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* start autodetect. Note: autodetect is not supported for
675de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		   NTSC-M and radio, hence we force the standard in those cases. */
6765af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		if (state->radio)
6775af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			std = 0x40;
678d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil		else
6795af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
6807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->watch_stereo = 0;
6818a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->nicam_on = 0;
6827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6833bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* wait for tuner to settle down after a channel change */
6843bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		if (msp_sleep(state, 200))
6853bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			goto restart;
6863bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil
687f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_debug)
6888a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
6895af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			       msp_standard_std_name(std), std);
6907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
6917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (std != 1) {
6927e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* programmed some specific mode */
6937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = std;
6947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		} else {
6957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* triggered autodetect */
6965af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			msp_write_dem(client, 0x20, std);
6977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			for (;;) {
698d312a46e5340be6a89c662ac483230c0737148c9Hans Verkuil				if (msp_sleep(state, 100))
6997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					goto restart;
7007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				/* check results */
7027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				val = msp_read_dem(client, 0x7e);
7037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				if (val < 0x07ff)
7047e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					break;
7058a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				v4l_dbg(2, msp_debug, client, "detection still in progress\n");
7067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
7077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7085af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		for (i = 0; msp_stdlist[i].name != NULL; i++)
7095af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			if (msp_stdlist[i].retval == val)
7107e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
711f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n",
7125af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			msp_standard_std_name(val), val);
7135af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		state->main   = msp_stdlist[i].main;
7145af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		state->second = msp_stdlist[i].second;
7155af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		state->std = val;
7163bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->rxsubchans = V4L2_TUNER_SUB_MONO;
7175af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil
718f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
7195af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil				(val != 0x0009)) {
7207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* autodetection has failed, let backup */
721f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "autodetection failed,"
7225af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil				" switching to backup standard: %s (0x%04x)\n",
7235af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil				msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
724de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			state->std = val = 0x0009;
7257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			msp_write_dem(client, 0x20, val);
7267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* set stereo */
7297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		switch (val) {
7307e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0008: /* B/G NICAM */
7317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x000a: /* I NICAM */
732de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		case 0x000b: /* D/K NICAM */
733de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			if (val == 0x000a)
7347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				state->mode = MSP_MODE_FM_NICAM2;
735de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			else
736de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil				state->mode = MSP_MODE_FM_NICAM1;
7377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* just turn on stereo */
7387e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
7397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7407e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0009:
7427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->mode = MSP_MODE_AM_NICAM;
7437e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->nicam_on = 1;
7447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7457e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0020: /* BTSC */
7478a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			/* The pre-'G' models only have BTSC-mono */
7487e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->mode = MSP_MODE_BTSC;
7497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0040: /* FM radio */
7517560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			state->mode = MSP_MODE_FM_RADIO;
7527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
7537560d7a4f9add362d60d4513033cf522c37adeeaHans Verkuil			/* not needed in theory if we have radio, but
7547e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			   short programming enables carrier mute */
7558a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
7568a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil			msp3400c_set_carrier(client, MSP_CARRIER(10.7),
7577e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil					    MSP_CARRIER(10.7));
7587e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
759de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		case 0x0002:
7607e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0003:
7617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0004:
7627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		case 0x0005:
7635af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			state->mode = MSP_MODE_FM_TERRA;
7647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			state->watch_stereo = 1;
7657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
7667e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7677e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
768de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* set various prescales */
769de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dsp(client, 0x0d, 0x1900); /* scart */
770de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dsp(client, 0x0e, 0x3000); /* FM */
771de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->has_nicam)
772de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
773de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
7745af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		if (state->has_i2s_conf)
7755af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil			msp_write_dem(client, 0x40, state->i2s_mode);
7767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7773bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		/* unmute */
7788a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp3400c_set_audmode(client);
7793bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		state->scan_in_progress = 0;
7803bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		msp_set_audio(client);
7818a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
7828a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		/* monitor tv audio mode, the first time don't wait
7838a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		   so long to get a quick stereo/bilingual result */
7843bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil		count = 3;
7857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		while (state->watch_stereo) {
7863bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			if (msp_sleep(state, count ? 1000 : 5000))
7878a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil				goto restart;
7880020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil			if (count) count--;
7893bbe5a83996c0a669250d91421eef054f3a30595Hans Verkuil			watch_stereo(client);
7907e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
7917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
792f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "thread: exit\n");
7937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
7947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
7957e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
7967e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil/* ----------------------------------------------------------------------- */
7977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
798de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil/* msp34xxG + (autoselect no-thread)
799de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil * this one uses both automatic standard detection and automatic sound
800de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil * select which are available in the newer G versions
801de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil * struct msp: only norm, acb and source are really used in this mode
802de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil */
8037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
8049a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuilstatic int msp34xxg_modus(struct i2c_client *client)
8059a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil{
8069a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8079a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil
8089a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->radio) {
8099a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected radio modus\n");
8109a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x0001;
8119a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8129a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil
8139a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std & V4L2_STD_PAL) {
8149a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected PAL modus\n");
8159a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x7001;
8169a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8179a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std == V4L2_STD_NTSC_M_JP) {
8189a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n");
8199a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x4001;
8209a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8219a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std == V4L2_STD_NTSC_M_KR) {
8229a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n");
8239a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x0001;
8249a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8259a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std & V4L2_STD_MN) {
8269a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n");
8279a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x2001;
8289a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8299a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	if (state->v4l2_std & V4L2_STD_SECAM) {
8309a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		v4l_dbg(1, msp_debug, client, "selected SECAM modus\n");
8319a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil		return 0x6001;
8329a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	}
8339a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	return 0x0001;
8349a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil}
8359a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil
8362474ed444b475614ef795523076be7cc8437ae00Hans Verkuilstatic void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
8372474ed444b475614ef795523076be7cc8437ae00Hans Verkuil {
8382474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8392474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	int source, matrix;
8402474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8412474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	switch (state->audmode) {
8422474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	case V4L2_TUNER_MODE_MONO:
8432474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = 0; /* mono only */
8442474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		matrix = 0x30;
8452474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		break;
8462474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	case V4L2_TUNER_MODE_LANG2:
8472474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = 4; /* stereo or B */
8482474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		matrix = 0x10;
8492474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		break;
850301e22d69140898eddd38a9134da711cb5dfc170Hans Verkuil	case V4L2_TUNER_MODE_LANG1_LANG2:
8512474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = 1; /* stereo or A|B */
8522474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		matrix = 0x20;
8532474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		break;
8540020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	case V4L2_TUNER_MODE_STEREO:
8550020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	case V4L2_TUNER_MODE_LANG1:
8560020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	default:
8570020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		source = 3; /* stereo or A */
8580020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		matrix = 0x00;
8590020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil		break;
8602474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	}
8612474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
86207151724a35e8e70f1aa64ce30a5a3f5c1ad49a3Hans Verkuil	if (in == MSP_DSP_IN_TUNER)
8632474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = (source << 8) | 0x20;
8642474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	/* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14
8652474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	   instead of 11, 12, 13. So we add one for that msp version. */
86607151724a35e8e70f1aa64ce30a5a3f5c1ad49a3Hans Verkuil	else if (in >= MSP_DSP_IN_MAIN_AVC && state->has_dolby_pro_logic)
8672474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = ((in + 1) << 8) | matrix;
8682474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	else
8692474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		source = (in << 8) | matrix;
8702474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8712474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n",
8722474ed444b475614ef795523076be7cc8437ae00Hans Verkuil			in, source, reg);
8732474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp_write_dsp(client, reg, source);
8742474ed444b475614ef795523076be7cc8437ae00Hans Verkuil}
8752474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8762474ed444b475614ef795523076be7cc8437ae00Hans Verkuilstatic void msp34xxg_set_sources(struct i2c_client *client)
8772474ed444b475614ef795523076be7cc8437ae00Hans Verkuil{
8782474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8792474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	u32 in = state->routing.input;
8802474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
8812474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf);
8822474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	/* quasi-peak detector is set to same input as the loudspeaker (MAIN) */
8832474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf);
8842474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf);
8852474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf);
8860020d3ef915fc01a0184bc96eeb3c240bded5d8eHans Verkuil	if (state->has_scart2_out)
8872474ed444b475614ef795523076be7cc8437ae00Hans Verkuil		msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf);
8882474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf);
8892474ed444b475614ef795523076be7cc8437ae00Hans Verkuil}
8902474ed444b475614ef795523076be7cc8437ae00Hans Verkuil
891de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil/* (re-)initialize the msp34xxg */
892de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuilstatic void msp34xxg_reset(struct i2c_client *client)
8937e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
8947e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
8952474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	int tuner = (state->routing.input >> 3) & 1;
896de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	int modus;
8977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
898de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	/* initialize std to 1 (autodetect) to signal that no standard is
899de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	   selected yet. */
900de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	state->std = 1;
901de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
902de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_reset(client);
9037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9045af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil	if (state->has_i2s_conf)
9055af0c8f6a09534ebc6c56b4e5d79d0d521364750Hans Verkuil		msp_write_dem(client, 0x40, state->i2s_mode);
9067e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9077e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* step-by-step initialisation, as described in the manual */
9089a80a93da738c631de644175fbd669ab9a9cb624Hans Verkuil	modus = msp34xxg_modus(client);
9092474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	modus |= tuner ? 0x100 : 0;
910de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dem(client, 0x30, modus);
9117e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9127e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	/* write the dsps that may have an influence on
9137e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	   standard/audio autodetection right now */
9142474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_sources(client);
9157e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
916de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dsp(client, 0x0d, 0x1900); /* scart */
917de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dsp(client, 0x0e, 0x3000); /* FM */
918de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	if (state->has_nicam)
919de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dsp(client, 0x10, 0x5a00); /* nicam */
9207e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
921de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	/* set identification threshold. Personally, I
922de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * I set it to a higher value than the default
923de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * of 0x190 to ignore noisy stereo signals.
924de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * this needs tuning. (recommended range 0x00a0-0x03c0)
925de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * 0x7f0 = forced mono mode
926de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 *
927de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * a2 threshold for stereo/bilingual.
928de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * Note: this register is part of the Manual/Compatibility mode.
929de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 * It is supported by all 'G'-family chips.
930de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	 */
931de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	msp_write_dem(client, 0x22, msp_stereo_thresh);
9327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
9337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9347e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuilint msp34xxg_thread(void *data)
9357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
9367e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct i2c_client *client = data;
9377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
938de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	int val, i;
9397e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
940f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
9417e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	for (;;) {
943f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n");
9447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_sleep(state, -1);
945f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n");
9467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	restart:
948f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab		v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
9497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		state->restart = 0;
9507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (kthread_should_stop())
9517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			break;
9527e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9532eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		if (state->mode == MSP_MODE_EXTERN) {
9542eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			/* no carrier scan needed, just unmute */
9552eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
9562eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			state->scan_in_progress = 0;
9572eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			msp_set_audio(client);
9582eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			continue;
9592eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		}
9602eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil
9617e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* setup the chip*/
9627e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp34xxg_reset(client);
963de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		state->std = state->radio ? 0x40 : msp_standard;
964de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->std != 1)
9657e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			goto unmute;
966de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* start autodetect */
967de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		msp_write_dem(client, 0x20, state->std);
9687e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9697e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* watch autodetect */
970de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n");
9717e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		for (i = 0; i < 10; i++) {
9727e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (msp_sleep(state, 100))
9737e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				goto restart;
9747e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9757e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			/* check results */
9767e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			val = msp_read_dem(client, 0x7e);
9777e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			if (val < 0x07ff) {
978de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil				state->std = val;
9797e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil				break;
9807e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			}
981f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(2, msp_debug, client, "detection still in progress\n");
9827e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
983de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->std == 1) {
984f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab			v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n");
9857e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			continue;
9867e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		}
9877e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9887e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	unmute:
989de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
990de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			msp_standard_std_name(state->std), state->std);
9917e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
9922eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		if (state->std == 9) {
9932eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			/* AM NICAM mode */
9942eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil			msp_write_dsp(client, 0x0e, 0x7c00);
9952eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil		}
9962eb606db1134ce860cc0cbf8b533b6315d182e21Hans Verkuil
9977e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* unmute: dispatch sound to scart output, set scart volume */
9987e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		msp_set_audio(client);
9997e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
10007e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		/* restore ACB */
10017e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		if (msp_write_dsp(client, 0x13, state->acb))
10027e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil			return -1;
10037e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1004de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* the periodic stereo/SAP check is only relevant for
1005de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		   the 0x20 standard (BTSC) */
1006de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->std != 0x20)
1007de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			continue;
1008de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
1009de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		state->watch_stereo = 1;
1010de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
1011de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		/* monitor tv audio mode, the first time don't wait
1012de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		   in order to get a quick stereo/SAP update */
1013de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		watch_stereo(client);
1014de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		while (state->watch_stereo) {
1015de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			watch_stereo(client);
1016de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			if (msp_sleep(state, 5000))
1017de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil				goto restart;
1018de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		}
10197e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
1020f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "thread: exit\n");
10217e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	return 0;
10227e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
10237e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1024de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuilstatic int msp34xxg_detect_stereo(struct i2c_client *client)
10257e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
10267e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
10277e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int status = msp_read_dem(client, 0x0200);
10287e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int is_bilingual = status & 0x100;
10297e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	int is_stereo = status & 0x40;
1030de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	int oldrx = state->rxsubchans;
10317e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
10327e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	state->rxsubchans = 0;
10337e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (is_stereo)
10348a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->rxsubchans = V4L2_TUNER_SUB_STEREO;
10357e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	else
10368a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		state->rxsubchans = V4L2_TUNER_SUB_MONO;
10377e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	if (is_bilingual) {
1038de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		if (state->std == 0x20)
1039de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			state->rxsubchans |= V4L2_TUNER_SUB_SAP;
1040de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		else
1041de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
10427e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	}
1043f167cb4e6ee07914b66eb85fc0bf006a409b6838Mauro Carvalho Chehab	v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
10447e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil		status, is_stereo, is_bilingual, state->rxsubchans);
1045de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	return (oldrx != state->rxsubchans);
10467e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
10477e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1048044f324f6ea5d55391db62fca6a295b2651cb946Adrian Bunkstatic void msp34xxg_set_audmode(struct i2c_client *client)
10497e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil{
10507e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
10517e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
1052de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	if (state->std == 0x20) {
1053de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	       if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) &&
1054cc33668b1eed1eac43f00cec639066047323b01dMauro Carvalho Chehab		   (state->audmode == V4L2_TUNER_MODE_LANG1_LANG2 ||
1055de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		    state->audmode == V4L2_TUNER_MODE_LANG2)) {
1056de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			msp_write_dem(client, 0x20, 0x21);
1057de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	       } else {
1058de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil			msp_write_dem(client, 0x20, 0x20);
1059de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	       }
1060de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	}
1061de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil
10622474ed444b475614ef795523076be7cc8437ae00Hans Verkuil	msp34xxg_set_sources(client);
10637e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil}
10647e8b09ea1636e360a8fabebeaeb91c17f64e01b5Hans Verkuil
10658a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuilvoid msp_set_audmode(struct i2c_client *client)
10668a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil{
10678a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	struct msp_state *state = i2c_get_clientdata(client);
10688a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
10698a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	switch (state->opmode) {
10708a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_MANUAL:
10718a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_AUTODETECT:
10728a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp3400c_set_audmode(client);
10738a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		break;
10748a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_AUTOSELECT:
10758a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		msp34xxg_set_audmode(client);
10768a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil		break;
10778a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	}
10788a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil}
10798a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
1080de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuilint msp_detect_stereo(struct i2c_client *client)
10818a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil{
10828a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	struct msp_state *state  = i2c_get_clientdata(client);
10838a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
10848a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	switch (state->opmode) {
10858a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_MANUAL:
10868a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_AUTODETECT:
1087de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		return msp3400c_detect_stereo(client);
10888a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	case OPMODE_AUTOSELECT:
1089de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil		return msp34xxg_detect_stereo(client);
10908a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil	}
1091de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9Hans Verkuil	return 0;
10928a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil}
10938a4b275f9c192921797f45c2d4b5e4bc3875500aHans Verkuil
1094