--- a/linux/drivers/media/video/wm8775.c Wed Nov 19 15:39:21 2008 +0000
+++ b/linux/drivers/media/video/wm8775.c Wed Nov 19 15:40:34 2008 +0000
@@ -57,6 +57,8 @@
struct wm8775_state {
u8 input; /* Last selected input (0-0xf) */
u8 muted;
+ u16 volume;
+ u16 balance;
};
static int wm8775_write(struct i2c_client *client, int reg, u16 val)
@@ -76,6 +78,55 @@
return -1;
}
+static void wm8775_set_audio(struct i2c_client *client)
+{
+ struct wm8775_state *state = i2c_get_clientdata(client);
+ u8 vol_l, vol_r;
+
+ wm8775_write(client, R21, 0x0c0);
+ if (state->muted)
+ return;
+
+ /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
+ vol_l = ((min(65536 - state->balance, 32768) * state->volume) / 32768) >> 8;
+ vol_r = ((min(state->balance, (u16)32768) * state->volume) / 32768) >> 8;
+
+ wm8775_write(client, R14, vol_l);
+ wm8775_write(client, R15, vol_r);
+ wm8775_write(client, R21, 0x100 + state->input);
+}
+
+static struct v4l2_queryctrl wm8775_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 0xCF00,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }, {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }, {
+ .id = V4L2_CID_AUDIO_BALANCE,
+ .name = "Balance",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535/100,
+ .default_value = 32768,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
{
struct wm8775_state *state = i2c_get_clientdata(client);
@@ -99,38 +150,69 @@
return -EINVAL;
}
state->input = route->input;
- if (state->muted)
- break;
- wm8775_write(client, R21, 0x0c0);
- wm8775_write(client, R14, 0x1d4);
- wm8775_write(client, R15, 0x1d4);
- wm8775_write(client, R21, 0x100 + state->input);
+ wm8775_set_audio(client);
break;
case VIDIOC_G_CTRL:
- if (ctrl->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- ctrl->value = state->muted;
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = state->muted;
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = state->volume;
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = state->balance;
+ break;
+
+ default:
+ return -EINVAL;
+ }
break;
case VIDIOC_S_CTRL:
- if (ctrl->id != V4L2_CID_AUDIO_MUTE)
- return -EINVAL;
- state->muted = ctrl->value;
- wm8775_write(client, R21, 0x0c0);
- wm8775_write(client, R14, 0x1d4);
- wm8775_write(client, R15, 0x1d4);
- if (!state->muted)
- wm8775_write(client, R21, 0x100 + state->input);
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ state->muted = ctrl->value;
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ state->volume = ctrl->value;
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ state->balance = ctrl->value;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ wm8775_set_audio(client);
break;
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wm8775_qctrl); i++)
+ if (qc->id && qc->id == wm8775_qctrl[i].id) {
+ memcpy(qc, &wm8775_qctrl[i], sizeof(*qc));
+ return 0;
+ }
+ return -EINVAL;
+ }
+
case VIDIOC_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client,
arg, V4L2_IDENT_WM8775, 0);
case VIDIOC_LOG_STATUS:
- v4l_info(client, "Input: %d%s\n", state->input,
- state->muted ? " (muted)" : "");
+ v4l_info(client, "Volume: %04x%s Balance: %04x Input: %d\n",
+ state->volume, state->muted ? " (muted)" : "",
+ state->balance, state->input);
break;
case VIDIOC_S_FREQUENCY:
@@ -138,10 +220,7 @@
sound the first time I tune from static to a valid channel.
It's difficult to reproduce and is almost certainly related
to the zero cross detect circuit. */
- wm8775_write(client, R21, 0x0c0);
- wm8775_write(client, R14, 0x1d4);
- wm8775_write(client, R15, 0x1d4);
- wm8775_write(client, R21, 0x100 + state->input);
+ wm8775_set_audio(client);
break;
default:
@@ -176,6 +255,8 @@
return -ENOMEM;
state->input = 2;
state->muted = 0;
+ state->volume = 0xCF00;
+ state->balance = 0x8000;
i2c_set_clientdata(client, state);
/* Initialize wm8775 */
@@ -190,23 +271,9 @@
wm8775_write(client, R12, 0x102);
/* Powered up */
wm8775_write(client, R13, 0x000);
- /* ADC gain +2.5dB, enable zero cross */
- wm8775_write(client, R14, 0x1d4);
- /* ADC gain +2.5dB, enable zero cross */
- wm8775_write(client, R15, 0x1d4);
- /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
- wm8775_write(client, R16, 0x1bf);
- /* Enable gain control, use zero cross detection,
- ALC hold time 42.6 ms */
- wm8775_write(client, R17, 0x185);
- /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
- wm8775_write(client, R18, 0x0a2);
- /* Enable noise gate, threshold -72dBfs */
- wm8775_write(client, R19, 0x005);
- /* Transient window 4ms, lower PGA gain limit -1dB */
- wm8775_write(client, R20, 0x07a);
- /* LRBOTH = 1, use input 2. */
- wm8775_write(client, R21, 0x102);
+ /* set volume/mute */
+ wm8775_set_audio(client);
+
return 0;
}