xref: /openbmc/linux/drivers/media/i2c/sony-btf-mpx.c (revision aaeb31c0)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c7c54a98SHans Verkuil /*
3c7c54a98SHans Verkuil  * Copyright (C) 2005-2006 Micronas USA Inc.
4c7c54a98SHans Verkuil  */
5c7c54a98SHans Verkuil 
6c7c54a98SHans Verkuil #include <linux/module.h>
7c7c54a98SHans Verkuil #include <linux/init.h>
8c7c54a98SHans Verkuil #include <linux/i2c.h>
9c7c54a98SHans Verkuil #include <linux/videodev2.h>
10c7c54a98SHans Verkuil #include <media/tuner.h>
11c7c54a98SHans Verkuil #include <media/v4l2-common.h>
12c7c54a98SHans Verkuil #include <media/v4l2-ioctl.h>
13c7c54a98SHans Verkuil #include <media/v4l2-device.h>
14c7c54a98SHans Verkuil #include <linux/slab.h>
15c7c54a98SHans Verkuil 
16c7c54a98SHans Verkuil MODULE_DESCRIPTION("sony-btf-mpx driver");
17c7c54a98SHans Verkuil MODULE_LICENSE("GPL v2");
18c7c54a98SHans Verkuil 
19c7c54a98SHans Verkuil static int debug;
20c7c54a98SHans Verkuil module_param(debug, int, 0644);
215c75a55eSJean Delvare MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on");
22c7c54a98SHans Verkuil 
23c7c54a98SHans Verkuil /* #define MPX_DEBUG */
24c7c54a98SHans Verkuil 
25c7c54a98SHans Verkuil /*
26c7c54a98SHans Verkuil  * Note:
27c7c54a98SHans Verkuil  *
28c7c54a98SHans Verkuil  * AS(IF/MPX) pin:      LOW      HIGH/OPEN
29c7c54a98SHans Verkuil  * IF/MPX address:   0x42/0x40   0x43/0x44
30c7c54a98SHans Verkuil  */
31c7c54a98SHans Verkuil 
32c7c54a98SHans Verkuil 
33c7c54a98SHans Verkuil static int force_mpx_mode = -1;
34c7c54a98SHans Verkuil module_param(force_mpx_mode, int, 0644);
35c7c54a98SHans Verkuil 
36c7c54a98SHans Verkuil struct sony_btf_mpx {
37c7c54a98SHans Verkuil 	struct v4l2_subdev sd;
38c7c54a98SHans Verkuil 	int mpxmode;
39c7c54a98SHans Verkuil 	u32 audmode;
40c7c54a98SHans Verkuil };
41c7c54a98SHans Verkuil 
to_state(struct v4l2_subdev * sd)42c7c54a98SHans Verkuil static inline struct sony_btf_mpx *to_state(struct v4l2_subdev *sd)
43c7c54a98SHans Verkuil {
44c7c54a98SHans Verkuil 	return container_of(sd, struct sony_btf_mpx, sd);
45c7c54a98SHans Verkuil }
46c7c54a98SHans Verkuil 
mpx_write(struct i2c_client * client,int dev,int addr,int val)47c7c54a98SHans Verkuil static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
48c7c54a98SHans Verkuil {
49c7c54a98SHans Verkuil 	u8 buffer[5];
50c7c54a98SHans Verkuil 	struct i2c_msg msg;
51c7c54a98SHans Verkuil 
52c7c54a98SHans Verkuil 	buffer[0] = dev;
53c7c54a98SHans Verkuil 	buffer[1] = addr >> 8;
54c7c54a98SHans Verkuil 	buffer[2] = addr & 0xff;
55c7c54a98SHans Verkuil 	buffer[3] = val >> 8;
56c7c54a98SHans Verkuil 	buffer[4] = val & 0xff;
57c7c54a98SHans Verkuil 	msg.addr = client->addr;
58c7c54a98SHans Verkuil 	msg.flags = 0;
59c7c54a98SHans Verkuil 	msg.len = 5;
60c7c54a98SHans Verkuil 	msg.buf = buffer;
61c7c54a98SHans Verkuil 	i2c_transfer(client->adapter, &msg, 1);
62c7c54a98SHans Verkuil 	return 0;
63c7c54a98SHans Verkuil }
64c7c54a98SHans Verkuil 
65c7c54a98SHans Verkuil /*
66c7c54a98SHans Verkuil  * MPX register values for the BTF-PG472Z:
67c7c54a98SHans Verkuil  *
68c7c54a98SHans Verkuil  *                                 FM_     NICAM_  SCART_
69c7c54a98SHans Verkuil  *          MODUS  SOURCE    ACB   PRESCAL PRESCAL PRESCAL SYSTEM  VOLUME
70c7c54a98SHans Verkuil  *         10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
71c7c54a98SHans Verkuil  *         ---------------------------------------------------------------
72c7c54a98SHans Verkuil  * Auto     1003    0020    0100    2603    5000    XXXX    0001    7500
73c7c54a98SHans Verkuil  *
74c7c54a98SHans Verkuil  * B/G
75c7c54a98SHans Verkuil  *  Mono    1003    0020    0100    2603    5000    XXXX    0003    7500
76c7c54a98SHans Verkuil  *  A2      1003    0020    0100    2601    5000    XXXX    0003    7500
77c7c54a98SHans Verkuil  *  NICAM   1003    0120    0100    2603    5000    XXXX    0008    7500
78c7c54a98SHans Verkuil  *
79c7c54a98SHans Verkuil  * I
80c7c54a98SHans Verkuil  *  Mono    1003    0020    0100    2603    7900    XXXX    000A    7500
81c7c54a98SHans Verkuil  *  NICAM   1003    0120    0100    2603    7900    XXXX    000A    7500
82c7c54a98SHans Verkuil  *
83c7c54a98SHans Verkuil  * D/K
84c7c54a98SHans Verkuil  *  Mono    1003    0020    0100    2603    5000    XXXX    0004    7500
85c7c54a98SHans Verkuil  *  A2-1    1003    0020    0100    2601    5000    XXXX    0004    7500
86c7c54a98SHans Verkuil  *  A2-2    1003    0020    0100    2601    5000    XXXX    0005    7500
87c7c54a98SHans Verkuil  *  A2-3    1003    0020    0100    2601    5000    XXXX    0007    7500
88c7c54a98SHans Verkuil  *  NICAM   1003    0120    0100    2603    5000    XXXX    000B    7500
89c7c54a98SHans Verkuil  *
90c7c54a98SHans Verkuil  * L/L'
91c7c54a98SHans Verkuil  *  Mono    0003    0200    0100    7C03    5000    2200    0009    7500
92c7c54a98SHans Verkuil  *  NICAM   0003    0120    0100    7C03    5000    XXXX    0009    7500
93c7c54a98SHans Verkuil  *
94c7c54a98SHans Verkuil  * M
95c7c54a98SHans Verkuil  *  Mono    1003    0200    0100    2B03    5000    2B00    0002    7500
96c7c54a98SHans Verkuil  *
97c7c54a98SHans Verkuil  * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
98c7c54a98SHans Verkuil  *
99c7c54a98SHans Verkuil  * Bilingual selection in A2/NICAM:
100c7c54a98SHans Verkuil  *
101c7c54a98SHans Verkuil  *         High byte of SOURCE     Left chan   Right chan
102c7c54a98SHans Verkuil  *                 0x01              MAIN         SUB
103c7c54a98SHans Verkuil  *                 0x03              MAIN         MAIN
104c7c54a98SHans Verkuil  *                 0x04              SUB          SUB
105c7c54a98SHans Verkuil  *
106c7c54a98SHans Verkuil  * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
107c7c54a98SHans Verkuil  * 0x00 (all other bands).  Force mono in A2 with FMONO_A2:
108c7c54a98SHans Verkuil  *
109c7c54a98SHans Verkuil  *                      FMONO_A2
110c7c54a98SHans Verkuil  *                      10/0022
111c7c54a98SHans Verkuil  *                      --------
112c7c54a98SHans Verkuil  *     Forced mono ON     07F0
113c7c54a98SHans Verkuil  *     Forced mono OFF    0190
114c7c54a98SHans Verkuil  */
115c7c54a98SHans Verkuil 
116c7c54a98SHans Verkuil static const struct {
117c7c54a98SHans Verkuil 	enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
118c7c54a98SHans Verkuil 	u16 modus;
119c7c54a98SHans Verkuil 	u16 source;
120c7c54a98SHans Verkuil 	u16 acb;
121c7c54a98SHans Verkuil 	u16 fm_prescale;
122c7c54a98SHans Verkuil 	u16 nicam_prescale;
123c7c54a98SHans Verkuil 	u16 scart_prescale;
124c7c54a98SHans Verkuil 	u16 system;
125c7c54a98SHans Verkuil 	u16 volume;
126c7c54a98SHans Verkuil } mpx_audio_modes[] = {
127c7c54a98SHans Verkuil 	/* Auto */	{ AUD_MONO,	0x1003, 0x0020, 0x0100, 0x2603,
128c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0001, 0x7500 },
129c7c54a98SHans Verkuil 	/* B/G Mono */	{ AUD_MONO,	0x1003, 0x0020, 0x0100, 0x2603,
130c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0003, 0x7500 },
131c7c54a98SHans Verkuil 	/* B/G A2 */	{ AUD_A2,	0x1003, 0x0020, 0x0100, 0x2601,
132c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0003, 0x7500 },
133c7c54a98SHans Verkuil 	/* B/G NICAM */ { AUD_NICAM,	0x1003, 0x0120, 0x0100, 0x2603,
134c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0008, 0x7500 },
135c7c54a98SHans Verkuil 	/* I Mono */	{ AUD_MONO,	0x1003, 0x0020, 0x0100, 0x2603,
136c7c54a98SHans Verkuil 					0x7900, 0x0000, 0x000A, 0x7500 },
137c7c54a98SHans Verkuil 	/* I NICAM */	{ AUD_NICAM,	0x1003, 0x0120, 0x0100, 0x2603,
138c7c54a98SHans Verkuil 					0x7900, 0x0000, 0x000A, 0x7500 },
139c7c54a98SHans Verkuil 	/* D/K Mono */	{ AUD_MONO,	0x1003, 0x0020, 0x0100, 0x2603,
140c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0004, 0x7500 },
141c7c54a98SHans Verkuil 	/* D/K A2-1 */	{ AUD_A2,	0x1003, 0x0020, 0x0100, 0x2601,
142c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0004, 0x7500 },
143c7c54a98SHans Verkuil 	/* D/K A2-2 */	{ AUD_A2,	0x1003, 0x0020, 0x0100, 0x2601,
144c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0005, 0x7500 },
145c7c54a98SHans Verkuil 	/* D/K A2-3 */	{ AUD_A2,	0x1003, 0x0020, 0x0100, 0x2601,
146c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0007, 0x7500 },
147c7c54a98SHans Verkuil 	/* D/K NICAM */	{ AUD_NICAM,	0x1003, 0x0120, 0x0100, 0x2603,
148c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x000B, 0x7500 },
149c7c54a98SHans Verkuil 	/* L/L' Mono */	{ AUD_MONO,	0x0003, 0x0200, 0x0100, 0x7C03,
150c7c54a98SHans Verkuil 					0x5000, 0x2200, 0x0009, 0x7500 },
151c7c54a98SHans Verkuil 	/* L/L' NICAM */{ AUD_NICAM_L,	0x0003, 0x0120, 0x0100, 0x7C03,
152c7c54a98SHans Verkuil 					0x5000, 0x0000, 0x0009, 0x7500 },
153c7c54a98SHans Verkuil };
154c7c54a98SHans Verkuil 
155c7c54a98SHans Verkuil #define MPX_NUM_MODES	ARRAY_SIZE(mpx_audio_modes)
156c7c54a98SHans Verkuil 
mpx_setup(struct sony_btf_mpx * t)157c7c54a98SHans Verkuil static int mpx_setup(struct sony_btf_mpx *t)
158c7c54a98SHans Verkuil {
159c7c54a98SHans Verkuil 	struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
160c7c54a98SHans Verkuil 	u16 source = 0;
161c7c54a98SHans Verkuil 	u8 buffer[3];
162c7c54a98SHans Verkuil 	struct i2c_msg msg;
163c7c54a98SHans Verkuil 	int mode = t->mpxmode;
164c7c54a98SHans Verkuil 
165c7c54a98SHans Verkuil 	/* reset MPX */
166c7c54a98SHans Verkuil 	buffer[0] = 0x00;
167c7c54a98SHans Verkuil 	buffer[1] = 0x80;
168c7c54a98SHans Verkuil 	buffer[2] = 0x00;
169c7c54a98SHans Verkuil 	msg.addr = client->addr;
170c7c54a98SHans Verkuil 	msg.flags = 0;
171c7c54a98SHans Verkuil 	msg.len = 3;
172c7c54a98SHans Verkuil 	msg.buf = buffer;
173c7c54a98SHans Verkuil 	i2c_transfer(client->adapter, &msg, 1);
174c7c54a98SHans Verkuil 	buffer[1] = 0x00;
175c7c54a98SHans Verkuil 	i2c_transfer(client->adapter, &msg, 1);
176c7c54a98SHans Verkuil 
177c7c54a98SHans Verkuil 	if (t->audmode != V4L2_TUNER_MODE_MONO)
178c7c54a98SHans Verkuil 		mode++;
179c7c54a98SHans Verkuil 
180c7c54a98SHans Verkuil 	if (mpx_audio_modes[mode].audio_mode != AUD_MONO) {
181c7c54a98SHans Verkuil 		switch (t->audmode) {
182c7c54a98SHans Verkuil 		case V4L2_TUNER_MODE_MONO:
183c7c54a98SHans Verkuil 			switch (mpx_audio_modes[mode].audio_mode) {
184c7c54a98SHans Verkuil 			case AUD_A2:
185c7c54a98SHans Verkuil 				source = mpx_audio_modes[mode].source;
186c7c54a98SHans Verkuil 				break;
187c7c54a98SHans Verkuil 			case AUD_NICAM:
188c7c54a98SHans Verkuil 				source = 0x0000;
189c7c54a98SHans Verkuil 				break;
190c7c54a98SHans Verkuil 			case AUD_NICAM_L:
191c7c54a98SHans Verkuil 				source = 0x0200;
192c7c54a98SHans Verkuil 				break;
193c7c54a98SHans Verkuil 			default:
194c7c54a98SHans Verkuil 				break;
195c7c54a98SHans Verkuil 			}
196c7c54a98SHans Verkuil 			break;
197c7c54a98SHans Verkuil 		case V4L2_TUNER_MODE_STEREO:
198c7c54a98SHans Verkuil 			source = mpx_audio_modes[mode].source;
199c7c54a98SHans Verkuil 			break;
200c7c54a98SHans Verkuil 		case V4L2_TUNER_MODE_LANG1:
201c7c54a98SHans Verkuil 			source = 0x0300;
202c7c54a98SHans Verkuil 			break;
203c7c54a98SHans Verkuil 		case V4L2_TUNER_MODE_LANG2:
204c7c54a98SHans Verkuil 			source = 0x0400;
205c7c54a98SHans Verkuil 			break;
206c7c54a98SHans Verkuil 		}
207c7c54a98SHans Verkuil 		source |= mpx_audio_modes[mode].source & 0x00ff;
208c7c54a98SHans Verkuil 	} else
209c7c54a98SHans Verkuil 		source = mpx_audio_modes[mode].source;
210c7c54a98SHans Verkuil 
211c7c54a98SHans Verkuil 	mpx_write(client, 0x10, 0x0030, mpx_audio_modes[mode].modus);
212c7c54a98SHans Verkuil 	mpx_write(client, 0x12, 0x0008, source);
213c7c54a98SHans Verkuil 	mpx_write(client, 0x12, 0x0013, mpx_audio_modes[mode].acb);
214c7c54a98SHans Verkuil 	mpx_write(client, 0x12, 0x000e,
215c7c54a98SHans Verkuil 			mpx_audio_modes[mode].fm_prescale);
216c7c54a98SHans Verkuil 	mpx_write(client, 0x12, 0x0010,
217c7c54a98SHans Verkuil 			mpx_audio_modes[mode].nicam_prescale);
218c7c54a98SHans Verkuil 	mpx_write(client, 0x12, 0x000d,
219c7c54a98SHans Verkuil 			mpx_audio_modes[mode].scart_prescale);
220c7c54a98SHans Verkuil 	mpx_write(client, 0x10, 0x0020, mpx_audio_modes[mode].system);
221c7c54a98SHans Verkuil 	mpx_write(client, 0x12, 0x0000, mpx_audio_modes[mode].volume);
222c7c54a98SHans Verkuil 	if (mpx_audio_modes[mode].audio_mode == AUD_A2)
223c7c54a98SHans Verkuil 		mpx_write(client, 0x10, 0x0022,
224c7c54a98SHans Verkuil 			t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
225c7c54a98SHans Verkuil 
226c7c54a98SHans Verkuil #ifdef MPX_DEBUG
227c7c54a98SHans Verkuil 	{
228c7c54a98SHans Verkuil 		u8 buf1[3], buf2[2];
229c7c54a98SHans Verkuil 		struct i2c_msg msgs[2];
230c7c54a98SHans Verkuil 
231c7c54a98SHans Verkuil 		v4l2_info(client,
232c7c54a98SHans Verkuil 			"MPX registers: %04x %04x %04x %04x %04x %04x %04x %04x\n",
233c7c54a98SHans Verkuil 			mpx_audio_modes[mode].modus,
234c7c54a98SHans Verkuil 			source,
235c7c54a98SHans Verkuil 			mpx_audio_modes[mode].acb,
236c7c54a98SHans Verkuil 			mpx_audio_modes[mode].fm_prescale,
237c7c54a98SHans Verkuil 			mpx_audio_modes[mode].nicam_prescale,
238c7c54a98SHans Verkuil 			mpx_audio_modes[mode].scart_prescale,
239c7c54a98SHans Verkuil 			mpx_audio_modes[mode].system,
240c7c54a98SHans Verkuil 			mpx_audio_modes[mode].volume);
241c7c54a98SHans Verkuil 		buf1[0] = 0x11;
242c7c54a98SHans Verkuil 		buf1[1] = 0x00;
243c7c54a98SHans Verkuil 		buf1[2] = 0x7e;
244c7c54a98SHans Verkuil 		msgs[0].addr = client->addr;
245c7c54a98SHans Verkuil 		msgs[0].flags = 0;
246c7c54a98SHans Verkuil 		msgs[0].len = 3;
247c7c54a98SHans Verkuil 		msgs[0].buf = buf1;
248c7c54a98SHans Verkuil 		msgs[1].addr = client->addr;
249c7c54a98SHans Verkuil 		msgs[1].flags = I2C_M_RD;
250c7c54a98SHans Verkuil 		msgs[1].len = 2;
251c7c54a98SHans Verkuil 		msgs[1].buf = buf2;
252c7c54a98SHans Verkuil 		i2c_transfer(client->adapter, msgs, 2);
253c7c54a98SHans Verkuil 		v4l2_info(client, "MPX system: %02x%02x\n",
254c7c54a98SHans Verkuil 				buf2[0], buf2[1]);
255c7c54a98SHans Verkuil 		buf1[0] = 0x11;
256c7c54a98SHans Verkuil 		buf1[1] = 0x02;
257c7c54a98SHans Verkuil 		buf1[2] = 0x00;
258c7c54a98SHans Verkuil 		i2c_transfer(client->adapter, msgs, 2);
259c7c54a98SHans Verkuil 		v4l2_info(client, "MPX status: %02x%02x\n",
260c7c54a98SHans Verkuil 				buf2[0], buf2[1]);
261c7c54a98SHans Verkuil 	}
262c7c54a98SHans Verkuil #endif
263c7c54a98SHans Verkuil 	return 0;
264c7c54a98SHans Verkuil }
265c7c54a98SHans Verkuil 
266c7c54a98SHans Verkuil 
sony_btf_mpx_s_std(struct v4l2_subdev * sd,v4l2_std_id std)267c7c54a98SHans Verkuil static int sony_btf_mpx_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
268c7c54a98SHans Verkuil {
269c7c54a98SHans Verkuil 	struct sony_btf_mpx *t = to_state(sd);
270c7c54a98SHans Verkuil 	int default_mpx_mode = 0;
271c7c54a98SHans Verkuil 
272c7c54a98SHans Verkuil 	if (std & V4L2_STD_PAL_BG)
273c7c54a98SHans Verkuil 		default_mpx_mode = 1;
274c7c54a98SHans Verkuil 	else if (std & V4L2_STD_PAL_I)
275c7c54a98SHans Verkuil 		default_mpx_mode = 4;
276c7c54a98SHans Verkuil 	else if (std & V4L2_STD_PAL_DK)
277c7c54a98SHans Verkuil 		default_mpx_mode = 6;
278c7c54a98SHans Verkuil 	else if (std & V4L2_STD_SECAM_L)
279c7c54a98SHans Verkuil 		default_mpx_mode = 11;
280c7c54a98SHans Verkuil 
281c7c54a98SHans Verkuil 	if (default_mpx_mode != t->mpxmode) {
282c7c54a98SHans Verkuil 		t->mpxmode = default_mpx_mode;
283c7c54a98SHans Verkuil 		mpx_setup(t);
284c7c54a98SHans Verkuil 	}
285c7c54a98SHans Verkuil 	return 0;
286c7c54a98SHans Verkuil }
287c7c54a98SHans Verkuil 
sony_btf_mpx_g_tuner(struct v4l2_subdev * sd,struct v4l2_tuner * vt)288c7c54a98SHans Verkuil static int sony_btf_mpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
289c7c54a98SHans Verkuil {
290c7c54a98SHans Verkuil 	struct sony_btf_mpx *t = to_state(sd);
291c7c54a98SHans Verkuil 
292c7c54a98SHans Verkuil 	vt->capability = V4L2_TUNER_CAP_NORM |
293c7c54a98SHans Verkuil 		V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
294c7c54a98SHans Verkuil 		V4L2_TUNER_CAP_LANG2;
295c7c54a98SHans Verkuil 	vt->rxsubchans = V4L2_TUNER_SUB_MONO |
296c7c54a98SHans Verkuil 		V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
297c7c54a98SHans Verkuil 		V4L2_TUNER_SUB_LANG2;
298c7c54a98SHans Verkuil 	vt->audmode = t->audmode;
299c7c54a98SHans Verkuil 	return 0;
300c7c54a98SHans Verkuil }
301c7c54a98SHans Verkuil 
sony_btf_mpx_s_tuner(struct v4l2_subdev * sd,const struct v4l2_tuner * vt)302b781e6beSMauro Carvalho Chehab static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
303c7c54a98SHans Verkuil {
304c7c54a98SHans Verkuil 	struct sony_btf_mpx *t = to_state(sd);
305c7c54a98SHans Verkuil 
306c7c54a98SHans Verkuil 	if (vt->type != V4L2_TUNER_ANALOG_TV)
307c7c54a98SHans Verkuil 		return -EINVAL;
308c7c54a98SHans Verkuil 
309c7c54a98SHans Verkuil 	if (vt->audmode != t->audmode) {
310c7c54a98SHans Verkuil 		t->audmode = vt->audmode;
311c7c54a98SHans Verkuil 		mpx_setup(t);
312c7c54a98SHans Verkuil 	}
313c7c54a98SHans Verkuil 	return 0;
314c7c54a98SHans Verkuil }
315c7c54a98SHans Verkuil 
316c7c54a98SHans Verkuil /* --------------------------------------------------------------------------*/
317c7c54a98SHans Verkuil 
318c7c54a98SHans Verkuil static const struct v4l2_subdev_tuner_ops sony_btf_mpx_tuner_ops = {
319c7c54a98SHans Verkuil 	.s_tuner = sony_btf_mpx_s_tuner,
320c7c54a98SHans Verkuil 	.g_tuner = sony_btf_mpx_g_tuner,
321c7c54a98SHans Verkuil };
322c7c54a98SHans Verkuil 
3238774bed9SLaurent Pinchart static const struct v4l2_subdev_video_ops sony_btf_mpx_video_ops = {
3248774bed9SLaurent Pinchart 	.s_std = sony_btf_mpx_s_std,
3258774bed9SLaurent Pinchart };
3268774bed9SLaurent Pinchart 
327c7c54a98SHans Verkuil static const struct v4l2_subdev_ops sony_btf_mpx_ops = {
328c7c54a98SHans Verkuil 	.tuner = &sony_btf_mpx_tuner_ops,
3298774bed9SLaurent Pinchart 	.video = &sony_btf_mpx_video_ops,
330c7c54a98SHans Verkuil };
331c7c54a98SHans Verkuil 
332c7c54a98SHans Verkuil /* --------------------------------------------------------------------------*/
333c7c54a98SHans Verkuil 
sony_btf_mpx_probe(struct i2c_client * client)334a22e9128SUwe Kleine-König static int sony_btf_mpx_probe(struct i2c_client *client)
335c7c54a98SHans Verkuil {
336c7c54a98SHans Verkuil 	struct sony_btf_mpx *t;
337c7c54a98SHans Verkuil 	struct v4l2_subdev *sd;
338c7c54a98SHans Verkuil 
339c7c54a98SHans Verkuil 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
340c7c54a98SHans Verkuil 		return -ENODEV;
341c7c54a98SHans Verkuil 
342c7c54a98SHans Verkuil 	v4l_info(client, "chip found @ 0x%x (%s)\n",
343c7c54a98SHans Verkuil 			client->addr << 1, client->adapter->name);
344c7c54a98SHans Verkuil 
345c02b211dSLaurent Pinchart 	t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL);
346c7c54a98SHans Verkuil 	if (t == NULL)
347c7c54a98SHans Verkuil 		return -ENOMEM;
348c7c54a98SHans Verkuil 
349c7c54a98SHans Verkuil 	sd = &t->sd;
350c7c54a98SHans Verkuil 	v4l2_i2c_subdev_init(sd, client, &sony_btf_mpx_ops);
351c7c54a98SHans Verkuil 
352c7c54a98SHans Verkuil 	/* Initialize sony_btf_mpx */
353c7c54a98SHans Verkuil 	t->mpxmode = 0;
354c7c54a98SHans Verkuil 	t->audmode = V4L2_TUNER_MODE_STEREO;
355c7c54a98SHans Verkuil 
356c7c54a98SHans Verkuil 	return 0;
357c7c54a98SHans Verkuil }
358c7c54a98SHans Verkuil 
sony_btf_mpx_remove(struct i2c_client * client)359ed5c2f5fSUwe Kleine-König static void sony_btf_mpx_remove(struct i2c_client *client)
360c7c54a98SHans Verkuil {
361c7c54a98SHans Verkuil 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
362c7c54a98SHans Verkuil 
363c7c54a98SHans Verkuil 	v4l2_device_unregister_subdev(sd);
364c7c54a98SHans Verkuil }
365c7c54a98SHans Verkuil 
366c7c54a98SHans Verkuil /* ----------------------------------------------------------------------- */
367c7c54a98SHans Verkuil 
368c7c54a98SHans Verkuil static const struct i2c_device_id sony_btf_mpx_id[] = {
369c7c54a98SHans Verkuil 	{ "sony-btf-mpx", 0 },
370c7c54a98SHans Verkuil 	{ }
371c7c54a98SHans Verkuil };
372c7c54a98SHans Verkuil MODULE_DEVICE_TABLE(i2c, sony_btf_mpx_id);
373c7c54a98SHans Verkuil 
374c7c54a98SHans Verkuil static struct i2c_driver sony_btf_mpx_driver = {
375c7c54a98SHans Verkuil 	.driver = {
376c7c54a98SHans Verkuil 		.name	= "sony-btf-mpx",
377c7c54a98SHans Verkuil 	},
378*aaeb31c0SUwe Kleine-König 	.probe = sony_btf_mpx_probe,
379c7c54a98SHans Verkuil 	.remove = sony_btf_mpx_remove,
380c7c54a98SHans Verkuil 	.id_table = sony_btf_mpx_id,
381c7c54a98SHans Verkuil };
382c7c54a98SHans Verkuil module_i2c_driver(sony_btf_mpx_driver);
383