<commit_before>/*
 * wm8753.c  --  WM8753 ALSA Soc Audio driver
 *
 * Copyright 2003 Wolfson Microelectronics PLC.
 * Author: <NAME> <<EMAIL>>
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 * Notes:
 *  The WM8753 is a low power, high quality stereo codec with integrated PCM
 *  codec designed for portable digital telephony applications.
 *
 * Dual DAI:-
 *
 * This driver support 2 DAI PCM's. This makes the default PCM available for
 * HiFi audio (e.g. MP3, ogg) playback/capture and the other PCM available for
 * voice.
 *
 * Please note that the voice PCM can be connected directly to a Bluetooth
 * codec or GSM modem and thus cannot be read or written to, although it is
 * available to be configured with snd_hw_params(), etc and kcontrols in the
 * normal alsa manner.
 *
 * Fast DAI switching:-
 *
 * The driver can now fast switch between the DAI configurations via a
 * an alsa kcontrol. This allows the PCM to remain open.
 *
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <asm/div64.h>

#include "wm8753.h"

static int caps_charge = 2000;
module_param(caps_charge, int, 0);
MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");

static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec,
		unsigned int fmt);
static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec,
		unsigned int fmt);

/*
 * wm8753 register cache
 * We can't read the WM8753 register space when we
 * are using 2 wire for device control, so we cache them instead.
 */
static const u16 wm8753_reg[] = {
	0x0000, 0x0008, 0x0000, 0x000a,
	0x000a, 0x0033, 0x0000, 0x0007,
	0x00ff, 0x00ff, 0x000f, 0x000f,
	0x007b, 0x0000, 0x0032, 0x0000,
	0x00c3, 0x00c3, 0x00c0, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0055, 0x0005, 0x0050, 0x0055,
	0x0050, 0x0055, 0x0050, 0x0055,
	0x0079, 0x0079, 0x0079, 0x0079,
	0x0079, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0097, 0x0097, 0x0000,
	0x0004, 0x0000, 0x0083, 0x0024,
	0x01ba, 0x0000, 0x0083, 0x0024,
	0x01ba, 0x0000, 0x0000, 0x0000
};

/* codec private data */
struct wm8753_priv {
	enum snd_soc_control_type control_type;
	unsigned int sysclk;
	unsigned int pcmclk;

	unsigned int voice_fmt;
	unsigned int hifi_fmt;

	int dai_func;
};

#define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0)

/*
 * WM8753 Controls
 */
static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"};
static const char *wm8753_base_filter[] =
	{"130Hz @ 48kHz", "200Hz @ 48kHz", "100Hz @ 16kHz", "400Hz @ 48kHz",
	"100Hz @ 8kHz", "200Hz @ 8kHz"};
static const char *wm8753_treble[] = {"8kHz", "4kHz"};
static const char *wm8753_alc_func[] = {"Off", "Right", "Left", "Stereo"};
static const char *wm8753_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"};
static const char *wm8753_3d_func[] = {"Capture", "Playback"};
static const char *wm8753_3d_uc[] = {"2.2kHz", "1.5kHz"};
static const char *wm8753_3d_lc[] = {"200Hz", "500Hz"};
static const char *wm8753_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"};
static const char *wm8753_mono_mix[] = {"Stereo", "Left", "Right", "Mono"};
static const char *wm8753_dac_phase[] = {"Non Inverted", "Inverted"};
static const char *wm8753_line_mix[] = {"Line 1 + 2", "Line 1 - 2",
	"Line 1", "Line 2"};
static const char *wm8753_mono_mux[] = {"Line Mix", "Rx Mix"};
static const char *wm8753_right_mux[] = {"Line 2", "Rx Mix"};
static const char *wm8753_left_mux[] = {"Line 1", "Rx Mix"};
static const char *wm8753_rxmsel[] = {"RXP - RXN", "RXP + RXN", "RXP", "RXN"};
static const char *wm8753_sidetone_mux[] = {"Left PGA", "Mic 1", "Mic 2",
	"Right PGA"};
static const char *wm8753_mono2_src[] = {"Inverted Mono 1", "Left", "Right",
	"Left + Right"};
static const char *wm8753_out3[] = {"VREF", "ROUT2", "Left + Right"};
static const char *wm8753_out4[] = {"VREF", "Capture ST", "LOUT2"};
static const char *wm8753_radcsel[] = {"PGA", "Line or RXP-RXN", "Sidetone"};
static const char *wm8753_ladcsel[] = {"PGA", "Line or RXP-RXN", "Line"};
static const char *wm8753_mono_adc[] = {"Stereo", "Analogue Mix Left",
	"Analogue Mix Right", "Digital Mono Mix"};
static const char *wm8753_adc_hp[] = {"3.4Hz @ 48kHz", "82Hz @ 16k",
	"82Hz @ 8kHz", "170Hz @ 8kHz"};
static const char *wm8753_adc_filter[] = {"HiFi", "Voice"};
static const char *wm8753_mic_sel[] = {"Mic 1", "Mic 2", "Mic 3"};
static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"};
static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC",
	"Channel Swap"};
static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"};

static const struct soc_enum wm8753_enum[] = {
SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base),
SOC_ENUM_SINGLE(WM8753_BASS, 4, 6, wm8753_base_filter),
SOC_ENUM_SINGLE(WM8753_TREBLE, 6, 2, wm8753_treble),
SOC_ENUM_SINGLE(WM8753_ALC1, 7, 4, wm8753_alc_func),
SOC_ENUM_SINGLE(WM8753_NGATE, 1, 2, wm8753_ng_type),
SOC_ENUM_SINGLE(WM8753_3D, 7, 2, wm8753_3d_func),
SOC_ENUM_SINGLE(WM8753_3D, 6, 2, wm8753_3d_uc),
SOC_ENUM_SINGLE(WM8753_3D, 5, 2, wm8753_3d_lc),
SOC_ENUM_SINGLE(WM8753_DAC, 1, 4, wm8753_deemp),
SOC_ENUM_SINGLE(WM8753_DAC, 4, 4, wm8753_mono_mix),
SOC_ENUM_SINGLE(WM8753_DAC, 6, 2, wm8753_dac_phase),
SOC_ENUM_SINGLE(WM8753_INCTL1, 3, 4, wm8753_line_mix),
SOC_ENUM_SINGLE(WM8753_INCTL1, 2, 2, wm8753_mono_mux),
SOC_ENUM_SINGLE(WM8753_INCTL1, 1, 2, wm8753_right_mux),
SOC_ENUM_SINGLE(WM8753_INCTL1, 0, 2, wm8753_left_mux),
SOC_ENUM_SINGLE(WM8753_INCTL2, 6, 4, wm8753_rxmsel),
SOC_ENUM_SINGLE(WM8753_INCTL2, 4, 4, wm8753_sidetone_mux),
SOC_ENUM_SINGLE(WM8753_OUTCTL, 7, 4, wm8753_mono2_src),
SOC_ENUM_SINGLE(WM8753_OUTCTL, 0, 3, wm8753_out3),
SOC_ENUM_SINGLE(WM8753_ADCTL2, 7, 3, wm8753_out4),
SOC_ENUM_SINGLE(WM8753_ADCIN, 2, 3, wm8753_radcsel),
SOC_ENUM_SINGLE(WM8753_ADCIN, 0, 3, wm8753_ladcsel),
SOC_ENUM_SINGLE(WM8753_ADCIN, 4, 4, wm8753_mono_adc),
SOC_ENUM_SINGLE(WM8753_ADC, 2, 4, wm8753_adc_hp),
SOC_ENUM_SINGLE(WM8753_ADC, 4, 2, wm8753_adc_filter),
SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel),
SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode),
SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel),
SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
};


static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);

	ucontrol->value.integer.value[0] = wm8753->dai_func;
	return 0;
}

static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
	u16 ioctl;

	if (codec->active)
		return -EBUSY;

	ioctl = snd_soc_read(codec, WM8753_IOCTL);

	wm8753->dai_func = ucontrol->value.integer.value[0];

	if (((ioctl >> 2) & 0x3) == wm8753->dai_func)
		return 1;

	ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2);
	snd_soc_write(codec, WM8753_IOCTL, ioctl);


	wm8753_hifi_write_dai_fmt(codec, wm8753->hifi_fmt);<commit_msg>ASoC: wm8753: Skip noop reconfiguration of DAI mode<commit_after>/*
 * wm8753.c  --  WM8753 ALSA Soc Audio driver
 *
 * Copyright 2003 Wolfson Microelectronics PLC.
 * Author: <NAME> <<EMAIL>>
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 * Notes:
 *  The WM8753 is a low power, high quality stereo codec with integrated PCM
 *  codec designed for portable digital telephony applications.
 *
 * Dual DAI:-
 *
 * This driver support 2 DAI PCM's. This makes the default PCM available for
 * HiFi audio (e.g. MP3, ogg) playback/capture and the other PCM available for
 * voice.
 *
 * Please note that the voice PCM can be connected directly to a Bluetooth
 * codec or GSM modem and thus cannot be read or written to, although it is
 * available to be configured with snd_hw_params(), etc and kcontrols in the
 * normal alsa manner.
 *
 * Fast DAI switching:-
 *
 * The driver can now fast switch between the DAI configurations via a
 * an alsa kcontrol. This allows the PCM to remain open.
 *
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <asm/div64.h>

#include "wm8753.h"

static int caps_charge = 2000;
module_param(caps_charge, int, 0);
MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");

static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec,
		unsigned int fmt);
static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec,
		unsigned int fmt);

/*
 * wm8753 register cache
 * We can't read the WM8753 register space when we
 * are using 2 wire for device control, so we cache them instead.
 */
static const u16 wm8753_reg[] = {
	0x0000, 0x0008, 0x0000, 0x000a,
	0x000a, 0x0033, 0x0000, 0x0007,
	0x00ff, 0x00ff, 0x000f, 0x000f,
	0x007b, 0x0000, 0x0032, 0x0000,
	0x00c3, 0x00c3, 0x00c0, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0055, 0x0005, 0x0050, 0x0055,
	0x0050, 0x0055, 0x0050, 0x0055,
	0x0079, 0x0079, 0x0079, 0x0079,
	0x0079, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0097, 0x0097, 0x0000,
	0x0004, 0x0000, 0x0083, 0x0024,
	0x01ba, 0x0000, 0x0083, 0x0024,
	0x01ba, 0x0000, 0x0000, 0x0000
};

/* codec private data */
struct wm8753_priv {
	enum snd_soc_control_type control_type;
	unsigned int sysclk;
	unsigned int pcmclk;

	unsigned int voice_fmt;
	unsigned int hifi_fmt;

	int dai_func;
};

#define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0)

/*
 * WM8753 Controls
 */
static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"};
static const char *wm8753_base_filter[] =
	{"130Hz @ 48kHz", "200Hz @ 48kHz", "100Hz @ 16kHz", "400Hz @ 48kHz",
	"100Hz @ 8kHz", "200Hz @ 8kHz"};
static const char *wm8753_treble[] = {"8kHz", "4kHz"};
static const char *wm8753_alc_func[] = {"Off", "Right", "Left", "Stereo"};
static const char *wm8753_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"};
static const char *wm8753_3d_func[] = {"Capture", "Playback"};
static const char *wm8753_3d_uc[] = {"2.2kHz", "1.5kHz"};
static const char *wm8753_3d_lc[] = {"200Hz", "500Hz"};
static const char *wm8753_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"};
static const char *wm8753_mono_mix[] = {"Stereo", "Left", "Right", "Mono"};
static const char *wm8753_dac_phase[] = {"Non Inverted", "Inverted"};
static const char *wm8753_line_mix[] = {"Line 1 + 2", "Line 1 - 2",
	"Line 1", "Line 2"};
static const char *wm8753_mono_mux[] = {"Line Mix", "Rx Mix"};
static const char *wm8753_right_mux[] = {"Line 2", "Rx Mix"};
static const char *wm8753_left_mux[] = {"Line 1", "Rx Mix"};
static const char *wm8753_rxmsel[] = {"RXP - RXN", "RXP + RXN", "RXP", "RXN"};
static const char *wm8753_sidetone_mux[] = {"Left PGA", "Mic 1", "Mic 2",
	"Right PGA"};
static const char *wm8753_mono2_src[] = {"Inverted Mono 1", "Left", "Right",
	"Left + Right"};
static const char *wm8753_out3[] = {"VREF", "ROUT2", "Left + Right"};
static const char *wm8753_out4[] = {"VREF", "Capture ST", "LOUT2"};
static const char *wm8753_radcsel[] = {"PGA", "Line or RXP-RXN", "Sidetone"};
static const char *wm8753_ladcsel[] = {"PGA", "Line or RXP-RXN", "Line"};
static const char *wm8753_mono_adc[] = {"Stereo", "Analogue Mix Left",
	"Analogue Mix Right", "Digital Mono Mix"};
static const char *wm8753_adc_hp[] = {"3.4Hz @ 48kHz", "82Hz @ 16k",
	"82Hz @ 8kHz", "170Hz @ 8kHz"};
static const char *wm8753_adc_filter[] = {"HiFi", "Voice"};
static const char *wm8753_mic_sel[] = {"Mic 1", "Mic 2", "Mic 3"};
static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"};
static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC",
	"Channel Swap"};
static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"};

static const struct soc_enum wm8753_enum[] = {
SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base),
SOC_ENUM_SINGLE(WM8753_BASS, 4, 6, wm8753_base_filter),
SOC_ENUM_SINGLE(WM8753_TREBLE, 6, 2, wm8753_treble),
SOC_ENUM_SINGLE(WM8753_ALC1, 7, 4, wm8753_alc_func),
SOC_ENUM_SINGLE(WM8753_NGATE, 1, 2, wm8753_ng_type),
SOC_ENUM_SINGLE(WM8753_3D, 7, 2, wm8753_3d_func),
SOC_ENUM_SINGLE(WM8753_3D, 6, 2, wm8753_3d_uc),
SOC_ENUM_SINGLE(WM8753_3D, 5, 2, wm8753_3d_lc),
SOC_ENUM_SINGLE(WM8753_DAC, 1, 4, wm8753_deemp),
SOC_ENUM_SINGLE(WM8753_DAC, 4, 4, wm8753_mono_mix),
SOC_ENUM_SINGLE(WM8753_DAC, 6, 2, wm8753_dac_phase),
SOC_ENUM_SINGLE(WM8753_INCTL1, 3, 4, wm8753_line_mix),
SOC_ENUM_SINGLE(WM8753_INCTL1, 2, 2, wm8753_mono_mux),
SOC_ENUM_SINGLE(WM8753_INCTL1, 1, 2, wm8753_right_mux),
SOC_ENUM_SINGLE(WM8753_INCTL1, 0, 2, wm8753_left_mux),
SOC_ENUM_SINGLE(WM8753_INCTL2, 6, 4, wm8753_rxmsel),
SOC_ENUM_SINGLE(WM8753_INCTL2, 4, 4, wm8753_sidetone_mux),
SOC_ENUM_SINGLE(WM8753_OUTCTL, 7, 4, wm8753_mono2_src),
SOC_ENUM_SINGLE(WM8753_OUTCTL, 0, 3, wm8753_out3),
SOC_ENUM_SINGLE(WM8753_ADCTL2, 7, 3, wm8753_out4),
SOC_ENUM_SINGLE(WM8753_ADCIN, 2, 3, wm8753_radcsel),
SOC_ENUM_SINGLE(WM8753_ADCIN, 0, 3, wm8753_ladcsel),
SOC_ENUM_SINGLE(WM8753_ADCIN, 4, 4, wm8753_mono_adc),
SOC_ENUM_SINGLE(WM8753_ADC, 2, 4, wm8753_adc_hp),
SOC_ENUM_SINGLE(WM8753_ADC, 4, 2, wm8753_adc_filter),
SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel),
SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode),
SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel),
SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
};


static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);

	ucontrol->value.integer.value[0] = wm8753->dai_func;
	return 0;
}

static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
	struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
	u16 ioctl;

	if (wm8753->dai_func == ucontrol->value.integer.value[0])
		return 0;

	if (codec->active)
		return -EBUSY;

	ioctl = snd_soc_read(codec, WM8753_IOCTL);

	wm8753->dai_func = ucontrol->value.integer.value[0];

	if (((ioctl >> 2) & 0x3) == wm8753->dai_func)
		return 1;

	ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2);
	snd_soc_write(codec, WM8753_IOCTL, ioctl);


	wm8753_hifi_write_dai_fmt(codec, wm8753->hifi_fmt);
{'fraction_non_alphanumeric': 0.13645765998707174, 'fraction_numerical': 0.12540400775694893, 'mean_word_length': 5.738240418118467, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4505877', 'n_tokens_mistral': 7747, 'n_tokens_neox': 6570, 'n_words': 1635}