1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/i2c.h>
21#include <linux/videodev2.h>
22#include <media/tuner.h>
23#include <media/v4l2-common.h>
24#include <media/v4l2-ioctl.h>
25#include <media/v4l2-device.h>
26#include <linux/slab.h>
27
28MODULE_DESCRIPTION("sony-btf-mpx driver");
29MODULE_LICENSE("GPL v2");
30
31static int debug;
32module_param(debug, int, 0644);
33MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on\n");
34
35
36
37
38
39
40
41
42
43
44
45static int force_mpx_mode = -1;
46module_param(force_mpx_mode, int, 0644);
47
48struct sony_btf_mpx {
49 struct v4l2_subdev sd;
50 int mpxmode;
51 u32 audmode;
52};
53
54static inline struct sony_btf_mpx *to_state(struct v4l2_subdev *sd)
55{
56 return container_of(sd, struct sony_btf_mpx, sd);
57}
58
59static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
60{
61 u8 buffer[5];
62 struct i2c_msg msg;
63
64 buffer[0] = dev;
65 buffer[1] = addr >> 8;
66 buffer[2] = addr & 0xff;
67 buffer[3] = val >> 8;
68 buffer[4] = val & 0xff;
69 msg.addr = client->addr;
70 msg.flags = 0;
71 msg.len = 5;
72 msg.buf = buffer;
73 i2c_transfer(client->adapter, &msg, 1);
74 return 0;
75}
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128static const struct {
129 enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
130 u16 modus;
131 u16 source;
132 u16 acb;
133 u16 fm_prescale;
134 u16 nicam_prescale;
135 u16 scart_prescale;
136 u16 system;
137 u16 volume;
138} mpx_audio_modes[] = {
139 { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
140 0x5000, 0x0000, 0x0001, 0x7500 },
141 { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
142 0x5000, 0x0000, 0x0003, 0x7500 },
143 { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
144 0x5000, 0x0000, 0x0003, 0x7500 },
145 { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
146 0x5000, 0x0000, 0x0008, 0x7500 },
147 { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
148 0x7900, 0x0000, 0x000A, 0x7500 },
149 { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
150 0x7900, 0x0000, 0x000A, 0x7500 },
151 { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
152 0x5000, 0x0000, 0x0004, 0x7500 },
153 { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
154 0x5000, 0x0000, 0x0004, 0x7500 },
155 { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
156 0x5000, 0x0000, 0x0005, 0x7500 },
157 { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
158 0x5000, 0x0000, 0x0007, 0x7500 },
159 { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
160 0x5000, 0x0000, 0x000B, 0x7500 },
161 { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03,
162 0x5000, 0x2200, 0x0009, 0x7500 },
163 { AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03,
164 0x5000, 0x0000, 0x0009, 0x7500 },
165};
166
167#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes)
168
169static int mpx_setup(struct sony_btf_mpx *t)
170{
171 struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
172 u16 source = 0;
173 u8 buffer[3];
174 struct i2c_msg msg;
175 int mode = t->mpxmode;
176
177
178 buffer[0] = 0x00;
179 buffer[1] = 0x80;
180 buffer[2] = 0x00;
181 msg.addr = client->addr;
182 msg.flags = 0;
183 msg.len = 3;
184 msg.buf = buffer;
185 i2c_transfer(client->adapter, &msg, 1);
186 buffer[1] = 0x00;
187 i2c_transfer(client->adapter, &msg, 1);
188
189 if (t->audmode != V4L2_TUNER_MODE_MONO)
190 mode++;
191
192 if (mpx_audio_modes[mode].audio_mode != AUD_MONO) {
193 switch (t->audmode) {
194 case V4L2_TUNER_MODE_MONO:
195 switch (mpx_audio_modes[mode].audio_mode) {
196 case AUD_A2:
197 source = mpx_audio_modes[mode].source;
198 break;
199 case AUD_NICAM:
200 source = 0x0000;
201 break;
202 case AUD_NICAM_L:
203 source = 0x0200;
204 break;
205 default:
206 break;
207 }
208 break;
209 case V4L2_TUNER_MODE_STEREO:
210 source = mpx_audio_modes[mode].source;
211 break;
212 case V4L2_TUNER_MODE_LANG1:
213 source = 0x0300;
214 break;
215 case V4L2_TUNER_MODE_LANG2:
216 source = 0x0400;
217 break;
218 }
219 source |= mpx_audio_modes[mode].source & 0x00ff;
220 } else
221 source = mpx_audio_modes[mode].source;
222
223 mpx_write(client, 0x10, 0x0030, mpx_audio_modes[mode].modus);
224 mpx_write(client, 0x12, 0x0008, source);
225 mpx_write(client, 0x12, 0x0013, mpx_audio_modes[mode].acb);
226 mpx_write(client, 0x12, 0x000e,
227 mpx_audio_modes[mode].fm_prescale);
228 mpx_write(client, 0x12, 0x0010,
229 mpx_audio_modes[mode].nicam_prescale);
230 mpx_write(client, 0x12, 0x000d,
231 mpx_audio_modes[mode].scart_prescale);
232 mpx_write(client, 0x10, 0x0020, mpx_audio_modes[mode].system);
233 mpx_write(client, 0x12, 0x0000, mpx_audio_modes[mode].volume);
234 if (mpx_audio_modes[mode].audio_mode == AUD_A2)
235 mpx_write(client, 0x10, 0x0022,
236 t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
237
238#ifdef MPX_DEBUG
239 {
240 u8 buf1[3], buf2[2];
241 struct i2c_msg msgs[2];
242
243 v4l2_info(client,
244 "MPX registers: %04x %04x %04x %04x %04x %04x %04x %04x\n",
245 mpx_audio_modes[mode].modus,
246 source,
247 mpx_audio_modes[mode].acb,
248 mpx_audio_modes[mode].fm_prescale,
249 mpx_audio_modes[mode].nicam_prescale,
250 mpx_audio_modes[mode].scart_prescale,
251 mpx_audio_modes[mode].system,
252 mpx_audio_modes[mode].volume);
253 buf1[0] = 0x11;
254 buf1[1] = 0x00;
255 buf1[2] = 0x7e;
256 msgs[0].addr = client->addr;
257 msgs[0].flags = 0;
258 msgs[0].len = 3;
259 msgs[0].buf = buf1;
260 msgs[1].addr = client->addr;
261 msgs[1].flags = I2C_M_RD;
262 msgs[1].len = 2;
263 msgs[1].buf = buf2;
264 i2c_transfer(client->adapter, msgs, 2);
265 v4l2_info(client, "MPX system: %02x%02x\n",
266 buf2[0], buf2[1]);
267 buf1[0] = 0x11;
268 buf1[1] = 0x02;
269 buf1[2] = 0x00;
270 i2c_transfer(client->adapter, msgs, 2);
271 v4l2_info(client, "MPX status: %02x%02x\n",
272 buf2[0], buf2[1]);
273 }
274#endif
275 return 0;
276}
277
278
279static int sony_btf_mpx_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
280{
281 struct sony_btf_mpx *t = to_state(sd);
282 int default_mpx_mode = 0;
283
284 if (std & V4L2_STD_PAL_BG)
285 default_mpx_mode = 1;
286 else if (std & V4L2_STD_PAL_I)
287 default_mpx_mode = 4;
288 else if (std & V4L2_STD_PAL_DK)
289 default_mpx_mode = 6;
290 else if (std & V4L2_STD_SECAM_L)
291 default_mpx_mode = 11;
292
293 if (default_mpx_mode != t->mpxmode) {
294 t->mpxmode = default_mpx_mode;
295 mpx_setup(t);
296 }
297 return 0;
298}
299
300static int sony_btf_mpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
301{
302 struct sony_btf_mpx *t = to_state(sd);
303
304 vt->capability = V4L2_TUNER_CAP_NORM |
305 V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
306 V4L2_TUNER_CAP_LANG2;
307 vt->rxsubchans = V4L2_TUNER_SUB_MONO |
308 V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
309 V4L2_TUNER_SUB_LANG2;
310 vt->audmode = t->audmode;
311 return 0;
312}
313
314static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
315{
316 struct sony_btf_mpx *t = to_state(sd);
317
318 if (vt->type != V4L2_TUNER_ANALOG_TV)
319 return -EINVAL;
320
321 if (vt->audmode != t->audmode) {
322 t->audmode = vt->audmode;
323 mpx_setup(t);
324 }
325 return 0;
326}
327
328
329
330static const struct v4l2_subdev_core_ops sony_btf_mpx_core_ops = {
331 .s_std = sony_btf_mpx_s_std,
332};
333
334static const struct v4l2_subdev_tuner_ops sony_btf_mpx_tuner_ops = {
335 .s_tuner = sony_btf_mpx_s_tuner,
336 .g_tuner = sony_btf_mpx_g_tuner,
337};
338
339static const struct v4l2_subdev_ops sony_btf_mpx_ops = {
340 .core = &sony_btf_mpx_core_ops,
341 .tuner = &sony_btf_mpx_tuner_ops,
342};
343
344
345
346static int sony_btf_mpx_probe(struct i2c_client *client,
347 const struct i2c_device_id *id)
348{
349 struct sony_btf_mpx *t;
350 struct v4l2_subdev *sd;
351
352 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
353 return -ENODEV;
354
355 v4l_info(client, "chip found @ 0x%x (%s)\n",
356 client->addr << 1, client->adapter->name);
357
358 t = kzalloc(sizeof(struct sony_btf_mpx), GFP_KERNEL);
359 if (t == NULL)
360 return -ENOMEM;
361
362 sd = &t->sd;
363 v4l2_i2c_subdev_init(sd, client, &sony_btf_mpx_ops);
364
365
366 t->mpxmode = 0;
367 t->audmode = V4L2_TUNER_MODE_STEREO;
368
369 return 0;
370}
371
372static int sony_btf_mpx_remove(struct i2c_client *client)
373{
374 struct v4l2_subdev *sd = i2c_get_clientdata(client);
375
376 v4l2_device_unregister_subdev(sd);
377 kfree(to_state(sd));
378
379 return 0;
380}
381
382
383
384static const struct i2c_device_id sony_btf_mpx_id[] = {
385 { "sony-btf-mpx", 0 },
386 { }
387};
388MODULE_DEVICE_TABLE(i2c, sony_btf_mpx_id);
389
390static struct i2c_driver sony_btf_mpx_driver = {
391 .driver = {
392 .owner = THIS_MODULE,
393 .name = "sony-btf-mpx",
394 },
395 .probe = sony_btf_mpx_probe,
396 .remove = sony_btf_mpx_remove,
397 .id_table = sony_btf_mpx_id,
398};
399module_i2c_driver(sony_btf_mpx_driver);
400