162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cx18 audio-related functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Derived from ivtv-audio.c 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "cx18-driver.h" 1162306a36Sopenharmony_ci#include "cx18-io.h" 1262306a36Sopenharmony_ci#include "cx18-cards.h" 1362306a36Sopenharmony_ci#include "cx18-audio.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define CX18_AUDIO_ENABLE 0xc72014 1662306a36Sopenharmony_ci#define CX18_AI1_MUX_MASK 0x30 1762306a36Sopenharmony_ci#define CX18_AI1_MUX_I2S1 0x00 1862306a36Sopenharmony_ci#define CX18_AI1_MUX_I2S2 0x10 1962306a36Sopenharmony_ci#define CX18_AI1_MUX_843_I2S 0x20 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Selects the audio input and output according to the current 2262306a36Sopenharmony_ci settings. */ 2362306a36Sopenharmony_ciint cx18_audio_set_io(struct cx18 *cx) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci const struct cx18_card_audio_input *in; 2662306a36Sopenharmony_ci u32 u, v; 2762306a36Sopenharmony_ci int err; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* Determine which input to use */ 3062306a36Sopenharmony_ci if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) 3162306a36Sopenharmony_ci in = &cx->card->radio_input; 3262306a36Sopenharmony_ci else 3362306a36Sopenharmony_ci in = &cx->card->audio_inputs[cx->audio_input]; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* handle muxer chips */ 3662306a36Sopenharmony_ci v4l2_subdev_call(cx->sd_extmux, audio, s_routing, 3762306a36Sopenharmony_ci (u32) in->muxer_input, 0, 0); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl, 4062306a36Sopenharmony_ci audio, s_routing, in->audio_input, 0, 0); 4162306a36Sopenharmony_ci if (err) 4262306a36Sopenharmony_ci return err; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* FIXME - this internal mux should be abstracted to a subdev */ 4562306a36Sopenharmony_ci u = cx18_read_reg(cx, CX18_AUDIO_ENABLE); 4662306a36Sopenharmony_ci v = u & ~CX18_AI1_MUX_MASK; 4762306a36Sopenharmony_ci switch (in->audio_input) { 4862306a36Sopenharmony_ci case CX18_AV_AUDIO_SERIAL1: 4962306a36Sopenharmony_ci v |= CX18_AI1_MUX_I2S1; 5062306a36Sopenharmony_ci break; 5162306a36Sopenharmony_ci case CX18_AV_AUDIO_SERIAL2: 5262306a36Sopenharmony_ci v |= CX18_AI1_MUX_I2S2; 5362306a36Sopenharmony_ci break; 5462306a36Sopenharmony_ci default: 5562306a36Sopenharmony_ci v |= CX18_AI1_MUX_843_I2S; 5662306a36Sopenharmony_ci break; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci if (v == u) { 5962306a36Sopenharmony_ci /* force a toggle of some AI1 MUX control bits */ 6062306a36Sopenharmony_ci u &= ~CX18_AI1_MUX_MASK; 6162306a36Sopenharmony_ci switch (in->audio_input) { 6262306a36Sopenharmony_ci case CX18_AV_AUDIO_SERIAL1: 6362306a36Sopenharmony_ci u |= CX18_AI1_MUX_843_I2S; 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci case CX18_AV_AUDIO_SERIAL2: 6662306a36Sopenharmony_ci u |= CX18_AI1_MUX_843_I2S; 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci default: 6962306a36Sopenharmony_ci u |= CX18_AI1_MUX_I2S1; 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE, 7362306a36Sopenharmony_ci u, CX18_AI1_MUX_MASK); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, 7662306a36Sopenharmony_ci v, CX18_AI1_MUX_MASK); 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 79