1269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls/*
2269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  ALSA mixer controls for the
3269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  ALSA interface to ivtv PCM capture streams
4269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *
5269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  Copyright (C) 2009,2012  Andy Walls <awalls@md.metrocast.net>
6269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *
7269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  This program is free software; you can redistribute it and/or modify
8269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  it under the terms of the GNU General Public License as published by
9269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  the Free Software Foundation; either version 2 of the License, or
10269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  (at your option) any later version.
11269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *
12269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  This program is distributed in the hope that it will be useful,
13269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  GNU General Public License for more details.
16269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *
17269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  You should have received a copy of the GNU General Public License
18269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  along with this program; if not, write to the Free Software
19269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *  02111-1307  USA
21269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls */
22269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
23269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <linux/init.h>
24269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <linux/kernel.h>
25269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <linux/device.h>
26269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <linux/spinlock.h>
27269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <linux/videodev2.h>
28269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
29269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <media/v4l2-device.h>
30269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
31269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <sound/core.h>
32269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <sound/control.h>
33269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include <sound/tlv.h>
34269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
35269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include "ivtv-alsa.h"
36269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls#include "ivtv-driver.h"
37269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
38269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls/*
39269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * Note the cx25840-core volume scale is funny, due to the alignment of the
40269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * scale with another chip's range:
41269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls *
42269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * v4l2_control value	/512	indicated dB	actual dB	reg 0x8d4
43269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * 0x0000 - 0x01ff	  0	-119		-96		228
44269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * 0x0200 - 0x02ff	  1	-118		-96		228
45269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * ...
46269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * 0x2c00 - 0x2dff	 22	 -97		-96		228
47269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * 0x2e00 - 0x2fff	 23	 -96		-96		228
48269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * 0x3000 - 0x31ff	 24	 -95		-95		226
49269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * ...
50269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * 0xee00 - 0xefff	119	   0		  0		 36
51269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * ...
52269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls * 0xfe00 - 0xffff	127	  +8		 +8		 20
53269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls */
54269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Wallsstatic inline int dB_to_cx25840_vol(int dB)
55269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls{
56269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	if (dB < -96)
57269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		dB = -96;
58269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	else if (dB > 8)
59269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		dB = 8;
60269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	return (dB + 119) << 9;
61269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls}
62269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
63269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Wallsstatic inline int cx25840_vol_to_dB(int v)
64269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls{
65269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	if (v < (23 << 9))
66269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		v = (23 << 9);
67269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	else if (v > (127 << 9))
68269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		v = (127 << 9);
69269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	return (v >> 9) - 119;
70269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls}
71269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
72269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Wallsstatic int snd_ivtv_mixer_tv_vol_info(struct snd_kcontrol *kcontrol,
73269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls				      struct snd_ctl_elem_info *uinfo)
74269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls{
75269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
76269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	uinfo->count = 1;
77269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	/* We're already translating values, just keep this control in dB */
78269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	uinfo->value.integer.min  = -96;
79269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	uinfo->value.integer.max  =   8;
80269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	uinfo->value.integer.step =   1;
81269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	return 0;
82269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls}
83269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
84269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Wallsstatic int snd_ivtv_mixer_tv_vol_get(struct snd_kcontrol *kctl,
85269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls				     struct snd_ctl_elem_value *uctl)
86269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls{
87269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	struct snd_ivtv_card *itvsc = snd_kcontrol_chip(kctl);
88269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	struct ivtv *itv = to_ivtv(itvsc->v4l2_dev);
89269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	struct v4l2_control vctrl;
90269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	int ret;
91269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
92269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	vctrl.id = V4L2_CID_AUDIO_VOLUME;
93269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]);
94269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
95269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	snd_ivtv_lock(itvsc);
96269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	ret = v4l2_subdev_call(itv->sd_audio, core, g_ctrl, &vctrl);
97269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	snd_ivtv_unlock(itvsc);
98269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
99269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	if (!ret)
100269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		uctl->value.integer.value[0] = cx25840_vol_to_dB(vctrl.value);
101269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	return ret;
102269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls}
103269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
104269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Wallsstatic int snd_ivtv_mixer_tv_vol_put(struct snd_kcontrol *kctl,
105269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls				     struct snd_ctl_elem_value *uctl)
106269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls{
107269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	struct snd_ivtv_card *itvsc = snd_kcontrol_chip(kctl);
108269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	struct ivtv *itv = to_ivtv(itvsc->v4l2_dev);
109269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	struct v4l2_control vctrl;
110269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	int ret;
111269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
112269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	vctrl.id = V4L2_CID_AUDIO_VOLUME;
113269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]);
114269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
115269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	snd_ivtv_lock(itvsc);
116269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
117269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	/* Fetch current state */
118269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	ret = v4l2_subdev_call(itv->sd_audio, core, g_ctrl, &vctrl);
119269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
120269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	if (ret ||
121269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	    (cx25840_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) {
122269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
123269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		/* Set, if needed */
124269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]);
125269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		ret = v4l2_subdev_call(itv->sd_audio, core, s_ctrl, &vctrl);
126269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		if (!ret)
127269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls			ret = 1; /* Indicate control was changed w/o error */
128269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	}
129269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	snd_ivtv_unlock(itvsc);
130269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
131269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	return ret;
132269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls}
133269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
134269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
135269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls/* This is a bit of overkill, the slider is already in dB internally */
136269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Wallsstatic DECLARE_TLV_DB_SCALE(snd_ivtv_mixer_tv_vol_db_scale, -9600, 100, 0);
137269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
138269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Wallsstatic struct snd_kcontrol_new snd_ivtv_mixer_tv_vol __initdata = {
139269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
140269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	.name = "Analog TV Capture Volume",
141269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
142269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
143269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	.info = snd_ivtv_mixer_tv_volume_info,
144269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	.get = snd_ivtv_mixer_tv_volume_get,
145269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	.put = snd_ivtv_mixer_tv_volume_put,
146269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	.tlv.p = snd_ivtv_mixer_tv_vol_db_scale
147269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls};
148269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
149269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls/* FIXME - add mute switch and balance, bass, treble sliders:
150269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	V4L2_CID_AUDIO_MUTE
151269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
152269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	V4L2_CID_AUDIO_BALANCE
153269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
154269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	V4L2_CID_AUDIO_BASS
155269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	V4L2_CID_AUDIO_TREBLE
156269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls*/
157269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
158269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls/* FIXME - add stereo, lang1, lang2, mono menu */
159269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls/* FIXME - add I2S volume */
160269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
161269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Wallsint __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc)
162269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls{
163269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	struct v4l2_device *v4l2_dev = itvsc->v4l2_dev;
164269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	struct snd_card *sc = itvsc->sc;
165269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	int ret;
166269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
167269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	strlcpy(sc->mixername, "CX2341[56] Mixer", sizeof(sc->mixername));
168269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls
169269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	ret = snd_ctl_add(sc, snd_ctl_new1(snd_ivtv_mixer_tv_vol, itvsc));
170269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	if (ret) {
171269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls		IVTV_ALSA_WARN("%s: failed to add %s control, err %d\n",
172269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls			       __func__, snd_ivtv_mixer_tv_vol.name, ret);
173269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	}
174269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls	return ret;
175269c11fbac4f7b4ed58e77f3049b64b55a342234Andy Walls}
176