18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * cx18 audio-related functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Derived from ivtv-audio.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "cx18-driver.h" 118c2ecf20Sopenharmony_ci#include "cx18-io.h" 128c2ecf20Sopenharmony_ci#include "cx18-cards.h" 138c2ecf20Sopenharmony_ci#include "cx18-audio.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define CX18_AUDIO_ENABLE 0xc72014 168c2ecf20Sopenharmony_ci#define CX18_AI1_MUX_MASK 0x30 178c2ecf20Sopenharmony_ci#define CX18_AI1_MUX_I2S1 0x00 188c2ecf20Sopenharmony_ci#define CX18_AI1_MUX_I2S2 0x10 198c2ecf20Sopenharmony_ci#define CX18_AI1_MUX_843_I2S 0x20 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Selects the audio input and output according to the current 228c2ecf20Sopenharmony_ci settings. */ 238c2ecf20Sopenharmony_ciint cx18_audio_set_io(struct cx18 *cx) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci const struct cx18_card_audio_input *in; 268c2ecf20Sopenharmony_ci u32 u, v; 278c2ecf20Sopenharmony_ci int err; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* Determine which input to use */ 308c2ecf20Sopenharmony_ci if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) 318c2ecf20Sopenharmony_ci in = &cx->card->radio_input; 328c2ecf20Sopenharmony_ci else 338c2ecf20Sopenharmony_ci in = &cx->card->audio_inputs[cx->audio_input]; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* handle muxer chips */ 368c2ecf20Sopenharmony_ci v4l2_subdev_call(cx->sd_extmux, audio, s_routing, 378c2ecf20Sopenharmony_ci (u32) in->muxer_input, 0, 0); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl, 408c2ecf20Sopenharmony_ci audio, s_routing, in->audio_input, 0, 0); 418c2ecf20Sopenharmony_ci if (err) 428c2ecf20Sopenharmony_ci return err; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* FIXME - this internal mux should be abstracted to a subdev */ 458c2ecf20Sopenharmony_ci u = cx18_read_reg(cx, CX18_AUDIO_ENABLE); 468c2ecf20Sopenharmony_ci v = u & ~CX18_AI1_MUX_MASK; 478c2ecf20Sopenharmony_ci switch (in->audio_input) { 488c2ecf20Sopenharmony_ci case CX18_AV_AUDIO_SERIAL1: 498c2ecf20Sopenharmony_ci v |= CX18_AI1_MUX_I2S1; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci case CX18_AV_AUDIO_SERIAL2: 528c2ecf20Sopenharmony_ci v |= CX18_AI1_MUX_I2S2; 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci default: 558c2ecf20Sopenharmony_ci v |= CX18_AI1_MUX_843_I2S; 568c2ecf20Sopenharmony_ci break; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci if (v == u) { 598c2ecf20Sopenharmony_ci /* force a toggle of some AI1 MUX control bits */ 608c2ecf20Sopenharmony_ci u &= ~CX18_AI1_MUX_MASK; 618c2ecf20Sopenharmony_ci switch (in->audio_input) { 628c2ecf20Sopenharmony_ci case CX18_AV_AUDIO_SERIAL1: 638c2ecf20Sopenharmony_ci u |= CX18_AI1_MUX_843_I2S; 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case CX18_AV_AUDIO_SERIAL2: 668c2ecf20Sopenharmony_ci u |= CX18_AI1_MUX_843_I2S; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci default: 698c2ecf20Sopenharmony_ci u |= CX18_AI1_MUX_I2S1; 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE, 738c2ecf20Sopenharmony_ci u, CX18_AI1_MUX_MASK); 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, 768c2ecf20Sopenharmony_ci v, CX18_AI1_MUX_MASK); 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci} 79