diff options
Diffstat (limited to 'drivers/media/i2c/tda7432.c')
-rw-r--r-- | drivers/media/i2c/tda7432.c | 276 |
1 files changed, 110 insertions, 166 deletions
diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index f7707e65761e..28b5121881f5 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c | |||
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | #include <media/v4l2-device.h> | 36 | #include <media/v4l2-device.h> |
37 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
38 | #include <media/v4l2-ctrls.h> | ||
38 | #include <media/i2c-addr.h> | 39 | #include <media/i2c-addr.h> |
39 | 40 | ||
40 | #ifndef VIDEO_AUDIO_BALANCE | 41 | #ifndef VIDEO_AUDIO_BALANCE |
@@ -60,13 +61,17 @@ MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default | |||
60 | 61 | ||
61 | struct tda7432 { | 62 | struct tda7432 { |
62 | struct v4l2_subdev sd; | 63 | struct v4l2_subdev sd; |
63 | int addr; | 64 | struct v4l2_ctrl_handler hdl; |
64 | int input; | 65 | struct { |
65 | int volume; | 66 | /* bass/treble cluster */ |
66 | int muted; | 67 | struct v4l2_ctrl *bass; |
67 | int bass, treble; | 68 | struct v4l2_ctrl *treble; |
68 | int lf, lr, rf, rr; | 69 | }; |
69 | int loud; | 70 | struct { |
71 | /* mute/balance cluster */ | ||
72 | struct v4l2_ctrl *mute; | ||
73 | struct v4l2_ctrl *balance; | ||
74 | }; | ||
70 | }; | 75 | }; |
71 | 76 | ||
72 | static inline struct tda7432 *to_state(struct v4l2_subdev *sd) | 77 | static inline struct tda7432 *to_state(struct v4l2_subdev *sd) |
@@ -74,6 +79,11 @@ static inline struct tda7432 *to_state(struct v4l2_subdev *sd) | |||
74 | return container_of(sd, struct tda7432, sd); | 79 | return container_of(sd, struct tda7432, sd); |
75 | } | 80 | } |
76 | 81 | ||
82 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
83 | { | ||
84 | return &container_of(ctrl->handler, struct tda7432, hdl)->sd; | ||
85 | } | ||
86 | |||
77 | /* The TDA7432 is made by STS-Thompson | 87 | /* The TDA7432 is made by STS-Thompson |
78 | * http://www.st.com | 88 | * http://www.st.com |
79 | * http://us.st.com/stonline/books/pdf/docs/4056.pdf | 89 | * http://us.st.com/stonline/books/pdf/docs/4056.pdf |
@@ -227,24 +237,22 @@ static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val) | |||
227 | static int tda7432_set(struct v4l2_subdev *sd) | 237 | static int tda7432_set(struct v4l2_subdev *sd) |
228 | { | 238 | { |
229 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 239 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
230 | struct tda7432 *t = to_state(sd); | ||
231 | unsigned char buf[16]; | 240 | unsigned char buf[16]; |
232 | 241 | ||
233 | v4l2_dbg(1, debug, sd, | ||
234 | "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", | ||
235 | t->input, t->volume, t->bass, t->treble, t->lf, t->lr, | ||
236 | t->rf, t->rr, t->loud); | ||
237 | buf[0] = TDA7432_IN; | 242 | buf[0] = TDA7432_IN; |
238 | buf[1] = t->input; | 243 | buf[1] = TDA7432_STEREO_IN | /* Main (stereo) input */ |
239 | buf[2] = t->volume; | 244 | TDA7432_BASS_SYM | /* Symmetric bass cut */ |
240 | buf[3] = t->bass; | 245 | TDA7432_BASS_NORM; /* Normal bass range */ |
241 | buf[4] = t->treble; | 246 | buf[2] = 0x3b; |
242 | buf[5] = t->lf; | 247 | if (loudness) /* Turn loudness on? */ |
243 | buf[6] = t->lr; | 248 | buf[2] |= TDA7432_LD_ON; |
244 | buf[7] = t->rf; | 249 | buf[3] = TDA7432_TREBLE_0DB | (TDA7432_BASS_0DB << 4); |
245 | buf[8] = t->rr; | 250 | buf[4] = TDA7432_ATTEN_0DB; |
246 | buf[9] = t->loud; | 251 | buf[5] = TDA7432_ATTEN_0DB; |
247 | if (10 != i2c_master_send(client, buf, 10)) { | 252 | buf[6] = TDA7432_ATTEN_0DB; |
253 | buf[7] = TDA7432_ATTEN_0DB; | ||
254 | buf[8] = loudness; | ||
255 | if (9 != i2c_master_send(client, buf, 9)) { | ||
248 | v4l2_err(sd, "I/O error, trying tda7432_set\n"); | 256 | v4l2_err(sd, "I/O error, trying tda7432_set\n"); |
249 | return -1; | 257 | return -1; |
250 | } | 258 | } |
@@ -252,174 +260,86 @@ static int tda7432_set(struct v4l2_subdev *sd) | |||
252 | return 0; | 260 | return 0; |
253 | } | 261 | } |
254 | 262 | ||
255 | static void do_tda7432_init(struct v4l2_subdev *sd) | 263 | static int tda7432_log_status(struct v4l2_subdev *sd) |
256 | { | ||
257 | struct tda7432 *t = to_state(sd); | ||
258 | |||
259 | v4l2_dbg(2, debug, sd, "In tda7432_init\n"); | ||
260 | |||
261 | t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ | ||
262 | TDA7432_BASS_SYM | /* Symmetric bass cut */ | ||
263 | TDA7432_BASS_NORM; /* Normal bass range */ | ||
264 | t->volume = 0x3b ; /* -27dB Volume */ | ||
265 | if (loudness) /* Turn loudness on? */ | ||
266 | t->volume |= TDA7432_LD_ON; | ||
267 | t->muted = 1; | ||
268 | t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ | ||
269 | t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ | ||
270 | t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ | ||
271 | t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ | ||
272 | t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ | ||
273 | t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ | ||
274 | t->loud = loudness; /* insmod parameter */ | ||
275 | |||
276 | tda7432_set(sd); | ||
277 | } | ||
278 | |||
279 | static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
280 | { | 264 | { |
281 | struct tda7432 *t = to_state(sd); | 265 | struct tda7432 *state = to_state(sd); |
282 | 266 | ||
283 | switch (ctrl->id) { | 267 | v4l2_ctrl_handler_log_status(&state->hdl, sd->name); |
284 | case V4L2_CID_AUDIO_MUTE: | 268 | return 0; |
285 | ctrl->value=t->muted; | ||
286 | return 0; | ||
287 | case V4L2_CID_AUDIO_VOLUME: | ||
288 | if (!maxvol){ /* max +20db */ | ||
289 | ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630; | ||
290 | } else { /* max 0db */ | ||
291 | ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829; | ||
292 | } | ||
293 | return 0; | ||
294 | case V4L2_CID_AUDIO_BALANCE: | ||
295 | { | ||
296 | if ( (t->lf) < (t->rf) ) | ||
297 | /* right is attenuated, balance shifted left */ | ||
298 | ctrl->value = (32768 - 1057*(t->rf)); | ||
299 | else | ||
300 | /* left is attenuated, balance shifted right */ | ||
301 | ctrl->value = (32768 + 1057*(t->lf)); | ||
302 | return 0; | ||
303 | } | ||
304 | case V4L2_CID_AUDIO_BASS: | ||
305 | { | ||
306 | /* Bass/treble 4 bits each */ | ||
307 | int bass=t->bass; | ||
308 | if(bass >= 0x8) | ||
309 | bass = ~(bass - 0x8) & 0xf; | ||
310 | ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass); | ||
311 | return 0; | ||
312 | } | ||
313 | case V4L2_CID_AUDIO_TREBLE: | ||
314 | { | ||
315 | int treble=t->treble; | ||
316 | if(treble >= 0x8) | ||
317 | treble = ~(treble - 0x8) & 0xf; | ||
318 | ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble); | ||
319 | return 0; | ||
320 | } | ||
321 | } | ||
322 | return -EINVAL; | ||
323 | } | 269 | } |
324 | 270 | ||
325 | static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 271 | static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl) |
326 | { | 272 | { |
273 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
327 | struct tda7432 *t = to_state(sd); | 274 | struct tda7432 *t = to_state(sd); |
275 | u8 bass, treble, volume; | ||
276 | u8 lf, lr, rf, rr; | ||
328 | 277 | ||
329 | switch (ctrl->id) { | 278 | switch (ctrl->id) { |
330 | case V4L2_CID_AUDIO_MUTE: | 279 | case V4L2_CID_AUDIO_MUTE: |
331 | t->muted=ctrl->value; | 280 | if (t->balance->val < 0) { |
332 | break; | ||
333 | case V4L2_CID_AUDIO_VOLUME: | ||
334 | if(!maxvol){ /* max +20db */ | ||
335 | t->volume = 0x6f - ((ctrl->value)/630); | ||
336 | } else { /* max 0db */ | ||
337 | t->volume = 0x6f - ((ctrl->value)/829); | ||
338 | } | ||
339 | if (loudness) /* Turn on the loudness bit */ | ||
340 | t->volume |= TDA7432_LD_ON; | ||
341 | |||
342 | tda7432_write(sd, TDA7432_VL, t->volume); | ||
343 | return 0; | ||
344 | case V4L2_CID_AUDIO_BALANCE: | ||
345 | if (ctrl->value < 32768) { | ||
346 | /* shifted to left, attenuate right */ | 281 | /* shifted to left, attenuate right */ |
347 | t->rr = (32768 - ctrl->value)/1057; | 282 | rr = rf = -t->balance->val; |
348 | t->rf = t->rr; | 283 | lr = lf = TDA7432_ATTEN_0DB; |
349 | t->lr = TDA7432_ATTEN_0DB; | 284 | } else if (t->balance->val > 0) { |
350 | t->lf = TDA7432_ATTEN_0DB; | ||
351 | } else if(ctrl->value > 32769) { | ||
352 | /* shifted to right, attenuate left */ | 285 | /* shifted to right, attenuate left */ |
353 | t->lf = (ctrl->value - 32768)/1057; | 286 | rr = rf = TDA7432_ATTEN_0DB; |
354 | t->lr = t->lf; | 287 | lr = lf = t->balance->val; |
355 | t->rr = TDA7432_ATTEN_0DB; | ||
356 | t->rf = TDA7432_ATTEN_0DB; | ||
357 | } else { | 288 | } else { |
358 | /* centered */ | 289 | /* centered */ |
359 | t->rr = TDA7432_ATTEN_0DB; | 290 | rr = rf = TDA7432_ATTEN_0DB; |
360 | t->rf = TDA7432_ATTEN_0DB; | 291 | lr = lf = TDA7432_ATTEN_0DB; |
361 | t->lf = TDA7432_ATTEN_0DB; | ||
362 | t->lr = TDA7432_ATTEN_0DB; | ||
363 | } | 292 | } |
364 | break; | 293 | if (t->mute->val) { |
365 | case V4L2_CID_AUDIO_BASS: | 294 | lf |= TDA7432_MUTE; |
366 | t->bass = ctrl->value >> 12; | 295 | lr |= TDA7432_MUTE; |
367 | if(t->bass>= 0x8) | 296 | lf |= TDA7432_MUTE; |
368 | t->bass = (~t->bass & 0xf) + 0x8 ; | 297 | rr |= TDA7432_MUTE; |
369 | 298 | } | |
370 | tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble); | 299 | /* Mute & update balance*/ |
300 | tda7432_write(sd, TDA7432_LF, lf); | ||
301 | tda7432_write(sd, TDA7432_LR, lr); | ||
302 | tda7432_write(sd, TDA7432_RF, rf); | ||
303 | tda7432_write(sd, TDA7432_RR, rr); | ||
371 | return 0; | 304 | return 0; |
372 | case V4L2_CID_AUDIO_TREBLE: | 305 | case V4L2_CID_AUDIO_VOLUME: |
373 | t->treble= ctrl->value >> 12; | 306 | volume = 0x6f - ctrl->val; |
374 | if(t->treble>= 0x8) | 307 | if (loudness) /* Turn on the loudness bit */ |
375 | t->treble = (~t->treble & 0xf) + 0x8 ; | 308 | volume |= TDA7432_LD_ON; |
376 | 309 | ||
377 | tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble); | 310 | tda7432_write(sd, TDA7432_VL, volume); |
378 | return 0; | 311 | return 0; |
379 | default: | ||
380 | return -EINVAL; | ||
381 | } | ||
382 | |||
383 | /* Used for both mute and balance changes */ | ||
384 | if (t->muted) | ||
385 | { | ||
386 | /* Mute & update balance*/ | ||
387 | tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE); | ||
388 | tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE); | ||
389 | tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE); | ||
390 | tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE); | ||
391 | } else { | ||
392 | tda7432_write(sd, TDA7432_LF, t->lf); | ||
393 | tda7432_write(sd, TDA7432_LR, t->lr); | ||
394 | tda7432_write(sd, TDA7432_RF, t->rf); | ||
395 | tda7432_write(sd, TDA7432_RR, t->rr); | ||
396 | } | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | ||
401 | { | ||
402 | switch (qc->id) { | ||
403 | case V4L2_CID_AUDIO_VOLUME: | ||
404 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); | ||
405 | case V4L2_CID_AUDIO_MUTE: | ||
406 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
407 | case V4L2_CID_AUDIO_BALANCE: | ||
408 | case V4L2_CID_AUDIO_BASS: | 312 | case V4L2_CID_AUDIO_BASS: |
409 | case V4L2_CID_AUDIO_TREBLE: | 313 | bass = t->bass->val; |
410 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); | 314 | treble = t->treble->val; |
315 | if (bass >= 0x8) | ||
316 | bass = 14 - (bass - 8); | ||
317 | if (treble >= 0x8) | ||
318 | treble = 14 - (treble - 8); | ||
319 | |||
320 | tda7432_write(sd, TDA7432_TN, 0x10 | (bass << 4) | treble); | ||
321 | return 0; | ||
411 | } | 322 | } |
412 | return -EINVAL; | 323 | return -EINVAL; |
413 | } | 324 | } |
414 | 325 | ||
415 | /* ----------------------------------------------------------------------- */ | 326 | /* ----------------------------------------------------------------------- */ |
416 | 327 | ||
417 | static const struct v4l2_subdev_core_ops tda7432_core_ops = { | 328 | static const struct v4l2_ctrl_ops tda7432_ctrl_ops = { |
418 | .queryctrl = tda7432_queryctrl, | ||
419 | .g_ctrl = tda7432_g_ctrl, | ||
420 | .s_ctrl = tda7432_s_ctrl, | 329 | .s_ctrl = tda7432_s_ctrl, |
421 | }; | 330 | }; |
422 | 331 | ||
332 | static const struct v4l2_subdev_core_ops tda7432_core_ops = { | ||
333 | .log_status = tda7432_log_status, | ||
334 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
335 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
336 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
337 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
338 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
339 | .queryctrl = v4l2_subdev_queryctrl, | ||
340 | .querymenu = v4l2_subdev_querymenu, | ||
341 | }; | ||
342 | |||
423 | static const struct v4l2_subdev_ops tda7432_ops = { | 343 | static const struct v4l2_subdev_ops tda7432_ops = { |
424 | .core = &tda7432_core_ops, | 344 | .core = &tda7432_core_ops, |
425 | }; | 345 | }; |
@@ -444,6 +364,28 @@ static int tda7432_probe(struct i2c_client *client, | |||
444 | return -ENOMEM; | 364 | return -ENOMEM; |
445 | sd = &t->sd; | 365 | sd = &t->sd; |
446 | v4l2_i2c_subdev_init(sd, client, &tda7432_ops); | 366 | v4l2_i2c_subdev_init(sd, client, &tda7432_ops); |
367 | v4l2_ctrl_handler_init(&t->hdl, 5); | ||
368 | v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, | ||
369 | V4L2_CID_AUDIO_VOLUME, 0, maxvol ? 0x68 : 0x4f, 1, maxvol ? 0x5d : 0x47); | ||
370 | t->mute = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, | ||
371 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); | ||
372 | t->balance = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, | ||
373 | V4L2_CID_AUDIO_BALANCE, -31, 31, 1, 0); | ||
374 | t->bass = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, | ||
375 | V4L2_CID_AUDIO_BASS, 0, 14, 1, 7); | ||
376 | t->treble = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, | ||
377 | V4L2_CID_AUDIO_TREBLE, 0, 14, 1, 7); | ||
378 | sd->ctrl_handler = &t->hdl; | ||
379 | if (t->hdl.error) { | ||
380 | int err = t->hdl.error; | ||
381 | |||
382 | v4l2_ctrl_handler_free(&t->hdl); | ||
383 | kfree(t); | ||
384 | return err; | ||
385 | } | ||
386 | v4l2_ctrl_cluster(2, &t->bass); | ||
387 | v4l2_ctrl_cluster(2, &t->mute); | ||
388 | v4l2_ctrl_handler_setup(&t->hdl); | ||
447 | if (loudness < 0 || loudness > 15) { | 389 | if (loudness < 0 || loudness > 15) { |
448 | v4l2_warn(sd, "loudness parameter must be between 0 and 15\n"); | 390 | v4l2_warn(sd, "loudness parameter must be between 0 and 15\n"); |
449 | if (loudness < 0) | 391 | if (loudness < 0) |
@@ -452,17 +394,19 @@ static int tda7432_probe(struct i2c_client *client, | |||
452 | loudness = 15; | 394 | loudness = 15; |
453 | } | 395 | } |
454 | 396 | ||
455 | do_tda7432_init(sd); | 397 | tda7432_set(sd); |
456 | return 0; | 398 | return 0; |
457 | } | 399 | } |
458 | 400 | ||
459 | static int tda7432_remove(struct i2c_client *client) | 401 | static int tda7432_remove(struct i2c_client *client) |
460 | { | 402 | { |
461 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 403 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
404 | struct tda7432 *t = to_state(sd); | ||
462 | 405 | ||
463 | do_tda7432_init(sd); | 406 | tda7432_set(sd); |
464 | v4l2_device_unregister_subdev(sd); | 407 | v4l2_device_unregister_subdev(sd); |
465 | kfree(to_state(sd)); | 408 | v4l2_ctrl_handler_free(&t->hdl); |
409 | kfree(t); | ||
466 | return 0; | 410 | return 0; |
467 | } | 411 | } |
468 | 412 | ||