Merge remote-tracking branches 'asoc/topic/msm8916', 'asoc/topic/mtk', 'asoc/topic/nau8824', 'asoc/topic/nau8825' and 'asoc/topic/of-graph' into asoc-next
This commit is contained in:
commit
f459768c6c
|
@ -10,6 +10,8 @@ see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
|
||||||
Below are same as Simple-Card.
|
Below are same as Simple-Card.
|
||||||
|
|
||||||
- label
|
- label
|
||||||
|
- widgets
|
||||||
|
- routing
|
||||||
- dai-format
|
- dai-format
|
||||||
- frame-master
|
- frame-master
|
||||||
- bitclock-master
|
- bitclock-master
|
||||||
|
@ -24,6 +26,9 @@ Required properties:
|
||||||
- compatible : "audio-graph-card";
|
- compatible : "audio-graph-card";
|
||||||
- dais : list of CPU DAI port{s}
|
- dais : list of CPU DAI port{s}
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- pa-gpios: GPIO used to control external amplifier.
|
||||||
|
|
||||||
Example: Single DAI case
|
Example: Single DAI case
|
||||||
|
|
||||||
sound_card {
|
sound_card {
|
||||||
|
|
|
@ -90,9 +90,12 @@ Example 2. 2 CPU 1 Codec (Mixing)
|
||||||
...
|
...
|
||||||
|
|
||||||
port {
|
port {
|
||||||
codec_endpoint: endpoint {
|
codec_endpoint0: endpoint {
|
||||||
remote-endpoint = <&cpu_endpoint0>;
|
remote-endpoint = <&cpu_endpoint0>;
|
||||||
};
|
};
|
||||||
|
codec_endpoint1: endpoint {
|
||||||
|
remote-endpoint = <&cpu_endpoint1>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,7 +104,7 @@ Example 2. 2 CPU 1 Codec (Mixing)
|
||||||
ports {
|
ports {
|
||||||
cpu_port0: port {
|
cpu_port0: port {
|
||||||
cpu_endpoint0: endpoint {
|
cpu_endpoint0: endpoint {
|
||||||
remote-endpoint = <&codec_endpoint>;
|
remote-endpoint = <&codec_endpoint0>;
|
||||||
|
|
||||||
dai-format = "left_j";
|
dai-format = "left_j";
|
||||||
...
|
...
|
||||||
|
@ -109,6 +112,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
|
||||||
};
|
};
|
||||||
cpu_port1: port {
|
cpu_port1: port {
|
||||||
cpu_endpoint1: endpoint {
|
cpu_endpoint1: endpoint {
|
||||||
|
remote-endpoint = <&codec_endpoint1>;
|
||||||
|
|
||||||
dai-format = "left_j";
|
dai-format = "left_j";
|
||||||
...
|
...
|
||||||
};
|
};
|
||||||
|
|
|
@ -69,6 +69,8 @@ Optional properties:
|
||||||
- nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
|
- nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
|
||||||
- nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
|
- nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
|
||||||
|
|
||||||
|
- nuvoton,crosstalk-bypass: make crosstalk function bypass if set.
|
||||||
|
|
||||||
- clocks: list of phandle and clock specifier pairs according to common clock bindings for the
|
- clocks: list of phandle and clock specifier pairs according to common clock bindings for the
|
||||||
clocks described in clock-names
|
clocks described in clock-names
|
||||||
- clock-names: should include "mclk" for the MCLK master clock
|
- clock-names: should include "mclk" for the MCLK master clock
|
||||||
|
@ -96,6 +98,7 @@ Example:
|
||||||
nuvoton,short-key-debounce = <2>;
|
nuvoton,short-key-debounce = <2>;
|
||||||
nuvoton,jack-insert-debounce = <7>;
|
nuvoton,jack-insert-debounce = <7>;
|
||||||
nuvoton,jack-eject-debounce = <7>;
|
nuvoton,jack-eject-debounce = <7>;
|
||||||
|
nuvoton,crosstalk-bypass;
|
||||||
|
|
||||||
clock-names = "mclk";
|
clock-names = "mclk";
|
||||||
clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
|
clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;
|
||||||
|
|
|
@ -22,6 +22,11 @@ struct asoc_simple_dai {
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct asoc_simple_card_data {
|
||||||
|
u32 convert_rate;
|
||||||
|
u32 convert_channels;
|
||||||
|
};
|
||||||
|
|
||||||
int asoc_simple_card_parse_daifmt(struct device *dev,
|
int asoc_simple_card_parse_daifmt(struct device *dev,
|
||||||
struct device_node *node,
|
struct device_node *node,
|
||||||
struct device_node *codec,
|
struct device_node *codec,
|
||||||
|
@ -45,6 +50,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
|
||||||
struct device_node *dai_of_node,
|
struct device_node *dai_of_node,
|
||||||
struct asoc_simple_dai *simple_dai,
|
struct asoc_simple_dai *simple_dai,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
|
||||||
|
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai);
|
||||||
|
|
||||||
#define asoc_simple_card_parse_cpu(node, dai_link, \
|
#define asoc_simple_card_parse_cpu(node, dai_link, \
|
||||||
list_name, cells_name, is_single_link) \
|
list_name, cells_name, is_single_link) \
|
||||||
|
@ -73,6 +80,12 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep,
|
||||||
struct device_node **endpoint_np,
|
struct device_node **endpoint_np,
|
||||||
const char **dai_name);
|
const char **dai_name);
|
||||||
|
|
||||||
|
#define asoc_simple_card_of_parse_tdm(np, dai) \
|
||||||
|
snd_soc_of_parse_tdm_slot(np, &(dai)->tx_slot_mask, \
|
||||||
|
&(dai)->rx_slot_mask, \
|
||||||
|
&(dai)->slots, \
|
||||||
|
&(dai)->slot_width);
|
||||||
|
|
||||||
int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
|
int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
|
||||||
struct asoc_simple_dai *simple_dai);
|
struct asoc_simple_dai *simple_dai);
|
||||||
|
|
||||||
|
@ -82,4 +95,15 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
|
||||||
|
|
||||||
int asoc_simple_card_clean_reference(struct snd_soc_card *card);
|
int asoc_simple_card_clean_reference(struct snd_soc_card *card);
|
||||||
|
|
||||||
|
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
|
||||||
|
struct snd_pcm_hw_params *params);
|
||||||
|
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
|
||||||
|
struct asoc_simple_card_data *data);
|
||||||
|
|
||||||
|
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
|
||||||
|
char *prefix,
|
||||||
|
int optional);
|
||||||
|
int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
|
||||||
|
char *prefix);
|
||||||
|
|
||||||
#endif /* __SIMPLE_CARD_UTILS_H */
|
#endif /* __SIMPLE_CARD_UTILS_H */
|
||||||
|
|
|
@ -223,8 +223,8 @@ struct pm8916_wcd_analog_priv {
|
||||||
u16 codec_version;
|
u16 codec_version;
|
||||||
struct clk *mclk;
|
struct clk *mclk;
|
||||||
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
|
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
|
||||||
bool micbias1_cap_mode;
|
unsigned int micbias1_cap_mode;
|
||||||
bool micbias2_cap_mode;
|
unsigned int micbias2_cap_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
|
static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
|
||||||
|
@ -285,7 +285,7 @@ static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
|
||||||
|
|
||||||
static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec
|
static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec
|
||||||
*codec, int event,
|
*codec, int event,
|
||||||
int reg, u32 cap_mode)
|
int reg, unsigned int cap_mode)
|
||||||
{
|
{
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case SND_SOC_DAPM_POST_PMU:
|
case SND_SOC_DAPM_POST_PMU:
|
||||||
|
|
|
@ -1124,6 +1124,57 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nau8824_set_tdm_slot - configure DAI TDM.
|
||||||
|
* @dai: DAI
|
||||||
|
* @tx_mask: Bitmask representing active TX slots. Ex.
|
||||||
|
* 0xf for normal 4 channel TDM.
|
||||||
|
* 0xf0 for shifted 4 channel TDM
|
||||||
|
* @rx_mask: Bitmask [0:1] representing active DACR RX slots.
|
||||||
|
* Bitmask [2:3] representing active DACL RX slots.
|
||||||
|
* 00=CH0,01=CH1,10=CH2,11=CH3. Ex.
|
||||||
|
* 0xf for DACL/R selecting TDM CH3.
|
||||||
|
* 0xf0 for DACL/R selecting shifted TDM CH3.
|
||||||
|
* @slots: Number of slots in use.
|
||||||
|
* @slot_width: Width in bits for each slot.
|
||||||
|
*
|
||||||
|
* Configures a DAI for TDM operation. Only support 4 slots TDM.
|
||||||
|
*/
|
||||||
|
static int nau8824_set_tdm_slot(struct snd_soc_dai *dai,
|
||||||
|
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
|
struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
|
||||||
|
unsigned int tslot_l = 0, ctrl_val = 0;
|
||||||
|
|
||||||
|
if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)) ||
|
||||||
|
((rx_mask & 0xf0) && (rx_mask & 0xf)) ||
|
||||||
|
((rx_mask & 0xf0) && (tx_mask & 0xf)) ||
|
||||||
|
((rx_mask & 0xf) && (tx_mask & 0xf0)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ctrl_val |= (NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN);
|
||||||
|
if (tx_mask & 0xf0) {
|
||||||
|
tslot_l = 4 * slot_width;
|
||||||
|
ctrl_val |= (tx_mask >> 4);
|
||||||
|
} else {
|
||||||
|
ctrl_val |= tx_mask;
|
||||||
|
}
|
||||||
|
if (rx_mask & 0xf0)
|
||||||
|
ctrl_val |= ((rx_mask >> 4) << NAU8824_TDM_DACR_RX_SFT);
|
||||||
|
else
|
||||||
|
ctrl_val |= (rx_mask << NAU8824_TDM_DACR_RX_SFT);
|
||||||
|
|
||||||
|
regmap_update_bits(nau8824->regmap, NAU8824_REG_TDM_CTRL,
|
||||||
|
NAU8824_TDM_MODE | NAU8824_TDM_OFFSET_EN |
|
||||||
|
NAU8824_TDM_DACL_RX_MASK | NAU8824_TDM_DACR_RX_MASK |
|
||||||
|
NAU8824_TDM_TX_MASK, ctrl_val);
|
||||||
|
regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_LEFT_TIME_SLOT,
|
||||||
|
NAU8824_TSLOT_L_MASK, tslot_l);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nau8824_calc_fll_param - Calculate FLL parameters.
|
* nau8824_calc_fll_param - Calculate FLL parameters.
|
||||||
* @fll_in: external clock provided to codec.
|
* @fll_in: external clock provided to codec.
|
||||||
|
@ -1440,6 +1491,7 @@ static struct snd_soc_codec_driver nau8824_codec_driver = {
|
||||||
static const struct snd_soc_dai_ops nau8824_dai_ops = {
|
static const struct snd_soc_dai_ops nau8824_dai_ops = {
|
||||||
.hw_params = nau8824_hw_params,
|
.hw_params = nau8824_hw_params,
|
||||||
.set_fmt = nau8824_set_fmt,
|
.set_fmt = nau8824_set_fmt,
|
||||||
|
.set_tdm_slot = nau8824_set_tdm_slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NAU8824_RATES SNDRV_PCM_RATE_8000_192000
|
#define NAU8824_RATES SNDRV_PCM_RATE_8000_192000
|
||||||
|
|
|
@ -258,6 +258,18 @@
|
||||||
#define NAU8824_I2S_MS_SLAVE (0 << NAU8824_I2S_MS_SFT)
|
#define NAU8824_I2S_MS_SLAVE (0 << NAU8824_I2S_MS_SFT)
|
||||||
#define NAU8824_I2S_BLK_DIV_MASK 0x7
|
#define NAU8824_I2S_BLK_DIV_MASK 0x7
|
||||||
|
|
||||||
|
/* PORT0_LEFT_TIME_SLOT (0x1E) */
|
||||||
|
#define NAU8824_TSLOT_L_MASK 0x3ff
|
||||||
|
|
||||||
|
/* TDM_CTRL (0x20) */
|
||||||
|
#define NAU8824_TDM_MODE (0x1 << 15)
|
||||||
|
#define NAU8824_TDM_OFFSET_EN (0x1 << 14)
|
||||||
|
#define NAU8824_TDM_DACL_RX_SFT 6
|
||||||
|
#define NAU8824_TDM_DACL_RX_MASK (0x3 << NAU8824_TDM_DACL_RX_SFT)
|
||||||
|
#define NAU8824_TDM_DACR_RX_SFT 4
|
||||||
|
#define NAU8824_TDM_DACR_RX_MASK (0x3 << NAU8824_TDM_DACR_RX_SFT)
|
||||||
|
#define NAU8824_TDM_TX_MASK 0xf
|
||||||
|
|
||||||
/* ADC_FILTER_CTRL (0x24) */
|
/* ADC_FILTER_CTRL (0x24) */
|
||||||
#define NAU8824_ADC_SYNC_DOWN_MASK 0x3
|
#define NAU8824_ADC_SYNC_DOWN_MASK 0x3
|
||||||
#define NAU8824_ADC_SYNC_DOWN_32 0
|
#define NAU8824_ADC_SYNC_DOWN_32 0
|
||||||
|
|
|
@ -1612,7 +1612,6 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
|
||||||
snd_soc_dapm_sync(dapm);
|
snd_soc_dapm_sync(dapm);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
|
||||||
dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
|
dev_dbg(nau8825->dev, "CTIA (micgnd2) mic connected\n");
|
||||||
type = SND_JACK_HEADSET;
|
type = SND_JACK_HEADSET;
|
||||||
|
|
||||||
|
@ -1632,6 +1631,11 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
|
||||||
snd_soc_dapm_force_enable_pin(dapm, "SAR");
|
snd_soc_dapm_force_enable_pin(dapm, "SAR");
|
||||||
snd_soc_dapm_sync(dapm);
|
snd_soc_dapm_sync(dapm);
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
/* detect error case */
|
||||||
|
dev_err(nau8825->dev, "detection error; disable mic function\n");
|
||||||
|
type = SND_JACK_HEADPHONE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Leaving HPOL/R grounded after jack insert by default. They will be
|
/* Leaving HPOL/R grounded after jack insert by default. They will be
|
||||||
|
@ -1682,7 +1686,7 @@ static irqreturn_t nau8825_interrupt(int irq, void *data)
|
||||||
} else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) {
|
} else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) {
|
||||||
if (nau8825_is_jack_inserted(regmap)) {
|
if (nau8825_is_jack_inserted(regmap)) {
|
||||||
event |= nau8825_jack_insert(nau8825);
|
event |= nau8825_jack_insert(nau8825);
|
||||||
if (!nau8825->high_imped) {
|
if (!nau8825->xtalk_bypass && !nau8825->high_imped) {
|
||||||
/* Apply the cross talk suppression in the
|
/* Apply the cross talk suppression in the
|
||||||
* headset without high impedance.
|
* headset without high impedance.
|
||||||
*/
|
*/
|
||||||
|
@ -2328,6 +2332,13 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SND_SOC_BIAS_OFF:
|
case SND_SOC_BIAS_OFF:
|
||||||
|
/* Reset the configuration of jack type for detection */
|
||||||
|
/* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */
|
||||||
|
regmap_update_bits(nau8825->regmap, NAU8825_REG_MIC_BIAS,
|
||||||
|
NAU8825_MICBIAS_JKSLV | NAU8825_MICBIAS_JKR2, 0);
|
||||||
|
/* ground HPL/HPR, MICGRND1/2 */
|
||||||
|
regmap_update_bits(nau8825->regmap,
|
||||||
|
NAU8825_REG_HSD_CTRL, 0xf, 0xf);
|
||||||
/* Cancel and reset cross talk detection funciton */
|
/* Cancel and reset cross talk detection funciton */
|
||||||
nau8825_xtalk_cancel(nau8825);
|
nau8825_xtalk_cancel(nau8825);
|
||||||
/* Turn off all interruptions before system shutdown. Keep the
|
/* Turn off all interruptions before system shutdown. Keep the
|
||||||
|
@ -2351,6 +2362,10 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec)
|
||||||
|
|
||||||
disable_irq(nau8825->irq);
|
disable_irq(nau8825->irq);
|
||||||
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
|
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||||
|
/* Power down codec power; don't suppoet button wakeup */
|
||||||
|
snd_soc_dapm_disable_pin(nau8825->dapm, "SAR");
|
||||||
|
snd_soc_dapm_disable_pin(nau8825->dapm, "MICBIAS");
|
||||||
|
snd_soc_dapm_sync(nau8825->dapm);
|
||||||
regcache_cache_only(nau8825->regmap, true);
|
regcache_cache_only(nau8825->regmap, true);
|
||||||
regcache_mark_dirty(nau8825->regmap);
|
regcache_mark_dirty(nau8825->regmap);
|
||||||
|
|
||||||
|
@ -2425,10 +2440,13 @@ static void nau8825_print_device_properties(struct nau8825 *nau8825)
|
||||||
nau8825->jack_insert_debounce);
|
nau8825->jack_insert_debounce);
|
||||||
dev_dbg(dev, "jack-eject-debounce: %d\n",
|
dev_dbg(dev, "jack-eject-debounce: %d\n",
|
||||||
nau8825->jack_eject_debounce);
|
nau8825->jack_eject_debounce);
|
||||||
|
dev_dbg(dev, "crosstalk-bypass: %d\n",
|
||||||
|
nau8825->xtalk_bypass);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nau8825_read_device_properties(struct device *dev,
|
static int nau8825_read_device_properties(struct device *dev,
|
||||||
struct nau8825 *nau8825) {
|
struct nau8825 *nau8825) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
nau8825->jkdet_enable = device_property_read_bool(dev,
|
nau8825->jkdet_enable = device_property_read_bool(dev,
|
||||||
"nuvoton,jkdet-enable");
|
"nuvoton,jkdet-enable");
|
||||||
|
@ -2436,30 +2454,60 @@ static int nau8825_read_device_properties(struct device *dev,
|
||||||
"nuvoton,jkdet-pull-enable");
|
"nuvoton,jkdet-pull-enable");
|
||||||
nau8825->jkdet_pull_up = device_property_read_bool(dev,
|
nau8825->jkdet_pull_up = device_property_read_bool(dev,
|
||||||
"nuvoton,jkdet-pull-up");
|
"nuvoton,jkdet-pull-up");
|
||||||
device_property_read_u32(dev, "nuvoton,jkdet-polarity",
|
ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
|
||||||
&nau8825->jkdet_polarity);
|
&nau8825->jkdet_polarity);
|
||||||
device_property_read_u32(dev, "nuvoton,micbias-voltage",
|
if (ret)
|
||||||
|
nau8825->jkdet_polarity = 1;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,micbias-voltage",
|
||||||
&nau8825->micbias_voltage);
|
&nau8825->micbias_voltage);
|
||||||
device_property_read_u32(dev, "nuvoton,vref-impedance",
|
if (ret)
|
||||||
|
nau8825->micbias_voltage = 6;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,vref-impedance",
|
||||||
&nau8825->vref_impedance);
|
&nau8825->vref_impedance);
|
||||||
device_property_read_u32(dev, "nuvoton,sar-threshold-num",
|
if (ret)
|
||||||
|
nau8825->vref_impedance = 2;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,sar-threshold-num",
|
||||||
&nau8825->sar_threshold_num);
|
&nau8825->sar_threshold_num);
|
||||||
device_property_read_u32_array(dev, "nuvoton,sar-threshold",
|
if (ret)
|
||||||
|
nau8825->sar_threshold_num = 4;
|
||||||
|
ret = device_property_read_u32_array(dev, "nuvoton,sar-threshold",
|
||||||
nau8825->sar_threshold, nau8825->sar_threshold_num);
|
nau8825->sar_threshold, nau8825->sar_threshold_num);
|
||||||
device_property_read_u32(dev, "nuvoton,sar-hysteresis",
|
if (ret) {
|
||||||
|
nau8825->sar_threshold[0] = 0x08;
|
||||||
|
nau8825->sar_threshold[1] = 0x12;
|
||||||
|
nau8825->sar_threshold[2] = 0x26;
|
||||||
|
nau8825->sar_threshold[3] = 0x73;
|
||||||
|
}
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,sar-hysteresis",
|
||||||
&nau8825->sar_hysteresis);
|
&nau8825->sar_hysteresis);
|
||||||
device_property_read_u32(dev, "nuvoton,sar-voltage",
|
if (ret)
|
||||||
|
nau8825->sar_hysteresis = 0;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,sar-voltage",
|
||||||
&nau8825->sar_voltage);
|
&nau8825->sar_voltage);
|
||||||
device_property_read_u32(dev, "nuvoton,sar-compare-time",
|
if (ret)
|
||||||
|
nau8825->sar_voltage = 6;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,sar-compare-time",
|
||||||
&nau8825->sar_compare_time);
|
&nau8825->sar_compare_time);
|
||||||
device_property_read_u32(dev, "nuvoton,sar-sampling-time",
|
if (ret)
|
||||||
|
nau8825->sar_compare_time = 1;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,sar-sampling-time",
|
||||||
&nau8825->sar_sampling_time);
|
&nau8825->sar_sampling_time);
|
||||||
device_property_read_u32(dev, "nuvoton,short-key-debounce",
|
if (ret)
|
||||||
|
nau8825->sar_sampling_time = 1;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,short-key-debounce",
|
||||||
&nau8825->key_debounce);
|
&nau8825->key_debounce);
|
||||||
device_property_read_u32(dev, "nuvoton,jack-insert-debounce",
|
if (ret)
|
||||||
|
nau8825->key_debounce = 3;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,jack-insert-debounce",
|
||||||
&nau8825->jack_insert_debounce);
|
&nau8825->jack_insert_debounce);
|
||||||
device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
|
if (ret)
|
||||||
|
nau8825->jack_insert_debounce = 7;
|
||||||
|
ret = device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
|
||||||
&nau8825->jack_eject_debounce);
|
&nau8825->jack_eject_debounce);
|
||||||
|
if (ret)
|
||||||
|
nau8825->jack_eject_debounce = 0;
|
||||||
|
nau8825->xtalk_bypass = device_property_read_bool(dev,
|
||||||
|
"nuvoton,crosstalk-bypass");
|
||||||
|
|
||||||
nau8825->mclk = devm_clk_get(dev, "mclk");
|
nau8825->mclk = devm_clk_get(dev, "mclk");
|
||||||
if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
|
if (PTR_ERR(nau8825->mclk) == -EPROBE_DEFER) {
|
||||||
|
|
|
@ -476,6 +476,7 @@ struct nau8825 {
|
||||||
int xtalk_event_mask;
|
int xtalk_event_mask;
|
||||||
bool xtalk_protect;
|
bool xtalk_protect;
|
||||||
int imp_rms[NAU8825_XTALK_IMM];
|
int imp_rms[NAU8825_XTALK_IMM];
|
||||||
|
int xtalk_bypass;
|
||||||
};
|
};
|
||||||
|
|
||||||
int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
|
int nau8825_enable_jack_detect(struct snd_soc_codec *codec,
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
@ -30,6 +31,34 @@ struct graph_card_data {
|
||||||
struct asoc_simple_dai codec_dai;
|
struct asoc_simple_dai codec_dai;
|
||||||
} *dai_props;
|
} *dai_props;
|
||||||
struct snd_soc_dai_link *dai_link;
|
struct snd_soc_dai_link *dai_link;
|
||||||
|
struct gpio_desc *pa_gpio;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w,
|
||||||
|
struct snd_kcontrol *kcontrol,
|
||||||
|
int event)
|
||||||
|
{
|
||||||
|
struct snd_soc_dapm_context *dapm = w->dapm;
|
||||||
|
struct graph_card_data *priv = snd_soc_card_get_drvdata(dapm->card);
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case SND_SOC_DAPM_POST_PMU:
|
||||||
|
gpiod_set_value_cansleep(priv->pa_gpio, 1);
|
||||||
|
break;
|
||||||
|
case SND_SOC_DAPM_PRE_PMD:
|
||||||
|
gpiod_set_value_cansleep(priv->pa_gpio, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = {
|
||||||
|
SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM,
|
||||||
|
0, 0, NULL, 0, asoc_graph_card_outdrv_event,
|
||||||
|
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define graph_priv_to_card(priv) (&(priv)->snd_card)
|
#define graph_priv_to_card(priv) (&(priv)->snd_card)
|
||||||
|
@ -44,13 +73,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
|
||||||
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
|
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = clk_prepare_enable(dai_props->cpu_dai.clk);
|
ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = clk_prepare_enable(dai_props->codec_dai.clk);
|
ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
|
||||||
if (ret)
|
if (ret)
|
||||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -61,9 +90,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
|
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
|
||||||
|
|
||||||
clk_disable_unprepare(dai_props->codec_dai.clk);
|
asoc_simple_card_clk_disable(&dai_props->codec_dai);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct snd_soc_ops asoc_graph_card_ops = {
|
static struct snd_soc_ops asoc_graph_card_ops = {
|
||||||
|
@ -100,7 +129,6 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
|
||||||
struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
|
struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
|
||||||
struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
|
struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
|
||||||
struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
|
struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
|
||||||
struct snd_soc_card *card = graph_priv_to_card(priv);
|
|
||||||
struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL);
|
struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL);
|
||||||
struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
|
struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
|
||||||
struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
|
struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
|
||||||
|
@ -131,19 +159,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
ret = snd_soc_of_parse_tdm_slot(cpu_ep,
|
ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
|
||||||
&cpu_dai->tx_slot_mask,
|
|
||||||
&cpu_dai->rx_slot_mask,
|
|
||||||
&cpu_dai->slots,
|
|
||||||
&cpu_dai->slot_width);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
ret = snd_soc_of_parse_tdm_slot(codec_ep,
|
ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
|
||||||
&codec_dai->tx_slot_mask,
|
|
||||||
&codec_dai->rx_slot_mask,
|
|
||||||
&codec_dai->slots,
|
|
||||||
&codec_dai->slot_width);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
|
@ -170,7 +190,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
|
||||||
dai_link->init = asoc_graph_card_dai_init;
|
dai_link->init = asoc_graph_card_dai_init;
|
||||||
|
|
||||||
asoc_simple_card_canonicalize_cpu(dai_link,
|
asoc_simple_card_canonicalize_cpu(dai_link,
|
||||||
card->num_links == 1);
|
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
|
||||||
|
|
||||||
dai_link_of_err:
|
dai_link_of_err:
|
||||||
of_node_put(cpu_ep);
|
of_node_put(cpu_ep);
|
||||||
|
@ -189,8 +209,16 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
|
||||||
int rc, idx = 0;
|
int rc, idx = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = asoc_simple_card_of_parse_widgets(card, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = asoc_simple_card_of_parse_routing(card, NULL, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we need to consider "widgets", "routing", "mclk-fs" around here
|
* we need to consider "mclk-fs" around here
|
||||||
* see simple-card
|
* see simple-card
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -242,6 +270,13 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
|
||||||
if (!dai_props || !dai_link)
|
if (!dai_props || !dai_link)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(priv->pa_gpio)) {
|
||||||
|
ret = PTR_ERR(priv->pa_gpio);
|
||||||
|
dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
priv->dai_props = dai_props;
|
priv->dai_props = dai_props;
|
||||||
priv->dai_link = dai_link;
|
priv->dai_link = dai_link;
|
||||||
|
|
||||||
|
@ -251,6 +286,8 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
|
||||||
card->dev = dev;
|
card->dev = dev;
|
||||||
card->dai_link = dai_link;
|
card->dai_link = dai_link;
|
||||||
card->num_links = num;
|
card->num_links = num;
|
||||||
|
card->dapm_widgets = asoc_graph_card_dapm_widgets;
|
||||||
|
card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
|
||||||
|
|
||||||
ret = asoc_graph_card_parse_of(priv);
|
ret = asoc_graph_card_parse_of(priv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
|
@ -30,8 +30,7 @@ struct graph_card_data {
|
||||||
struct snd_soc_codec_conf codec_conf;
|
struct snd_soc_codec_conf codec_conf;
|
||||||
struct asoc_simple_dai *dai_props;
|
struct asoc_simple_dai *dai_props;
|
||||||
struct snd_soc_dai_link *dai_link;
|
struct snd_soc_dai_link *dai_link;
|
||||||
u32 convert_rate;
|
struct asoc_simple_card_data adata;
|
||||||
u32 convert_channels;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define graph_priv_to_card(priv) (&(priv)->snd_card)
|
#define graph_priv_to_card(priv) (&(priv)->snd_card)
|
||||||
|
@ -45,7 +44,7 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
|
||||||
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
|
struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
return clk_prepare_enable(dai_props->clk);
|
return asoc_simple_card_clk_enable(dai_props);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
|
static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
|
@ -54,7 +53,7 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
|
struct asoc_simple_dai *dai_props = graph_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
clk_disable_unprepare(dai_props->clk);
|
asoc_simple_card_clk_disable(dai_props);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct snd_soc_ops asoc_graph_card_ops = {
|
static struct snd_soc_ops asoc_graph_card_ops = {
|
||||||
|
@ -83,18 +82,8 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||||
struct snd_pcm_hw_params *params)
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
struct snd_interval *rate = hw_param_interval(params,
|
|
||||||
SNDRV_PCM_HW_PARAM_RATE);
|
|
||||||
struct snd_interval *channels = hw_param_interval(params,
|
|
||||||
SNDRV_PCM_HW_PARAM_CHANNELS);
|
|
||||||
|
|
||||||
if (priv->convert_rate)
|
asoc_simple_card_convert_fixup(&priv->adata, params);
|
||||||
rate->min =
|
|
||||||
rate->max = priv->convert_rate;
|
|
||||||
|
|
||||||
if (priv->convert_channels)
|
|
||||||
channels->min =
|
|
||||||
channels->max = priv->convert_channels;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -136,7 +125,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
|
||||||
|
|
||||||
/* card->num_links includes Codec */
|
/* card->num_links includes Codec */
|
||||||
asoc_simple_card_canonicalize_cpu(dai_link,
|
asoc_simple_card_canonicalize_cpu(dai_link,
|
||||||
(card->num_links - 1) == 1);
|
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
|
||||||
} else {
|
} else {
|
||||||
/* FE is dummy */
|
/* FE is dummy */
|
||||||
dai_link->cpu_of_node = NULL;
|
dai_link->cpu_of_node = NULL;
|
||||||
|
@ -167,11 +156,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
|
||||||
"prefix");
|
"prefix");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = snd_soc_of_parse_tdm_slot(ep,
|
ret = asoc_simple_card_of_parse_tdm(ep, dai_props);
|
||||||
&dai_props->tx_slot_mask,
|
|
||||||
&dai_props->rx_slot_mask,
|
|
||||||
&dai_props->slots,
|
|
||||||
&dai_props->slot_width);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -198,6 +183,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
|
||||||
struct device_node *cpu_ep;
|
struct device_node *cpu_ep;
|
||||||
struct device_node *codec_ep;
|
struct device_node *codec_ep;
|
||||||
struct device_node *rcpu_ep;
|
struct device_node *rcpu_ep;
|
||||||
|
struct device_node *codec_port;
|
||||||
|
struct device_node *codec_port_old;
|
||||||
unsigned int daifmt = 0;
|
unsigned int daifmt = 0;
|
||||||
int dai_idx, ret;
|
int dai_idx, ret;
|
||||||
int rc, codec;
|
int rc, codec;
|
||||||
|
@ -210,15 +197,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
|
||||||
* see simple-card
|
* see simple-card
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = snd_soc_of_parse_audio_routing(card, "routing");
|
ret = asoc_simple_card_of_parse_routing(card, NULL, 0);
|
||||||
if (ret)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* sampling rate convert */
|
asoc_simple_card_parse_convert(dev, NULL, &priv->adata);
|
||||||
of_property_read_u32(node, "convert-rate", &priv->convert_rate);
|
|
||||||
|
|
||||||
/* channels transfer */
|
|
||||||
of_property_read_u32(node, "convert-channels", &priv->convert_channels);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* it supports multi CPU, single CODEC only here
|
* it supports multi CPU, single CODEC only here
|
||||||
|
@ -254,6 +237,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
|
||||||
}
|
}
|
||||||
|
|
||||||
dai_idx = 0;
|
dai_idx = 0;
|
||||||
|
codec_port_old = NULL;
|
||||||
for (codec = 0; codec < 2; codec++) {
|
for (codec = 0; codec < 2; codec++) {
|
||||||
/*
|
/*
|
||||||
* To listup valid sounds continuously,
|
* To listup valid sounds continuously,
|
||||||
|
@ -264,15 +248,22 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
|
||||||
cpu_port = it.node;
|
cpu_port = it.node;
|
||||||
cpu_ep = of_get_next_child(cpu_port, NULL);
|
cpu_ep = of_get_next_child(cpu_port, NULL);
|
||||||
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
|
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
|
||||||
|
codec_port = of_graph_get_port_parent(codec_ep);
|
||||||
|
|
||||||
of_node_put(cpu_port);
|
of_node_put(cpu_port);
|
||||||
of_node_put(cpu_ep);
|
of_node_put(cpu_ep);
|
||||||
of_node_put(codec_ep);
|
of_node_put(codec_ep);
|
||||||
|
of_node_put(codec_port);
|
||||||
|
|
||||||
if (codec) {
|
if (codec) {
|
||||||
if (!codec_ep)
|
if (!codec_port)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (codec_port_old == codec_port)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
codec_port_old = codec_port;
|
||||||
|
|
||||||
/* Back-End (= Codec) */
|
/* Back-End (= Codec) */
|
||||||
ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
|
ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -290,9 +281,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto parse_of_err;
|
goto parse_of_err;
|
||||||
|
|
||||||
dev_dbg(dev, "convert_rate %d\n", priv->convert_rate);
|
|
||||||
dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
parse_of_err:
|
parse_of_err:
|
||||||
|
@ -306,22 +294,34 @@ static int asoc_graph_get_dais_count(struct device *dev)
|
||||||
struct device_node *cpu_port;
|
struct device_node *cpu_port;
|
||||||
struct device_node *cpu_ep;
|
struct device_node *cpu_ep;
|
||||||
struct device_node *codec_ep;
|
struct device_node *codec_ep;
|
||||||
|
struct device_node *codec_port;
|
||||||
|
struct device_node *codec_port_old;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
codec_port_old = NULL;
|
||||||
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
|
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
|
||||||
cpu_port = it.node;
|
cpu_port = it.node;
|
||||||
cpu_ep = of_get_next_child(cpu_port, NULL);
|
cpu_ep = of_get_next_child(cpu_port, NULL);
|
||||||
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
|
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
|
||||||
|
codec_port = of_graph_get_port_parent(codec_ep);
|
||||||
|
|
||||||
of_node_put(cpu_port);
|
of_node_put(cpu_port);
|
||||||
of_node_put(cpu_ep);
|
of_node_put(cpu_ep);
|
||||||
of_node_put(codec_ep);
|
of_node_put(codec_ep);
|
||||||
|
of_node_put(codec_port);
|
||||||
|
|
||||||
if (cpu_ep)
|
if (cpu_ep)
|
||||||
count++;
|
count++;
|
||||||
if (codec_ep)
|
|
||||||
count++;
|
if (!codec_port)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (codec_port_old == codec_port)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
codec_port_old = codec_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
|
|
@ -13,6 +13,46 @@
|
||||||
#include <linux/of_graph.h>
|
#include <linux/of_graph.h>
|
||||||
#include <sound/simple_card_utils.h>
|
#include <sound/simple_card_utils.h>
|
||||||
|
|
||||||
|
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_interval *rate = hw_param_interval(params,
|
||||||
|
SNDRV_PCM_HW_PARAM_RATE);
|
||||||
|
struct snd_interval *channels = hw_param_interval(params,
|
||||||
|
SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||||
|
|
||||||
|
if (data->convert_rate)
|
||||||
|
rate->min =
|
||||||
|
rate->max = data->convert_rate;
|
||||||
|
|
||||||
|
if (data->convert_channels)
|
||||||
|
channels->min =
|
||||||
|
channels->max = data->convert_channels;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
|
||||||
|
|
||||||
|
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
|
||||||
|
struct asoc_simple_card_data *data)
|
||||||
|
{
|
||||||
|
struct device_node *np = dev->of_node;
|
||||||
|
char prop[128];
|
||||||
|
|
||||||
|
if (!prefix)
|
||||||
|
prefix = "";
|
||||||
|
|
||||||
|
/* sampling rate convert */
|
||||||
|
snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
|
||||||
|
of_property_read_u32(np, prop, &data->convert_rate);
|
||||||
|
|
||||||
|
/* channels transfer */
|
||||||
|
snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
|
||||||
|
of_property_read_u32(np, prop, &data->convert_channels);
|
||||||
|
|
||||||
|
dev_dbg(dev, "convert_rate %d\n", data->convert_rate);
|
||||||
|
dev_dbg(dev, "convert_channels %d\n", data->convert_channels);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_convert);
|
||||||
|
|
||||||
int asoc_simple_card_parse_daifmt(struct device *dev,
|
int asoc_simple_card_parse_daifmt(struct device *dev,
|
||||||
struct device_node *node,
|
struct device_node *node,
|
||||||
struct device_node *codec,
|
struct device_node *codec,
|
||||||
|
@ -110,6 +150,24 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
|
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
|
||||||
|
|
||||||
|
static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
|
||||||
|
struct clk *clk)
|
||||||
|
{
|
||||||
|
dai->clk = clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
|
||||||
|
{
|
||||||
|
return clk_prepare_enable(dai->clk);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
|
||||||
|
|
||||||
|
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
|
||||||
|
{
|
||||||
|
clk_disable_unprepare(dai->clk);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
|
||||||
|
|
||||||
int asoc_simple_card_parse_clk(struct device *dev,
|
int asoc_simple_card_parse_clk(struct device *dev,
|
||||||
struct device_node *node,
|
struct device_node *node,
|
||||||
struct device_node *dai_of_node,
|
struct device_node *dai_of_node,
|
||||||
|
@ -128,7 +186,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
|
||||||
clk = devm_get_clk_from_child(dev, node, NULL);
|
clk = devm_get_clk_from_child(dev, node, NULL);
|
||||||
if (!IS_ERR(clk)) {
|
if (!IS_ERR(clk)) {
|
||||||
simple_dai->sysclk = clk_get_rate(clk);
|
simple_dai->sysclk = clk_get_rate(clk);
|
||||||
simple_dai->clk = clk;
|
|
||||||
|
asoc_simple_card_clk_register(simple_dai, clk);
|
||||||
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
|
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
|
||||||
simple_dai->sysclk = val;
|
simple_dai->sysclk = val;
|
||||||
} else {
|
} else {
|
||||||
|
@ -316,6 +375,47 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
|
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
|
||||||
|
|
||||||
|
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
|
||||||
|
char *prefix,
|
||||||
|
int optional)
|
||||||
|
{
|
||||||
|
struct device_node *node = card->dev->of_node;
|
||||||
|
char prop[128];
|
||||||
|
|
||||||
|
if (!prefix)
|
||||||
|
prefix = "";
|
||||||
|
|
||||||
|
snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
|
||||||
|
|
||||||
|
if (!of_property_read_bool(node, prop)) {
|
||||||
|
if (optional)
|
||||||
|
return 0;
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return snd_soc_of_parse_audio_routing(card, prop);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing);
|
||||||
|
|
||||||
|
int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
|
||||||
|
char *prefix)
|
||||||
|
{
|
||||||
|
struct device_node *node = card->dev->of_node;
|
||||||
|
char prop[128];
|
||||||
|
|
||||||
|
if (!prefix)
|
||||||
|
prefix = "";
|
||||||
|
|
||||||
|
snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
|
||||||
|
|
||||||
|
if (of_property_read_bool(node, prop))
|
||||||
|
return snd_soc_of_parse_audio_simple_widgets(card, prop);
|
||||||
|
|
||||||
|
/* no widgets is not error */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets);
|
||||||
|
|
||||||
/* Module information */
|
/* Module information */
|
||||||
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
|
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
|
||||||
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
|
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
|
||||||
|
|
|
@ -118,13 +118,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
|
||||||
simple_priv_to_props(priv, rtd->num);
|
simple_priv_to_props(priv, rtd->num);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = clk_prepare_enable(dai_props->cpu_dai.clk);
|
ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = clk_prepare_enable(dai_props->codec_dai.clk);
|
ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
|
||||||
if (ret)
|
if (ret)
|
||||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -136,9 +136,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
struct simple_dai_props *dai_props =
|
struct simple_dai_props *dai_props =
|
||||||
simple_priv_to_props(priv, rtd->num);
|
simple_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
clk_disable_unprepare(dai_props->cpu_dai.clk);
|
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
|
||||||
|
|
||||||
clk_disable_unprepare(dai_props->codec_dai.clk);
|
asoc_simple_card_clk_disable(&dai_props->codec_dai);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
|
static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
@ -233,13 +233,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
|
||||||
snprintf(prop, sizeof(prop), "%scpu", prefix);
|
snprintf(prop, sizeof(prop), "%scpu", prefix);
|
||||||
cpu = of_get_child_by_name(node, prop);
|
cpu = of_get_child_by_name(node, prop);
|
||||||
|
|
||||||
|
if (!cpu) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
|
||||||
|
goto dai_link_of_err;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(prop, sizeof(prop), "%splat", prefix);
|
snprintf(prop, sizeof(prop), "%splat", prefix);
|
||||||
plat = of_get_child_by_name(node, prop);
|
plat = of_get_child_by_name(node, prop);
|
||||||
|
|
||||||
snprintf(prop, sizeof(prop), "%scodec", prefix);
|
snprintf(prop, sizeof(prop), "%scodec", prefix);
|
||||||
codec = of_get_child_by_name(node, prop);
|
codec = of_get_child_by_name(node, prop);
|
||||||
|
|
||||||
if (!cpu || !codec) {
|
if (!codec) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
|
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
@ -265,17 +271,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
ret = snd_soc_of_parse_tdm_slot(cpu, &cpu_dai->tx_slot_mask,
|
ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
|
||||||
&cpu_dai->rx_slot_mask,
|
|
||||||
&cpu_dai->slots,
|
|
||||||
&cpu_dai->slot_width);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
ret = snd_soc_of_parse_tdm_slot(codec, &codec_dai->tx_slot_mask,
|
ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
|
||||||
&codec_dai->rx_slot_mask,
|
|
||||||
&codec_dai->slots,
|
|
||||||
&codec_dai->slot_width);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_link_of_err;
|
goto dai_link_of_err;
|
||||||
|
|
||||||
|
@ -341,12 +341,12 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asoc_simple_card_parse_of(struct device_node *node,
|
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
|
||||||
struct simple_card_data *priv)
|
|
||||||
{
|
{
|
||||||
struct device *dev = simple_priv_to_dev(priv);
|
struct device *dev = simple_priv_to_dev(priv);
|
||||||
struct snd_soc_card *card = simple_priv_to_card(priv);
|
struct snd_soc_card *card = simple_priv_to_card(priv);
|
||||||
struct device_node *dai_link;
|
struct device_node *dai_link;
|
||||||
|
struct device_node *node = dev->of_node;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!node)
|
if (!node)
|
||||||
|
@ -354,21 +354,13 @@ static int asoc_simple_card_parse_of(struct device_node *node,
|
||||||
|
|
||||||
dai_link = of_get_child_by_name(node, PREFIX "dai-link");
|
dai_link = of_get_child_by_name(node, PREFIX "dai-link");
|
||||||
|
|
||||||
/* The off-codec widgets */
|
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
|
||||||
if (of_property_read_bool(node, PREFIX "widgets")) {
|
if (ret < 0)
|
||||||
ret = snd_soc_of_parse_audio_simple_widgets(card,
|
goto card_parse_end;
|
||||||
PREFIX "widgets");
|
|
||||||
if (ret)
|
|
||||||
goto card_parse_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DAPM routes */
|
ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
|
||||||
if (of_property_read_bool(node, PREFIX "routing")) {
|
if (ret < 0)
|
||||||
ret = snd_soc_of_parse_audio_routing(card,
|
goto card_parse_end;
|
||||||
PREFIX "routing");
|
|
||||||
if (ret)
|
|
||||||
goto card_parse_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Factor to mclk, used in hw_params() */
|
/* Factor to mclk, used in hw_params() */
|
||||||
of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
|
of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
|
||||||
|
@ -445,7 +437,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
if (np && of_device_is_available(np)) {
|
if (np && of_device_is_available(np)) {
|
||||||
|
|
||||||
ret = asoc_simple_card_parse_of(np, priv);
|
ret = asoc_simple_card_parse_of(priv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ret != -EPROBE_DEFER)
|
if (ret != -EPROBE_DEFER)
|
||||||
dev_err(dev, "parse error %d\n", ret);
|
dev_err(dev, "parse error %d\n", ret);
|
||||||
|
|
|
@ -27,8 +27,7 @@ struct simple_card_data {
|
||||||
struct snd_soc_codec_conf codec_conf;
|
struct snd_soc_codec_conf codec_conf;
|
||||||
struct asoc_simple_dai *dai_props;
|
struct asoc_simple_dai *dai_props;
|
||||||
struct snd_soc_dai_link *dai_link;
|
struct snd_soc_dai_link *dai_link;
|
||||||
u32 convert_rate;
|
struct asoc_simple_card_data adata;
|
||||||
u32 convert_channels;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define simple_priv_to_card(priv) (&(priv)->snd_card)
|
#define simple_priv_to_card(priv) (&(priv)->snd_card)
|
||||||
|
@ -47,7 +46,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
|
||||||
struct asoc_simple_dai *dai_props =
|
struct asoc_simple_dai *dai_props =
|
||||||
simple_priv_to_props(priv, rtd->num);
|
simple_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
return clk_prepare_enable(dai_props->clk);
|
return asoc_simple_card_clk_enable(dai_props);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
|
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
|
@ -57,7 +56,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
|
||||||
struct asoc_simple_dai *dai_props =
|
struct asoc_simple_dai *dai_props =
|
||||||
simple_priv_to_props(priv, rtd->num);
|
simple_priv_to_props(priv, rtd->num);
|
||||||
|
|
||||||
clk_disable_unprepare(dai_props->clk);
|
asoc_simple_card_clk_disable(dai_props);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct snd_soc_ops asoc_simple_card_ops = {
|
static const struct snd_soc_ops asoc_simple_card_ops = {
|
||||||
|
@ -86,18 +85,8 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||||
struct snd_pcm_hw_params *params)
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||||
struct snd_interval *rate = hw_param_interval(params,
|
|
||||||
SNDRV_PCM_HW_PARAM_RATE);
|
|
||||||
struct snd_interval *channels = hw_param_interval(params,
|
|
||||||
SNDRV_PCM_HW_PARAM_CHANNELS);
|
|
||||||
|
|
||||||
if (priv->convert_rate)
|
asoc_simple_card_convert_fixup(&priv->adata, params);
|
||||||
rate->min =
|
|
||||||
rate->max = priv->convert_rate;
|
|
||||||
|
|
||||||
if (priv->convert_channels)
|
|
||||||
channels->min =
|
|
||||||
channels->max = priv->convert_channels;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -171,11 +160,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
|
||||||
PREFIX "prefix");
|
PREFIX "prefix");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = snd_soc_of_parse_tdm_slot(np,
|
ret = asoc_simple_card_of_parse_tdm(np, dai_props);
|
||||||
&dai_props->tx_slot_mask,
|
|
||||||
&dai_props->rx_slot_mask,
|
|
||||||
&dai_props->slots,
|
|
||||||
&dai_props->slot_width);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -206,15 +191,11 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
|
||||||
if (!node)
|
if (!node)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = snd_soc_of_parse_audio_routing(card, PREFIX "routing");
|
ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* sampling rate convert */
|
asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);
|
||||||
of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate);
|
|
||||||
|
|
||||||
/* channels transfer */
|
|
||||||
of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels);
|
|
||||||
|
|
||||||
/* find 1st codec */
|
/* find 1st codec */
|
||||||
np = of_get_child_by_name(node, PREFIX "codec");
|
np = of_get_child_by_name(node, PREFIX "codec");
|
||||||
|
@ -241,9 +222,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
dev_dbg(dev, "convert_rate %d\n", priv->convert_rate);
|
|
||||||
dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ static const struct snd_kcontrol_new mt2701_cs42448_controls[] = {
|
||||||
|
|
||||||
static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
|
static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
|
||||||
|
|
||||||
static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
|
static const struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
|
||||||
.count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
|
.count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
|
||||||
.list = mt2701_cs42448_sampling_rates,
|
.list = mt2701_cs42448_sampling_rates,
|
||||||
.mask = 0,
|
.mask = 0,
|
||||||
|
|
Loading…
Reference in a new issue