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