162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci    Audio/video-routing-related ivtv functions.
462306a36Sopenharmony_ci    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
562306a36Sopenharmony_ci    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "ivtv-driver.h"
1062306a36Sopenharmony_ci#include "ivtv-i2c.h"
1162306a36Sopenharmony_ci#include "ivtv-cards.h"
1262306a36Sopenharmony_ci#include "ivtv-gpio.h"
1362306a36Sopenharmony_ci#include "ivtv-routing.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <media/drv-intf/msp3400.h>
1662306a36Sopenharmony_ci#include <media/i2c/m52790.h>
1762306a36Sopenharmony_ci#include <media/i2c/upd64031a.h>
1862306a36Sopenharmony_ci#include <media/i2c/upd64083.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Selects the audio input and output according to the current
2162306a36Sopenharmony_ci   settings. */
2262306a36Sopenharmony_civoid ivtv_audio_set_io(struct ivtv *itv)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	const struct ivtv_card_audio_input *in;
2562306a36Sopenharmony_ci	u32 input, output = 0;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	/* Determine which input to use */
2862306a36Sopenharmony_ci	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
2962306a36Sopenharmony_ci		in = &itv->card->radio_input;
3062306a36Sopenharmony_ci	else
3162306a36Sopenharmony_ci		in = &itv->card->audio_inputs[itv->audio_input];
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	/* handle muxer chips */
3462306a36Sopenharmony_ci	input = in->muxer_input;
3562306a36Sopenharmony_ci	if (itv->card->hw_muxer & IVTV_HW_M52790)
3662306a36Sopenharmony_ci		output = M52790_OUT_STEREO;
3762306a36Sopenharmony_ci	v4l2_subdev_call(itv->sd_muxer, audio, s_routing,
3862306a36Sopenharmony_ci			input, output, 0);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	input = in->audio_input;
4162306a36Sopenharmony_ci	output = 0;
4262306a36Sopenharmony_ci	if (itv->card->hw_audio & IVTV_HW_MSP34XX)
4362306a36Sopenharmony_ci		output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
4462306a36Sopenharmony_ci	ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing,
4562306a36Sopenharmony_ci			input, output, 0);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Selects the video input and output according to the current
4962306a36Sopenharmony_ci   settings. */
5062306a36Sopenharmony_civoid ivtv_video_set_io(struct ivtv *itv)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	int inp = itv->active_input;
5362306a36Sopenharmony_ci	u32 input;
5462306a36Sopenharmony_ci	u32 type;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	v4l2_subdev_call(itv->sd_video, video, s_routing,
5762306a36Sopenharmony_ci		itv->card->video_inputs[inp].video_input, 0, 0);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	type = itv->card->video_inputs[inp].video_type;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (type == IVTV_CARD_INPUT_VID_TUNER) {
6262306a36Sopenharmony_ci		input = 0;  /* Tuner */
6362306a36Sopenharmony_ci	} else if (type < IVTV_CARD_INPUT_COMPOSITE1) {
6462306a36Sopenharmony_ci		input = 2;  /* S-Video */
6562306a36Sopenharmony_ci	} else {
6662306a36Sopenharmony_ci		input = 1;  /* Composite */
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (itv->card->hw_video & IVTV_HW_GPIO)
7062306a36Sopenharmony_ci		ivtv_call_hw(itv, IVTV_HW_GPIO, video, s_routing,
7162306a36Sopenharmony_ci				input, 0, 0);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (itv->card->hw_video & IVTV_HW_UPD64031A) {
7462306a36Sopenharmony_ci		if (type == IVTV_CARD_INPUT_VID_TUNER ||
7562306a36Sopenharmony_ci		    type >= IVTV_CARD_INPUT_COMPOSITE1) {
7662306a36Sopenharmony_ci			/* Composite: GR on, connect to 3DYCS */
7762306a36Sopenharmony_ci			input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE;
7862306a36Sopenharmony_ci		} else {
7962306a36Sopenharmony_ci			/* S-Video: GR bypassed, turn it off */
8062306a36Sopenharmony_ci			input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE;
8162306a36Sopenharmony_ci		}
8262306a36Sopenharmony_ci		input |= itv->card->gr_config;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		ivtv_call_hw(itv, IVTV_HW_UPD64031A, video, s_routing,
8562306a36Sopenharmony_ci				input, 0, 0);
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (itv->card->hw_video & IVTV_HW_UPD6408X) {
8962306a36Sopenharmony_ci		input = UPD64083_YCS_MODE;
9062306a36Sopenharmony_ci		if (type > IVTV_CARD_INPUT_VID_TUNER &&
9162306a36Sopenharmony_ci		    type < IVTV_CARD_INPUT_COMPOSITE1) {
9262306a36Sopenharmony_ci			/* S-Video uses YCNR mode and internal Y-ADC, the
9362306a36Sopenharmony_ci			   upd64031a is not used. */
9462306a36Sopenharmony_ci			input |= UPD64083_YCNR_MODE;
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci		else if (itv->card->hw_video & IVTV_HW_UPD64031A) {
9762306a36Sopenharmony_ci			/* Use upd64031a output for tuner and
9862306a36Sopenharmony_ci			   composite(CX23416GYC only) inputs */
9962306a36Sopenharmony_ci			if (type == IVTV_CARD_INPUT_VID_TUNER ||
10062306a36Sopenharmony_ci			    itv->card->type == IVTV_CARD_CX23416GYC) {
10162306a36Sopenharmony_ci				input |= UPD64083_EXT_Y_ADC;
10262306a36Sopenharmony_ci			}
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci		ivtv_call_hw(itv, IVTV_HW_UPD6408X, video, s_routing,
10562306a36Sopenharmony_ci				input, 0, 0);
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci}
108