@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -57,6 +58,31 @@ static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir)
return !sai->synchronous[dir] && sai->synchronous[adir];
}
+static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk)
+{
+ struct pinctrl_state *state = 0;
+
+ if (sai->is_pdm_mode) {
+ /* DSD512@44.1kHz, DSD512@48kHz */
+ if (bclk >= 22579200)
+ state = pinctrl_lookup_state(sai->pinctrl, "dsd512");
+
+ /* Get default DSD state */
+ if (IS_ERR_OR_NULL(state))
+ state = pinctrl_lookup_state(sai->pinctrl, "dsd");
+ } else {
+ /* 706k32b2c, 768k32b2c, etc */
+ if (bclk >= 45158400)
+ state = pinctrl_lookup_state(sai->pinctrl, "pcm_b2m");
+ }
+
+ /* Get default state */
+ if (IS_ERR_OR_NULL(state))
+ state = pinctrl_lookup_state(sai->pinctrl, "default");
+
+ return state;
+}
+
static irqreturn_t fsl_sai_isr(int irq, void *devid)
{
struct fsl_sai *sai = (struct fsl_sai *)devid;
@@ -466,7 +492,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
u32 slots = (channels == 1) ? 2 : channels;
u32 slot_width = word_width;
int adir = tx ? RX : TX;
- u32 pins;
+ u32 pins, bclk;
int ret;
if (sai->slots)
@@ -484,15 +510,21 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
if (sai->is_pdm_mode)
pins = channels;
+ bclk = params_rate(params) * (sai->bclk_ratio ? sai->bclk_ratio : slots * slot_width);
+
+ if (!IS_ERR_OR_NULL(sai->pinctrl)) {
+ sai->pins_state = fsl_sai_get_pins_state(sai, bclk);
+ if (!IS_ERR_OR_NULL(sai->pins_state)) {
+ ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+ if (ret) {
+ dev_err(cpu_dai->dev, "failed to set proper pins state: %d\n", ret);
+ return ret;
+ }
+ }
+ }
+
if (!sai->is_consumer_mode) {
- if (sai->bclk_ratio)
- ret = fsl_sai_set_bclk(cpu_dai, tx,
- sai->bclk_ratio *
- params_rate(params));
- else
- ret = fsl_sai_set_bclk(cpu_dai, tx,
- slots * slot_width *
- params_rate(params));
+ ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
if (ret)
return ret;
@@ -757,6 +789,23 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static int fsl_sai_dai_resume(struct snd_soc_component *component)
+{
+ struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
+ struct device *dev = &sai->pdev->dev;
+ int ret;
+
+ if (!IS_ERR_OR_NULL(sai->pinctrl) && !IS_ERR_OR_NULL(sai->pins_state)) {
+ ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+ if (ret) {
+ dev_err(dev, "failed to set proper pins state: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static struct snd_soc_dai_driver fsl_sai_dai_template = {
.probe = fsl_sai_dai_probe,
.playback = {
@@ -782,6 +831,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = {
static const struct snd_soc_component_driver fsl_component = {
.name = "fsl-sai",
+ .resume = fsl_sai_dai_resume,
};
static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
@@ -1147,6 +1197,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+ sai->pinctrl = devm_pinctrl_get(&pdev->dev);
+
platform_set_drvdata(pdev, sai);
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev)) {
@@ -278,6 +278,8 @@ struct fsl_sai {
struct fsl_sai_verid verid;
struct fsl_sai_param param;
struct pm_qos_request pm_qos_req;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_state;
};
#define TX 1