2019-05-29 14:17:58 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2015-03-04 00:21:54 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
|
|
|
|
*
|
|
|
|
* lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/of.h>
|
2015-05-16 12:32:17 +00:00
|
|
|
#include <linux/of_device.h>
|
2015-03-04 00:21:54 +00:00
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <sound/pcm.h>
|
|
|
|
#include <sound/pcm_params.h>
|
|
|
|
#include <linux/regmap.h>
|
|
|
|
#include <sound/soc.h>
|
|
|
|
#include <sound/soc-dai.h>
|
2015-05-16 12:32:17 +00:00
|
|
|
#include "lpass-lpaif-reg.h"
|
2015-03-04 00:21:54 +00:00
|
|
|
#include "lpass.h"
|
|
|
|
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
#define LPASS_CPU_MAX_MI2S_LINES 4
|
|
|
|
#define LPASS_CPU_I2S_SD0_MASK BIT(0)
|
|
|
|
#define LPASS_CPU_I2S_SD1_MASK BIT(1)
|
|
|
|
#define LPASS_CPU_I2S_SD2_MASK BIT(2)
|
|
|
|
#define LPASS_CPU_I2S_SD3_MASK BIT(3)
|
|
|
|
#define LPASS_CPU_I2S_SD0_1_MASK GENMASK(1, 0)
|
|
|
|
#define LPASS_CPU_I2S_SD2_3_MASK GENMASK(3, 2)
|
|
|
|
#define LPASS_CPU_I2S_SD0_1_2_MASK GENMASK(2, 0)
|
|
|
|
#define LPASS_CPU_I2S_SD0_1_2_3_MASK GENMASK(3, 0)
|
2022-02-24 15:33:44 +00:00
|
|
|
#define LPASS_REG_READ 1
|
|
|
|
#define LPASS_REG_WRITE 0
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
|
2021-06-09 13:30:39 +00:00
|
|
|
/*
|
|
|
|
* Channel maps for Quad channel playbacks on MI2S Secondary
|
|
|
|
*/
|
|
|
|
static struct snd_pcm_chmap_elem lpass_quad_chmaps[] = {
|
|
|
|
{ .channels = 4,
|
|
|
|
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_RL,
|
|
|
|
SNDRV_CHMAP_FR, SNDRV_CHMAP_RR } },
|
|
|
|
{ }
|
|
|
|
};
|
2020-08-14 10:53:01 +00:00
|
|
|
static int lpass_cpu_init_i2sctl_bitfields(struct device *dev,
|
|
|
|
struct lpaif_i2sctl *i2sctl, struct regmap *map)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
|
|
|
|
i2sctl->loopback = devm_regmap_field_alloc(dev, map, v->loopback);
|
|
|
|
i2sctl->spken = devm_regmap_field_alloc(dev, map, v->spken);
|
|
|
|
i2sctl->spkmode = devm_regmap_field_alloc(dev, map, v->spkmode);
|
|
|
|
i2sctl->spkmono = devm_regmap_field_alloc(dev, map, v->spkmono);
|
|
|
|
i2sctl->micen = devm_regmap_field_alloc(dev, map, v->micen);
|
|
|
|
i2sctl->micmode = devm_regmap_field_alloc(dev, map, v->micmode);
|
|
|
|
i2sctl->micmono = devm_regmap_field_alloc(dev, map, v->micmono);
|
|
|
|
i2sctl->wssrc = devm_regmap_field_alloc(dev, map, v->wssrc);
|
|
|
|
i2sctl->bitwidth = devm_regmap_field_alloc(dev, map, v->bitwidth);
|
|
|
|
|
|
|
|
if (IS_ERR(i2sctl->loopback) || IS_ERR(i2sctl->spken) ||
|
|
|
|
IS_ERR(i2sctl->spkmode) || IS_ERR(i2sctl->spkmono) ||
|
|
|
|
IS_ERR(i2sctl->micen) || IS_ERR(i2sctl->micmode) ||
|
|
|
|
IS_ERR(i2sctl->micmono) || IS_ERR(i2sctl->wssrc) ||
|
|
|
|
IS_ERR(i2sctl->bitwidth))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-04 00:21:54 +00:00
|
|
|
static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
|
|
|
unsigned int freq, int dir)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
|
|
|
int ret;
|
|
|
|
|
2015-05-21 21:52:49 +00:00
|
|
|
ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
|
2015-03-04 00:21:54 +00:00
|
|
|
if (ret)
|
2017-01-30 21:03:37 +00:00
|
|
|
dev_err(dai->dev, "error setting mi2s osrclk to %u: %d\n",
|
|
|
|
freq, ret);
|
2015-03-04 00:21:54 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
|
|
|
|
struct snd_soc_dai *dai)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
|
|
|
int ret;
|
|
|
|
|
2017-01-30 21:03:36 +00:00
|
|
|
ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->driver->id]);
|
|
|
|
if (ret) {
|
2017-01-30 21:03:37 +00:00
|
|
|
dev_err(dai->dev, "error in enabling mi2s osr clk: %d\n", ret);
|
2017-01-30 21:03:36 +00:00
|
|
|
return ret;
|
2015-03-04 00:21:54 +00:00
|
|
|
}
|
2020-10-19 09:06:03 +00:00
|
|
|
ret = clk_prepare(drvdata->mi2s_bit_clk[dai->driver->id]);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
|
|
|
|
clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
|
|
|
|
return ret;
|
|
|
|
}
|
2015-03-04 00:21:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
|
|
|
|
struct snd_soc_dai *dai)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
2021-06-04 15:45:45 +00:00
|
|
|
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
|
|
|
|
unsigned int id = dai->driver->id;
|
2015-03-04 00:21:54 +00:00
|
|
|
|
2017-01-30 21:03:36 +00:00
|
|
|
clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
|
2021-06-04 15:45:45 +00:00
|
|
|
/*
|
|
|
|
* Ensure LRCLK is disabled even in device node validation.
|
|
|
|
* Will not impact if disabled in lpass_cpu_daiops_trigger()
|
|
|
|
* suspend.
|
|
|
|
*/
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
|
|
regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_DISABLE);
|
|
|
|
else
|
|
|
|
regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_DISABLE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BCLK may not be enabled if lpass_cpu_daiops_prepare is called before
|
|
|
|
* lpass_cpu_daiops_shutdown. It's paired with the clk_enable in
|
|
|
|
* lpass_cpu_daiops_prepare.
|
|
|
|
*/
|
|
|
|
if (drvdata->mi2s_was_prepared[dai->driver->id]) {
|
|
|
|
drvdata->mi2s_was_prepared[dai->driver->id] = false;
|
|
|
|
clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
|
|
|
|
}
|
|
|
|
|
2020-10-19 09:06:03 +00:00
|
|
|
clk_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
|
2015-03-04 00:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
|
|
|
|
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
2020-08-14 10:53:01 +00:00
|
|
|
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
|
|
|
|
unsigned int id = dai->driver->id;
|
2015-03-04 00:21:54 +00:00
|
|
|
snd_pcm_format_t format = params_format(params);
|
|
|
|
unsigned int channels = params_channels(params);
|
|
|
|
unsigned int rate = params_rate(params);
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
unsigned int mode;
|
2015-03-04 00:21:54 +00:00
|
|
|
unsigned int regval;
|
|
|
|
int bitwidth, ret;
|
|
|
|
|
|
|
|
bitwidth = snd_pcm_format_width(format);
|
|
|
|
if (bitwidth < 0) {
|
2017-01-30 21:03:37 +00:00
|
|
|
dev_err(dai->dev, "invalid bit width given: %d\n", bitwidth);
|
2015-03-04 00:21:54 +00:00
|
|
|
return bitwidth;
|
|
|
|
}
|
|
|
|
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->loopback, id,
|
|
|
|
LPAIF_I2SCTL_LOOPBACK_DISABLE);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error updating loopback field: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = regmap_fields_write(i2sctl->wssrc, id,
|
|
|
|
LPAIF_I2SCTL_WSSRC_INTERNAL);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error updating wssrc field: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2015-03-04 00:21:54 +00:00
|
|
|
|
|
|
|
switch (bitwidth) {
|
|
|
|
case 16:
|
2020-08-14 10:53:01 +00:00
|
|
|
regval = LPAIF_I2SCTL_BITWIDTH_16;
|
2015-03-04 00:21:54 +00:00
|
|
|
break;
|
|
|
|
case 24:
|
2020-08-14 10:53:01 +00:00
|
|
|
regval = LPAIF_I2SCTL_BITWIDTH_24;
|
2015-03-04 00:21:54 +00:00
|
|
|
break;
|
|
|
|
case 32:
|
2020-08-14 10:53:01 +00:00
|
|
|
regval = LPAIF_I2SCTL_BITWIDTH_32;
|
2015-03-04 00:21:54 +00:00
|
|
|
break;
|
|
|
|
default:
|
2017-01-30 21:03:37 +00:00
|
|
|
dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth);
|
2015-03-04 00:21:54 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->bitwidth, id, regval);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error updating bitwidth field: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
2020-08-14 10:53:01 +00:00
|
|
|
mode = drvdata->mi2s_playback_sd_mode[id];
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
else
|
2020-08-14 10:53:01 +00:00
|
|
|
mode = drvdata->mi2s_capture_sd_mode[id];
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
|
|
|
|
if (!mode) {
|
|
|
|
dev_err(dai->dev, "no line is assigned\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (channels) {
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
switch (mode) {
|
|
|
|
case LPAIF_I2SCTL_MODE_QUAD01:
|
|
|
|
case LPAIF_I2SCTL_MODE_6CH:
|
|
|
|
case LPAIF_I2SCTL_MODE_8CH:
|
|
|
|
mode = LPAIF_I2SCTL_MODE_SD0;
|
2016-02-11 12:18:33 +00:00
|
|
|
break;
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
case LPAIF_I2SCTL_MODE_QUAD23:
|
|
|
|
mode = LPAIF_I2SCTL_MODE_SD2;
|
2016-02-11 12:18:33 +00:00
|
|
|
break;
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if (mode < LPAIF_I2SCTL_MODE_QUAD01) {
|
|
|
|
dev_err(dai->dev, "cannot configure 4 channels with mode %d\n",
|
|
|
|
mode);
|
2016-02-11 12:18:33 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case LPAIF_I2SCTL_MODE_6CH:
|
|
|
|
case LPAIF_I2SCTL_MODE_8CH:
|
|
|
|
mode = LPAIF_I2SCTL_MODE_QUAD01;
|
2016-02-11 12:18:33 +00:00
|
|
|
break;
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
if (mode < LPAIF_I2SCTL_MODE_6CH) {
|
|
|
|
dev_err(dai->dev, "cannot configure 6 channels with mode %d\n",
|
|
|
|
mode);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case LPAIF_I2SCTL_MODE_8CH:
|
|
|
|
mode = LPAIF_I2SCTL_MODE_6CH;
|
2016-02-11 12:18:33 +00:00
|
|
|
break;
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
if (mode < LPAIF_I2SCTL_MODE_8CH) {
|
|
|
|
dev_err(dai->dev, "cannot configure 8 channels with mode %d\n",
|
|
|
|
mode);
|
2016-02-11 12:18:33 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dev_err(dai->dev, "invalid channels given: %u\n", channels);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->spkmode, id,
|
|
|
|
LPAIF_I2SCTL_SPKMODE(mode));
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error writing to i2sctl spkr mode: %d\n",
|
|
|
|
ret);
|
|
|
|
return ret;
|
|
|
|
}
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
if (channels >= 2)
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->spkmono, id,
|
|
|
|
LPAIF_I2SCTL_SPKMONO_STEREO);
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
else
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->spkmono, id,
|
|
|
|
LPAIF_I2SCTL_SPKMONO_MONO);
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
} else {
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->micmode, id,
|
|
|
|
LPAIF_I2SCTL_MICMODE(mode));
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error writing to i2sctl mic mode: %d\n",
|
|
|
|
ret);
|
|
|
|
return ret;
|
|
|
|
}
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
if (channels >= 2)
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->micmono, id,
|
|
|
|
LPAIF_I2SCTL_MICMONO_STEREO);
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
else
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->micmono, id,
|
|
|
|
LPAIF_I2SCTL_MICMONO_MONO);
|
2015-03-04 00:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ret) {
|
2020-08-14 10:53:01 +00:00
|
|
|
dev_err(dai->dev, "error writing to i2sctl channels mode: %d\n",
|
|
|
|
ret);
|
2015-03-04 00:21:54 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = clk_set_rate(drvdata->mi2s_bit_clk[id],
|
2015-05-21 21:52:49 +00:00
|
|
|
rate * bitwidth * 2);
|
2015-03-04 00:21:54 +00:00
|
|
|
if (ret) {
|
2017-01-30 21:03:37 +00:00
|
|
|
dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n",
|
|
|
|
rate * bitwidth * 2, ret);
|
2015-03-04 00:21:54 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
|
|
|
|
int cmd, struct snd_soc_dai *dai)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
2020-08-14 10:53:01 +00:00
|
|
|
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
|
|
|
|
unsigned int id = dai->driver->id;
|
2015-04-13 12:23:29 +00:00
|
|
|
int ret = -EINVAL;
|
2015-03-04 00:21:54 +00:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
|
|
case SNDRV_PCM_TRIGGER_RESUME:
|
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
2021-06-04 15:45:45 +00:00
|
|
|
/*
|
|
|
|
* Ensure lpass BCLK/LRCLK is enabled during
|
|
|
|
* device resume as lpass_cpu_daiops_prepare() is not called
|
|
|
|
* after the device resumes. We don't check mi2s_was_prepared before
|
|
|
|
* enable/disable BCLK in trigger events because:
|
|
|
|
* 1. These trigger events are paired, so the BCLK
|
|
|
|
* enable_count is balanced.
|
|
|
|
* 2. the BCLK can be shared (ex: headset and headset mic),
|
|
|
|
* we need to increase the enable_count so that we don't
|
|
|
|
* turn off the shared BCLK while other devices are using
|
|
|
|
* it.
|
|
|
|
*/
|
2016-02-11 12:18:33 +00:00
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->spken, id,
|
|
|
|
LPAIF_I2SCTL_SPKEN_ENABLE);
|
2016-02-11 12:18:33 +00:00
|
|
|
} else {
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->micen, id,
|
|
|
|
LPAIF_I2SCTL_MICEN_ENABLE);
|
2016-02-11 12:18:33 +00:00
|
|
|
}
|
2015-03-04 00:21:54 +00:00
|
|
|
if (ret)
|
2017-01-30 21:03:37 +00:00
|
|
|
dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
|
|
|
|
ret);
|
2020-09-18 16:54:33 +00:00
|
|
|
|
2021-01-27 15:18:24 +00:00
|
|
|
ret = clk_enable(drvdata->mi2s_bit_clk[id]);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
|
|
|
|
clk_disable(drvdata->mi2s_osr_clk[id]);
|
|
|
|
return ret;
|
2020-09-18 16:54:33 +00:00
|
|
|
}
|
2015-03-04 00:21:54 +00:00
|
|
|
break;
|
|
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
|
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
2021-06-04 15:45:45 +00:00
|
|
|
/*
|
|
|
|
* To ensure lpass BCLK/LRCLK is disabled during
|
|
|
|
* device suspend.
|
|
|
|
*/
|
2016-02-11 12:18:33 +00:00
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->spken, id,
|
|
|
|
LPAIF_I2SCTL_SPKEN_DISABLE);
|
2016-02-11 12:18:33 +00:00
|
|
|
} else {
|
2020-08-14 10:53:01 +00:00
|
|
|
ret = regmap_fields_write(i2sctl->micen, id,
|
|
|
|
LPAIF_I2SCTL_MICEN_DISABLE);
|
2016-02-11 12:18:33 +00:00
|
|
|
}
|
2015-03-04 00:21:54 +00:00
|
|
|
if (ret)
|
2017-01-30 21:03:37 +00:00
|
|
|
dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
|
|
|
|
ret);
|
2021-01-27 15:18:24 +00:00
|
|
|
|
|
|
|
clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
|
|
|
|
|
2015-03-04 00:21:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-06-04 15:45:45 +00:00
|
|
|
static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
|
|
|
|
struct snd_soc_dai *dai)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
|
|
|
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
|
|
|
|
unsigned int id = dai->driver->id;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure lpass BCLK/LRCLK is enabled bit before playback/capture
|
|
|
|
* data flow starts. This allows other codec to have some delay before
|
|
|
|
* the data flow.
|
|
|
|
* (ex: to drop start up pop noise before capture starts).
|
|
|
|
*/
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
|
|
ret = regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_ENABLE);
|
|
|
|
else
|
|
|
|
ret = regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_ENABLE);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check mi2s_was_prepared before enabling BCLK as lpass_cpu_daiops_prepare can
|
|
|
|
* be called multiple times. It's paired with the clk_disable in
|
|
|
|
* lpass_cpu_daiops_shutdown.
|
|
|
|
*/
|
|
|
|
if (!drvdata->mi2s_was_prepared[dai->driver->id]) {
|
|
|
|
ret = clk_enable(drvdata->mi2s_bit_clk[id]);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
drvdata->mi2s_was_prepared[dai->driver->id] = true;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-28 02:53:31 +00:00
|
|
|
const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
|
2015-03-04 00:21:54 +00:00
|
|
|
.set_sysclk = lpass_cpu_daiops_set_sysclk,
|
|
|
|
.startup = lpass_cpu_daiops_startup,
|
|
|
|
.shutdown = lpass_cpu_daiops_shutdown,
|
|
|
|
.hw_params = lpass_cpu_daiops_hw_params,
|
|
|
|
.trigger = lpass_cpu_daiops_trigger,
|
2021-06-04 15:45:45 +00:00
|
|
|
.prepare = lpass_cpu_daiops_prepare,
|
2015-03-04 00:21:54 +00:00
|
|
|
};
|
2015-05-16 12:32:17 +00:00
|
|
|
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
|
2015-03-04 00:21:54 +00:00
|
|
|
|
2021-06-09 13:30:39 +00:00
|
|
|
int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
|
|
|
|
struct snd_soc_dai *dai)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct snd_soc_dai_driver *drv = dai->driver;
|
|
|
|
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
|
|
|
|
|
|
|
if (drvdata->mi2s_playback_sd_mode[dai->id] == LPAIF_I2SCTL_MODE_QUAD01) {
|
|
|
|
ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
|
|
|
lpass_quad_chmaps, drv->playback.channels_max, 0,
|
|
|
|
NULL);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new);
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
|
2015-03-04 00:21:54 +00:00
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* ensure audio hardware is disabled */
|
|
|
|
ret = regmap_write(drvdata->lpaif_map,
|
2015-05-16 12:32:25 +00:00
|
|
|
LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
|
2015-03-04 00:21:54 +00:00
|
|
|
if (ret)
|
2017-01-30 21:03:37 +00:00
|
|
|
dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
|
2015-03-04 00:21:54 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2015-05-16 12:32:17 +00:00
|
|
|
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
|
2015-03-04 00:21:54 +00:00
|
|
|
|
2021-01-19 17:15:27 +00:00
|
|
|
static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component,
|
2021-02-21 15:30:24 +00:00
|
|
|
const struct of_phandle_args *args,
|
2021-01-19 17:15:27 +00:00
|
|
|
const char **dai_name)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
|
|
|
struct lpass_variant *variant = drvdata->variant;
|
|
|
|
int id = args->args[0];
|
|
|
|
int ret = -EINVAL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < variant->num_dai; i++) {
|
|
|
|
if (variant->dai_driver[i].id == id) {
|
|
|
|
*dai_name = variant->dai_driver[i].name;
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-03-04 00:21:54 +00:00
|
|
|
static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
|
|
|
|
.name = "lpass-cpu",
|
2021-01-19 17:15:27 +00:00
|
|
|
.of_xlate_dai_name = asoc_qcom_of_xlate_dai_name,
|
2015-03-04 00:21:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
|
|
|
|
{
|
2015-05-16 12:32:17 +00:00
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
2015-03-04 00:21:54 +00:00
|
|
|
int i;
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
for (i = 0; i < v->i2s_ports; ++i)
|
|
|
|
if (reg == LPAIF_I2SCTL_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
for (i = 0; i < v->irq_ports; ++i) {
|
|
|
|
if (reg == LPAIF_IRQEN_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_IRQCLEAR_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
for (i = 0; i < v->rdma_channels; ++i) {
|
|
|
|
if (reg == LPAIF_RDMACTL_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_RDMABASE_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_RDMABUFF_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_RDMAPER_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-11 12:18:27 +00:00
|
|
|
for (i = 0; i < v->wrdma_channels; ++i) {
|
|
|
|
if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-03-04 00:21:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
|
|
|
|
{
|
2015-05-16 12:32:17 +00:00
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
2015-03-04 00:21:54 +00:00
|
|
|
int i;
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
for (i = 0; i < v->i2s_ports; ++i)
|
|
|
|
if (reg == LPAIF_I2SCTL_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
for (i = 0; i < v->irq_ports; ++i) {
|
2021-06-24 09:21:53 +00:00
|
|
|
if (reg == LPAIF_IRQCLEAR_REG(v, i))
|
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_IRQEN_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_IRQSTAT_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
for (i = 0; i < v->rdma_channels; ++i) {
|
|
|
|
if (reg == LPAIF_RDMACTL_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_RDMABASE_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_RDMABUFF_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_RDMACURR_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_RDMAPER_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-11 12:18:27 +00:00
|
|
|
for (i = 0; i < v->wrdma_channels; ++i) {
|
|
|
|
if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-03-04 00:21:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
|
|
|
|
{
|
2015-05-16 12:32:17 +00:00
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
2015-03-04 00:21:54 +00:00
|
|
|
int i;
|
|
|
|
|
2021-06-24 09:21:53 +00:00
|
|
|
for (i = 0; i < v->irq_ports; ++i) {
|
|
|
|
if (reg == LPAIF_IRQCLEAR_REG(v, i))
|
|
|
|
return true;
|
2015-05-16 12:32:17 +00:00
|
|
|
if (reg == LPAIF_IRQSTAT_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
2021-06-24 09:21:53 +00:00
|
|
|
}
|
2015-03-04 00:21:54 +00:00
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
for (i = 0; i < v->rdma_channels; ++i)
|
2020-12-17 08:08:33 +00:00
|
|
|
if (reg == LPAIF_RDMACURR_REG(v, i))
|
2015-03-04 00:21:54 +00:00
|
|
|
return true;
|
|
|
|
|
2016-02-11 12:18:27 +00:00
|
|
|
for (i = 0; i < v->wrdma_channels; ++i)
|
2020-12-17 08:08:33 +00:00
|
|
|
if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
|
2016-02-11 12:18:27 +00:00
|
|
|
return true;
|
|
|
|
|
2015-03-04 00:21:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
static struct regmap_config lpass_cpu_regmap_config = {
|
2021-01-15 03:43:25 +00:00
|
|
|
.name = "lpass_cpu",
|
2015-03-04 00:21:54 +00:00
|
|
|
.reg_bits = 32,
|
|
|
|
.reg_stride = 4,
|
|
|
|
.val_bits = 32,
|
|
|
|
.writeable_reg = lpass_cpu_regmap_writeable,
|
|
|
|
.readable_reg = lpass_cpu_regmap_readable,
|
|
|
|
.volatile_reg = lpass_cpu_regmap_volatile,
|
|
|
|
.cache_type = REGCACHE_FLAT,
|
|
|
|
};
|
|
|
|
|
2020-10-08 05:17:01 +00:00
|
|
|
static int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
unsigned int i;
|
|
|
|
struct lpass_hdmi_tx_ctl *tx_ctl;
|
|
|
|
struct regmap_field *legacy_en;
|
|
|
|
struct lpass_vbit_ctrl *vbit_ctl;
|
|
|
|
struct regmap_field *tx_parity;
|
|
|
|
struct lpass_dp_metadata_ctl *meta_ctl;
|
|
|
|
struct lpass_sstream_ctl *sstream_ctl;
|
|
|
|
struct regmap_field *ch_msb;
|
|
|
|
struct regmap_field *ch_lsb;
|
|
|
|
struct lpass_hdmitx_dmactl *tx_dmactl;
|
|
|
|
int rval;
|
|
|
|
|
|
|
|
tx_ctl = devm_kzalloc(dev, sizeof(*tx_ctl), GFP_KERNEL);
|
|
|
|
if (!tx_ctl)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->soft_reset, tx_ctl->soft_reset);
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->force_reset, tx_ctl->force_reset);
|
|
|
|
drvdata->tx_ctl = tx_ctl;
|
|
|
|
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->legacy_en, legacy_en);
|
|
|
|
drvdata->hdmitx_legacy_en = legacy_en;
|
|
|
|
|
|
|
|
vbit_ctl = devm_kzalloc(dev, sizeof(*vbit_ctl), GFP_KERNEL);
|
|
|
|
if (!vbit_ctl)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->replace_vbit, vbit_ctl->replace_vbit);
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->vbit_stream, vbit_ctl->vbit_stream);
|
|
|
|
drvdata->vbit_ctl = vbit_ctl;
|
|
|
|
|
|
|
|
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->calc_en, tx_parity);
|
|
|
|
drvdata->hdmitx_parity_calc_en = tx_parity;
|
|
|
|
|
|
|
|
meta_ctl = devm_kzalloc(dev, sizeof(*meta_ctl), GFP_KERNEL);
|
|
|
|
if (!meta_ctl)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
rval = devm_regmap_field_bulk_alloc(dev, map, &meta_ctl->mute, &v->mute, 7);
|
|
|
|
if (rval)
|
|
|
|
return rval;
|
|
|
|
drvdata->meta_ctl = meta_ctl;
|
|
|
|
|
|
|
|
sstream_ctl = devm_kzalloc(dev, sizeof(*sstream_ctl), GFP_KERNEL);
|
|
|
|
if (!sstream_ctl)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
rval = devm_regmap_field_bulk_alloc(dev, map, &sstream_ctl->sstream_en, &v->sstream_en, 9);
|
|
|
|
if (rval)
|
|
|
|
return rval;
|
|
|
|
|
|
|
|
drvdata->sstream_ctl = sstream_ctl;
|
|
|
|
|
|
|
|
for (i = 0; i < LPASS_MAX_HDMI_DMA_CHANNELS; i++) {
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->msb_bits, ch_msb);
|
|
|
|
drvdata->hdmitx_ch_msb[i] = ch_msb;
|
|
|
|
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->lsb_bits, ch_lsb);
|
|
|
|
drvdata->hdmitx_ch_lsb[i] = ch_lsb;
|
|
|
|
|
|
|
|
tx_dmactl = devm_kzalloc(dev, sizeof(*tx_dmactl), GFP_KERNEL);
|
|
|
|
if (!tx_dmactl)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_chs, tx_dmactl->use_hw_chs);
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_usr, tx_dmactl->use_hw_usr);
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_chs_sel, tx_dmactl->hw_chs_sel);
|
|
|
|
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_usr_sel, tx_dmactl->hw_usr_sel);
|
|
|
|
drvdata->hdmi_tx_dmactl[i] = tx_dmactl;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_DP_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMITX_APP_IRQCLEAR_REG(v))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
for (i = 0; i < v->hdmi_rdma_channels; i++) {
|
|
|
|
if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-02-02 06:27:27 +00:00
|
|
|
for (i = 0; i < v->hdmi_rdma_channels; ++i) {
|
2020-10-08 05:17:01 +00:00
|
|
|
if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
for (i = 0; i < v->hdmi_rdma_channels; i++) {
|
|
|
|
if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_DP_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
|
|
|
|
return true;
|
|
|
|
|
2021-02-02 06:27:27 +00:00
|
|
|
for (i = 0; i < v->hdmi_rdma_channels; ++i) {
|
2020-10-08 05:17:01 +00:00
|
|
|
if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
|
|
|
|
return true;
|
|
|
|
if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
|
|
|
|
return true;
|
|
|
|
|
2021-02-02 06:27:27 +00:00
|
|
|
for (i = 0; i < v->hdmi_rdma_channels; ++i) {
|
2020-10-08 05:17:01 +00:00
|
|
|
if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-05 11:41:00 +00:00
|
|
|
static struct regmap_config lpass_hdmi_regmap_config = {
|
2021-01-15 03:43:25 +00:00
|
|
|
.name = "lpass_hdmi",
|
2020-10-08 05:17:01 +00:00
|
|
|
.reg_bits = 32,
|
|
|
|
.reg_stride = 4,
|
|
|
|
.val_bits = 32,
|
|
|
|
.writeable_reg = lpass_hdmi_regmap_writeable,
|
|
|
|
.readable_reg = lpass_hdmi_regmap_readable,
|
|
|
|
.volatile_reg = lpass_hdmi_regmap_volatile,
|
|
|
|
.cache_type = REGCACHE_FLAT,
|
|
|
|
};
|
|
|
|
|
2022-02-24 15:33:44 +00:00
|
|
|
static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < v->rxtx_irq_ports; ++i) {
|
|
|
|
if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_RXTX_IRQEN_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < v->rxtx_rdma_channels; ++i) {
|
|
|
|
if (reg == LPAIF_CDC_RXTX_RDMACTL_REG(v, i, LPASS_CDC_DMA_RX0))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_RXTX_RDMABASE_REG(v, i, LPASS_CDC_DMA_RX0))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_RXTX_RDMABUFF_REG(v, i, LPASS_CDC_DMA_RX0))
|
|
|
|
return true;
|
|
|
|
if (rw == LPASS_REG_READ) {
|
|
|
|
if (reg == LPAIF_CDC_RXTX_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (reg == LPAIF_CDC_RXTX_RDMAPER_REG(v, i, LPASS_CDC_DMA_RX0))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_RXTX_RDMA_INTF_REG(v, i, LPASS_CDC_DMA_RX0))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < v->rxtx_wrdma_channels; ++i) {
|
|
|
|
if (reg == LPAIF_CDC_RXTX_WRDMACTL_REG(v, i + v->rxtx_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_TX3))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_RXTX_WRDMABASE_REG(v, i + v->rxtx_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_TX3))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_RXTX_WRDMABUFF_REG(v, i + v->rxtx_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_TX3))
|
|
|
|
return true;
|
|
|
|
if (rw == LPASS_REG_READ) {
|
|
|
|
if (reg == LPAIF_CDC_RXTX_WRDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (reg == LPAIF_CDC_RXTX_WRDMAPER_REG(v, i + v->rxtx_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_TX3))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_RXTX_WRDMA_INTF_REG(v, i + v->rxtx_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_TX3))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_rxtx_regmap_writeable(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_WRITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_READ);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < v->rxtx_irq_ports; ++i) {
|
|
|
|
if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < v->rxtx_rdma_channels; ++i)
|
|
|
|
if (reg == LPAIF_CDC_RXTX_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
for (i = 0; i < v->rxtx_wrdma_channels; ++i)
|
|
|
|
if (reg == LPAIF_CDC_RXTX_WRDMACURR_REG(v, i + v->rxtx_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_TX3))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool __lpass_va_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < v->va_irq_ports; ++i) {
|
|
|
|
if (reg == LPAIF_VA_IRQCLEAR_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_VA_IRQEN_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_VA_IRQSTAT_REG(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < v->va_wrdma_channels; ++i) {
|
|
|
|
if (reg == LPAIF_CDC_VA_WRDMACTL_REG(v, i + v->va_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_VA_TX0))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_VA_WRDMABASE_REG(v, i + v->va_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_VA_TX0))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_VA_WRDMABUFF_REG(v, i + v->va_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_VA_TX0))
|
|
|
|
return true;
|
|
|
|
if (rw == LPASS_REG_READ) {
|
|
|
|
if (reg == LPAIF_CDC_VA_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_VA_TX0))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (reg == LPAIF_CDC_VA_WRDMAPER_REG(v, i + v->va_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_VA_TX0))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_CDC_VA_WRDMA_INTF_REG(v, i + v->va_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_VA_TX0))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_va_regmap_writeable(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_WRITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_va_regmap_readable(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_READ);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lpass_va_regmap_volatile(struct device *dev, unsigned int reg)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = dev_get_drvdata(dev);
|
|
|
|
struct lpass_variant *v = drvdata->variant;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < v->va_irq_ports; ++i) {
|
|
|
|
if (reg == LPAIF_VA_IRQCLEAR_REG(v, i))
|
|
|
|
return true;
|
|
|
|
if (reg == LPAIF_VA_IRQSTAT_REG(v, i))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < v->va_wrdma_channels; ++i) {
|
|
|
|
if (reg == LPAIF_CDC_VA_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
|
|
|
|
LPASS_CDC_DMA_VA_TX0))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct regmap_config lpass_rxtx_regmap_config = {
|
|
|
|
.reg_bits = 32,
|
|
|
|
.reg_stride = 4,
|
|
|
|
.val_bits = 32,
|
|
|
|
.writeable_reg = lpass_rxtx_regmap_writeable,
|
|
|
|
.readable_reg = lpass_rxtx_regmap_readable,
|
|
|
|
.volatile_reg = lpass_rxtx_regmap_volatile,
|
|
|
|
.cache_type = REGCACHE_FLAT,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct regmap_config lpass_va_regmap_config = {
|
|
|
|
.reg_bits = 32,
|
|
|
|
.reg_stride = 4,
|
|
|
|
.val_bits = 32,
|
|
|
|
.writeable_reg = lpass_va_regmap_writeable,
|
|
|
|
.readable_reg = lpass_va_regmap_readable,
|
|
|
|
.volatile_reg = lpass_va_regmap_volatile,
|
|
|
|
.cache_type = REGCACHE_FLAT,
|
|
|
|
};
|
|
|
|
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
|
|
|
|
struct device_node *node,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
unsigned int lines[LPASS_CPU_MAX_MI2S_LINES];
|
|
|
|
unsigned int sd_line_mask = 0;
|
|
|
|
int num_lines, i;
|
|
|
|
|
|
|
|
num_lines = of_property_read_variable_u32_array(node, name, lines, 0,
|
|
|
|
LPASS_CPU_MAX_MI2S_LINES);
|
|
|
|
if (num_lines < 0)
|
|
|
|
return LPAIF_I2SCTL_MODE_NONE;
|
|
|
|
|
|
|
|
for (i = 0; i < num_lines; i++)
|
|
|
|
sd_line_mask |= BIT(lines[i]);
|
|
|
|
|
|
|
|
switch (sd_line_mask) {
|
|
|
|
case LPASS_CPU_I2S_SD0_MASK:
|
|
|
|
return LPAIF_I2SCTL_MODE_SD0;
|
|
|
|
case LPASS_CPU_I2S_SD1_MASK:
|
|
|
|
return LPAIF_I2SCTL_MODE_SD1;
|
|
|
|
case LPASS_CPU_I2S_SD2_MASK:
|
|
|
|
return LPAIF_I2SCTL_MODE_SD2;
|
|
|
|
case LPASS_CPU_I2S_SD3_MASK:
|
|
|
|
return LPAIF_I2SCTL_MODE_SD3;
|
|
|
|
case LPASS_CPU_I2S_SD0_1_MASK:
|
|
|
|
return LPAIF_I2SCTL_MODE_QUAD01;
|
|
|
|
case LPASS_CPU_I2S_SD2_3_MASK:
|
|
|
|
return LPAIF_I2SCTL_MODE_QUAD23;
|
|
|
|
case LPASS_CPU_I2S_SD0_1_2_MASK:
|
|
|
|
return LPAIF_I2SCTL_MODE_6CH;
|
|
|
|
case LPASS_CPU_I2S_SD0_1_2_3_MASK:
|
|
|
|
return LPAIF_I2SCTL_MODE_8CH;
|
|
|
|
default:
|
|
|
|
dev_err(dev, "Unsupported SD line mask: %#x\n", sd_line_mask);
|
|
|
|
return LPAIF_I2SCTL_MODE_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void of_lpass_cpu_parse_dai_data(struct device *dev,
|
|
|
|
struct lpass_data *data)
|
|
|
|
{
|
|
|
|
struct device_node *node;
|
|
|
|
int ret, id;
|
|
|
|
|
|
|
|
/* Allow all channels by default for backwards compatibility */
|
|
|
|
for (id = 0; id < data->variant->num_dai; id++) {
|
|
|
|
data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
|
|
|
|
data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
|
|
|
|
}
|
|
|
|
|
|
|
|
for_each_child_of_node(dev->of_node, node) {
|
|
|
|
ret = of_property_read_u32(node, "reg", &id);
|
2021-03-11 15:45:57 +00:00
|
|
|
if (ret || id < 0) {
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
dev_err(dev, "valid dai id not found: %d\n", ret);
|
|
|
|
continue;
|
|
|
|
}
|
2020-10-08 05:17:01 +00:00
|
|
|
if (id == LPASS_DP_RX) {
|
|
|
|
data->hdmi_port_enable = 1;
|
2022-02-24 15:33:44 +00:00
|
|
|
} else if (is_cdc_dma_port(id)) {
|
|
|
|
data->codec_dma_enable = 1;
|
2020-10-08 05:17:01 +00:00
|
|
|
} else {
|
|
|
|
data->mi2s_playback_sd_mode[id] =
|
|
|
|
of_lpass_cpu_parse_sd_lines(dev, node,
|
|
|
|
"qcom,playback-sd-lines");
|
|
|
|
data->mi2s_capture_sd_mode[id] =
|
|
|
|
of_lpass_cpu_parse_sd_lines(dev, node,
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
"qcom,capture-sd-lines");
|
2020-10-08 05:17:01 +00:00
|
|
|
}
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-24 15:33:44 +00:00
|
|
|
static int of_lpass_cdc_dma_clks_parse(struct device *dev,
|
|
|
|
struct lpass_data *data)
|
|
|
|
{
|
|
|
|
data->codec_mem0 = devm_clk_get(dev, "audio_cc_codec_mem0");
|
|
|
|
if (IS_ERR(data->codec_mem0))
|
|
|
|
return PTR_ERR(data->codec_mem0);
|
|
|
|
|
|
|
|
data->codec_mem1 = devm_clk_get(dev, "audio_cc_codec_mem1");
|
|
|
|
if (IS_ERR(data->codec_mem1))
|
|
|
|
return PTR_ERR(data->codec_mem1);
|
|
|
|
|
|
|
|
data->codec_mem2 = devm_clk_get(dev, "audio_cc_codec_mem2");
|
|
|
|
if (IS_ERR(data->codec_mem2))
|
|
|
|
return PTR_ERR(data->codec_mem2);
|
|
|
|
|
|
|
|
data->va_mem0 = devm_clk_get(dev, "aon_cc_va_mem0");
|
|
|
|
if (IS_ERR(data->va_mem0))
|
|
|
|
return PTR_ERR(data->va_mem0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
|
2015-03-04 00:21:54 +00:00
|
|
|
{
|
2015-03-13 07:54:17 +00:00
|
|
|
struct lpass_data *drvdata;
|
2015-03-04 00:21:54 +00:00
|
|
|
struct device_node *dsp_of_node;
|
2022-02-24 15:33:44 +00:00
|
|
|
struct resource *res;
|
2015-05-16 12:32:17 +00:00
|
|
|
struct lpass_variant *variant;
|
|
|
|
struct device *dev = &pdev->dev;
|
|
|
|
const struct of_device_id *match;
|
2015-05-21 21:52:49 +00:00
|
|
|
int ret, i, dai_id;
|
2015-03-04 00:21:54 +00:00
|
|
|
|
2015-03-13 07:54:17 +00:00
|
|
|
dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
|
|
|
|
if (dsp_of_node) {
|
2020-05-04 06:59:47 +00:00
|
|
|
dev_err(dev, "DSP exists and holds audio resources\n");
|
2015-03-04 00:21:54 +00:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2020-05-04 06:59:47 +00:00
|
|
|
drvdata = devm_kzalloc(dev, sizeof(struct lpass_data), GFP_KERNEL);
|
2015-03-04 00:21:54 +00:00
|
|
|
if (!drvdata)
|
|
|
|
return -ENOMEM;
|
|
|
|
platform_set_drvdata(pdev, drvdata);
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
match = of_match_device(dev->driver->of_match_table, dev);
|
|
|
|
if (!match || !match->data)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
drvdata->variant = (struct lpass_variant *)match->data;
|
|
|
|
variant = drvdata->variant;
|
|
|
|
|
ASoC: qcom: lpass-cpu: Make I2S SD lines configurable
The LPASS hardware allows configuring the MI2S SD lines to use
when playing/recording audio. However, at the moment the lpass-cpu
driver has SD0 hard-coded for mono/stereo (or additional fixed
SD lines for more channels).
For weird reasons there seems to be hardware that uses one of the
other SD lines for mono/stereo. For example, some Samsung devices
use an external Speaker amplifier connected to Quaternary MI2S.
For some reason, the SD line for audio playback was connected to
SD1 rather than SD0. (I have no idea why...)
At the moment, the lpass-cpu driver cannot be configured to work
for the Speaker on these devices.
The q6afe driver already allows configuring the MI2S SD lines
through the "qcom,sd-lines" device tree property, but this works
only when routing audio through the ADSP.
This commit adds a very similar configuration for the lpass-cpu driver.
It is now possible to add additional subnodes to the lpass device in
the device tree, to configure the SD lines for playback and/or capture.
E.g. for the Samsung devices mentioned above:
&lpass {
dai@3 {
reg = <MI2S_QUATERNARY>;
qcom,playback-sd-lines = <1>;
};
};
qcom,playback/capture-sd-lines takes a list of SD lines (0-3)
in the same format as the q6afe driver. (The difference here is that
q6afe has separate DAIs for playback/capture, while lpass-cpu has one
for both...)
For backwards compatibility with older device trees, the lpass-cpu driver
defaults to LPAIF_I2SCTL_MODE_8CH if the subnode for a DAI is missing.
This is equivalent to the previous behavior: Up to 8 channels can be
configured, and SD0/QUAT01 will be chosen when setting up a stream
with fewer channels.
This allows the speaker to work on Samsung MSM8916 devices
that use an external speaker amplifier.
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20200425184657.121991-2-stephan@gerhold.net
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-04-25 18:46:57 +00:00
|
|
|
of_lpass_cpu_parse_dai_data(dev, drvdata);
|
|
|
|
|
2022-02-24 15:33:44 +00:00
|
|
|
if (drvdata->codec_dma_enable) {
|
|
|
|
drvdata->rxtx_lpaif =
|
|
|
|
devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
|
|
|
|
if (IS_ERR(drvdata->rxtx_lpaif))
|
|
|
|
return PTR_ERR(drvdata->rxtx_lpaif);
|
|
|
|
|
|
|
|
drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
|
|
|
|
if (IS_ERR(drvdata->va_lpaif))
|
|
|
|
return PTR_ERR(drvdata->va_lpaif);
|
|
|
|
|
|
|
|
lpass_rxtx_regmap_config.max_register = LPAIF_CDC_RXTX_WRDMAPER_REG(variant,
|
|
|
|
variant->rxtx_wrdma_channels +
|
|
|
|
variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
|
|
|
|
|
|
|
|
drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
|
|
|
|
&lpass_rxtx_regmap_config);
|
|
|
|
if (IS_ERR(drvdata->rxtx_lpaif_map))
|
|
|
|
return PTR_ERR(drvdata->rxtx_lpaif_map);
|
|
|
|
|
|
|
|
lpass_va_regmap_config.max_register = LPAIF_CDC_VA_WRDMAPER_REG(variant,
|
|
|
|
variant->va_wrdma_channels +
|
|
|
|
variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
|
|
|
|
|
|
|
|
drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
|
|
|
|
&lpass_va_regmap_config);
|
|
|
|
if (IS_ERR(drvdata->va_lpaif_map))
|
|
|
|
return PTR_ERR(drvdata->va_lpaif_map);
|
|
|
|
|
|
|
|
ret = of_lpass_cdc_dma_clks_parse(dev, drvdata);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dev, "failed to get cdc dma clocks %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
|
|
|
|
drvdata->rxtx_cdc_dma_lpm_buf = res->start;
|
|
|
|
|
|
|
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
|
|
|
|
drvdata->va_cdc_dma_lpm_buf = res->start;
|
|
|
|
}
|
|
|
|
|
2021-06-15 14:07:11 +00:00
|
|
|
drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
|
2021-01-15 03:43:27 +00:00
|
|
|
if (IS_ERR(drvdata->lpaif))
|
2021-01-15 03:43:26 +00:00
|
|
|
return PTR_ERR(drvdata->lpaif);
|
2015-03-04 00:21:54 +00:00
|
|
|
|
2016-02-11 12:18:27 +00:00
|
|
|
lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant,
|
|
|
|
variant->wrdma_channels +
|
|
|
|
variant->wrdma_channel_start);
|
2015-05-16 12:32:17 +00:00
|
|
|
|
2020-05-04 06:59:47 +00:00
|
|
|
drvdata->lpaif_map = devm_regmap_init_mmio(dev, drvdata->lpaif,
|
2015-03-04 00:21:54 +00:00
|
|
|
&lpass_cpu_regmap_config);
|
|
|
|
if (IS_ERR(drvdata->lpaif_map)) {
|
2020-05-04 06:59:47 +00:00
|
|
|
dev_err(dev, "error initializing regmap: %ld\n",
|
2017-01-30 21:03:37 +00:00
|
|
|
PTR_ERR(drvdata->lpaif_map));
|
2015-03-04 00:21:54 +00:00
|
|
|
return PTR_ERR(drvdata->lpaif_map);
|
|
|
|
}
|
|
|
|
|
2020-10-08 05:17:01 +00:00
|
|
|
if (drvdata->hdmi_port_enable) {
|
2021-06-15 14:07:11 +00:00
|
|
|
drvdata->hdmiif = devm_platform_ioremap_resource_byname(pdev, "lpass-hdmiif");
|
2021-01-15 03:43:27 +00:00
|
|
|
if (IS_ERR(drvdata->hdmiif))
|
2021-01-15 03:43:26 +00:00
|
|
|
return PTR_ERR(drvdata->hdmiif);
|
2020-10-08 05:17:01 +00:00
|
|
|
|
|
|
|
lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
|
2021-02-02 06:27:27 +00:00
|
|
|
variant->hdmi_rdma_channels - 1);
|
2020-10-08 05:17:01 +00:00
|
|
|
drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
|
|
|
|
&lpass_hdmi_regmap_config);
|
|
|
|
if (IS_ERR(drvdata->hdmiif_map)) {
|
|
|
|
dev_err(dev, "error initializing regmap: %ld\n",
|
|
|
|
PTR_ERR(drvdata->hdmiif_map));
|
|
|
|
return PTR_ERR(drvdata->hdmiif_map);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-14 10:52:58 +00:00
|
|
|
if (variant->init) {
|
|
|
|
ret = variant->init(pdev);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dev, "error initializing variant: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2015-05-16 12:32:17 +00:00
|
|
|
|
2015-05-21 21:52:49 +00:00
|
|
|
for (i = 0; i < variant->num_dai; i++) {
|
|
|
|
dai_id = variant->dai_driver[i].id;
|
2022-02-24 15:33:44 +00:00
|
|
|
if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
|
2020-10-08 05:17:01 +00:00
|
|
|
continue;
|
|
|
|
|
2021-05-20 01:48:07 +00:00
|
|
|
drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
|
2017-04-05 08:34:10 +00:00
|
|
|
variant->dai_osr_clk_names[i]);
|
2020-05-04 06:59:47 +00:00
|
|
|
drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(dev,
|
2017-04-05 08:34:10 +00:00
|
|
|
variant->dai_bit_clk_names[i]);
|
2015-05-21 21:52:49 +00:00
|
|
|
if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
|
2020-05-04 06:59:47 +00:00
|
|
|
dev_err(dev,
|
2017-04-05 08:34:10 +00:00
|
|
|
"error getting %s: %ld\n",
|
|
|
|
variant->dai_bit_clk_names[i],
|
2015-09-17 08:47:33 +00:00
|
|
|
PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
|
2015-05-21 21:52:49 +00:00
|
|
|
return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
|
|
|
|
}
|
2021-06-09 13:30:39 +00:00
|
|
|
if (drvdata->mi2s_playback_sd_mode[dai_id] ==
|
|
|
|
LPAIF_I2SCTL_MODE_QUAD01) {
|
|
|
|
variant->dai_driver[dai_id].playback.channels_min = 4;
|
|
|
|
variant->dai_driver[dai_id].playback.channels_max = 4;
|
|
|
|
}
|
2015-03-04 00:21:54 +00:00
|
|
|
}
|
|
|
|
|
2020-08-14 10:53:01 +00:00
|
|
|
/* Allocation for i2sctl regmap fields */
|
|
|
|
drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
|
|
|
/* Initialize bitfields for dai I2SCTL register */
|
|
|
|
ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
|
|
|
|
drvdata->lpaif_map);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dev, "error init i2sctl field: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-10-08 05:17:01 +00:00
|
|
|
if (drvdata->hdmi_port_enable) {
|
|
|
|
ret = lpass_hdmi_init_bitfields(dev, drvdata->hdmiif_map);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(dev, "%s error hdmi init failed\n", __func__);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2020-05-04 06:59:47 +00:00
|
|
|
ret = devm_snd_soc_register_component(dev,
|
2015-05-16 12:32:17 +00:00
|
|
|
&lpass_cpu_comp_driver,
|
|
|
|
variant->dai_driver,
|
|
|
|
variant->num_dai);
|
2015-03-04 00:21:54 +00:00
|
|
|
if (ret) {
|
2020-05-04 06:59:47 +00:00
|
|
|
dev_err(dev, "error registering cpu driver: %d\n", ret);
|
2020-08-14 10:52:58 +00:00
|
|
|
goto err;
|
2015-03-04 00:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = asoc_qcom_lpass_platform_register(pdev);
|
|
|
|
if (ret) {
|
2020-05-04 06:59:47 +00:00
|
|
|
dev_err(dev, "error registering platform driver: %d\n", ret);
|
2020-08-14 10:52:58 +00:00
|
|
|
goto err;
|
2015-03-04 00:21:54 +00:00
|
|
|
}
|
|
|
|
|
2020-08-14 10:52:58 +00:00
|
|
|
err:
|
2015-03-04 00:21:54 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2015-05-16 12:32:17 +00:00
|
|
|
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
|
2015-03-04 00:21:54 +00:00
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
|
2015-03-04 00:21:54 +00:00
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = platform_get_drvdata(pdev);
|
|
|
|
|
2015-05-16 12:32:17 +00:00
|
|
|
if (drvdata->variant->exit)
|
|
|
|
drvdata->variant->exit(pdev);
|
|
|
|
|
2015-03-04 00:21:54 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-05-16 12:32:17 +00:00
|
|
|
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
|
2016-10-31 11:25:45 +00:00
|
|
|
|
2020-11-13 18:38:22 +00:00
|
|
|
void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct lpass_data *drvdata = platform_get_drvdata(pdev);
|
|
|
|
|
|
|
|
if (drvdata->variant->exit)
|
|
|
|
drvdata->variant->exit(pdev);
|
|
|
|
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown);
|
|
|
|
|
2016-10-31 11:25:45 +00:00
|
|
|
MODULE_DESCRIPTION("QTi LPASS CPU Driver");
|
|
|
|
MODULE_LICENSE("GPL v2");
|