19722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls/*
29722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  ALSA mixer controls for the
39722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  ALSA interface to cx18 PCM capture streams
49722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *
56afdeaf865b729287e02aafc61d8d013b89996efAndy Walls *  Copyright (C) 2009  Andy Walls <awalls@md.metrocast.net>
69722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *
79722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  This program is free software; you can redistribute it and/or modify
89722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  it under the terms of the GNU General Public License as published by
99722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  the Free Software Foundation; either version 2 of the License, or
109722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  (at your option) any later version.
119722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *
129722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  This program is distributed in the hope that it will be useful,
139722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  but WITHOUT ANY WARRANTY; without even the implied warranty of
149722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
159722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  GNU General Public License for more details.
169722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *
179722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  You should have received a copy of the GNU General Public License
189722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  along with this program; if not, write to the Free Software
199722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
209722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *  02111-1307  USA
219722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls */
229722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
239722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <linux/init.h>
249722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <linux/kernel.h>
259722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <linux/device.h>
269722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <linux/spinlock.h>
279722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <linux/videodev2.h>
289722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
299722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <media/v4l2-device.h>
309722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
319722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <sound/core.h>
329722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <sound/control.h>
339722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include <sound/tlv.h>
349722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
359722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include "cx18-alsa.h"
369722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls#include "cx18-driver.h"
379722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
389722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls/*
399722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * Note the cx18-av-core volume scale is funny, due to the alignment of the
409722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * scale with another chip's range:
419722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls *
429722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * v4l2_control value	/512	indicated dB	actual dB	reg 0x8d4
439722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * 0x0000 - 0x01ff	  0	-119		-96		228
449722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * 0x0200 - 0x02ff	  1	-118		-96		228
459722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * ...
469722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * 0x2c00 - 0x2dff	 22	 -97		-96		228
479722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * 0x2e00 - 0x2fff	 23	 -96		-96		228
489722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * 0x3000 - 0x31ff	 24	 -95		-95		226
499722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * ...
509722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * 0xee00 - 0xefff	119	   0		  0		 36
519722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * ...
529722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls * 0xfe00 - 0xffff	127	  +8		 +8		 20
539722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls */
549722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Wallsstatic inline int dB_to_cx18_av_vol(int dB)
559722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls{
569722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	if (dB < -96)
579722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		dB = -96;
589722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	else if (dB > 8)
599722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		dB = 8;
609722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	return (dB + 119) << 9;
619722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls}
629722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
639722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Wallsstatic inline int cx18_av_vol_to_dB(int v)
649722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls{
659722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	if (v < (23 << 9))
669722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		v = (23 << 9);
679722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	else if (v > (127 << 9))
689722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		v = (127 << 9);
699722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	return (v >> 9) - 119;
709722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls}
719722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
729722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Wallsstatic int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol,
739722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls				      struct snd_ctl_elem_info *uinfo)
749722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls{
759722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
769722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	uinfo->count = 1;
779722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	/* We're already translating values, just keep this control in dB */
789722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	uinfo->value.integer.min  = -96;
794dae2f0f84374d4e7cd6c8d41385a7c250f0726dDevin Heitmueller	uinfo->value.integer.max  =   8;
809722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	uinfo->value.integer.step =   1;
819722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	return 0;
829722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls}
839722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
849722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Wallsstatic int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl,
859722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls				     struct snd_ctl_elem_value *uctl)
869722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls{
879722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
889722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
899722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	struct v4l2_control vctrl;
909722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	int ret;
919722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
929722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	vctrl.id = V4L2_CID_AUDIO_VOLUME;
939722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
949722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
9583695009a439b86c520f9001c80cc5a042c2d940Andy Walls	snd_cx18_lock(cxsc);
969722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl);
9783695009a439b86c520f9001c80cc5a042c2d940Andy Walls	snd_cx18_unlock(cxsc);
989722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
999722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	if (!ret)
1009722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value);
1019722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	return ret;
1029722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls}
1039722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1049722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Wallsstatic int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl,
1059722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls				     struct snd_ctl_elem_value *uctl)
1069722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls{
1079722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
1089722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
1099722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	struct v4l2_control vctrl;
1109722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	int ret;
1119722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1129722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	vctrl.id = V4L2_CID_AUDIO_VOLUME;
1139722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
1149722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
11583695009a439b86c520f9001c80cc5a042c2d940Andy Walls	snd_cx18_lock(cxsc);
1169722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1179722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	/* Fetch current state */
1189722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl);
1199722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1209722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	if (ret ||
1219722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	    (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) {
1229722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1239722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		/* Set, if needed */
1249722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
1259722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		ret = v4l2_subdev_call(cx->sd_av, core, s_ctrl, &vctrl);
1269722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		if (!ret)
1279722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls			ret = 1; /* Indicate control was changed w/o error */
1289722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	}
12983695009a439b86c520f9001c80cc5a042c2d940Andy Walls	snd_cx18_unlock(cxsc);
1309722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1319722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	return ret;
1329722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls}
1339722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1349722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1359722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls/* This is a bit of overkill, the slider is already in dB internally */
1369722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Wallsstatic DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0);
1379722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1389722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Wallsstatic struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = {
1399722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1409722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	.name = "Analog TV Capture Volume",
1419722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1429722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
1439722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	.info = snd_cx18_mixer_tv_volume_info,
1449722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	.get = snd_cx18_mixer_tv_volume_get,
1459722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	.put = snd_cx18_mixer_tv_volume_put,
1469722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	.tlv.p = snd_cx18_mixer_tv_vol_db_scale
1479722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls};
1489722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1499722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls/* FIXME - add mute switch and balance, bass, treble sliders:
1509722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	V4L2_CID_AUDIO_MUTE
1519722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1529722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	V4L2_CID_AUDIO_BALANCE
1539722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1549722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	V4L2_CID_AUDIO_BASS
1559722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	V4L2_CID_AUDIO_TREBLE
1569722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls*/
1579722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1589722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls/* FIXME - add stereo, lang1, lang2, mono menu */
1599722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls/* FIXME - add CS5345 I2S volume for HVR-1600 */
1609722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1619722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Wallsint __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc)
1629722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls{
1639722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
1649722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	struct snd_card *sc = cxsc->sc;
1659722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	int ret;
1669722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1679722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername));
1689722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls
1699722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc));
1709722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	if (ret) {
1719722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls		CX18_ALSA_WARN("%s: failed to add %s control, err %d\n",
1729722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls				__func__, snd_cx18_mixer_tv_vol.name, ret);
1739722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	}
1749722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls	return ret;
1759722c8f95a5bd51a3d392cb2f125c8240b745c48Andy Walls}
176