Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2000000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-always-on; //FIXME: DVDD AW88261
};

vreg_l19b: ldo19 {
Expand Down Expand Up @@ -620,7 +621,7 @@

vreg_bob: bob {
regulator-name = "vreg_bob";
regulator-min-microvolt = <3008000>;
regulator-min-microvolt = <3150000>;
regulator-max-microvolt = <3960000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
};
Expand Down Expand Up @@ -1287,11 +1288,22 @@

status = "okay";
};

&q6afedai {
dai@127 {
reg = <QUINARY_MI2S_RX>;
qcom,sd-lines = <0>;
};
};

&sound {
compatible = "fairphone,fp5-sndcard";
model = "Fairphone 5";

pinctrl-0 = <&i2s1_active>;
pinctrl-1 = <&i2s1_sleep>;
pinctrl-names = "default", "sleep";

mm1-dai-link {
link-name = "MultiMedia1";

Expand All @@ -1300,6 +1312,23 @@
};
};

i2s-dai-link {
link-name = "I2S Playback";
cpu {
// From my understanding, the playback path to the amplifier is via GPIO152 / QUINARY_MI2S_RX.
// The amplifier also returns the audio (I2STXEN) via GPIO153 / QUINARY_MI2S_TX for echo-reference.
sound-dai = <&q6afedai QUINARY_MI2S_RX>;
};

platform {
sound-dai = <&q6routing>;
};

codec {
sound-dai = <&aw88261_l>, <&aw88261_r>;
};
};

displayport-rx-dai-link {
link-name = "DisplayPort Playback";

Expand Down Expand Up @@ -1478,6 +1507,8 @@
drive-strength = <2>;
bias-pull-up;
};


};

&uart5 {
Expand Down
54 changes: 54 additions & 0 deletions arch/arm64/boot/dts/qcom/sc7280.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -2845,6 +2845,8 @@
#clock-cells = <1>;
#power-domain-cells = <1>;
#reset-cells = <1>;

status = "reserved"; /* Owned by ADSP firmware */
};

lpass_va_macro: codec@3370000 {
Expand Down Expand Up @@ -3026,6 +3028,58 @@
bias-pull-down;
};

i2s1_active: i2s1-active-state {
clk {
pins = "gpio6";
function = "i2s1_clk";
drive-strength = <8>;
bias-disable;
output-high;
};

ws {
pins = "gpio7";
function = "i2s1_ws";
drive-strength = <8>;
bias-disable;
output-high;
};

data {
pins = "gpio8", "gpio9";
function = "i2s1_data";
drive-strength = <8>;
bias-disable;
output-high;
};
};

i2s1_sleep: i2s1-sleep-state {
clk {
pins = "gpio6";
function = "i2s1_clk";
drive-strength = <2>;
bias-pull-down;
input-enable;
};

ws {
pins = "gpio7";
function = "i2s1_ws";
drive-strength = <2>;
bias-pull-down;
input-enable;
};

data {
pins = "gpio8", "gpio9";
function = "i2s1_data";
drive-strength = <2>;
bias-pull-down;
input-enable;
};
};

lpass_rx_swr_clk: rx-swr-clk-state {
pins = "gpio3";
function = "swr_rx_clk";
Expand Down
109 changes: 105 additions & 4 deletions sound/soc/codecs/aw88261.c
Original file line number Diff line number Diff line change
Expand Up @@ -1129,9 +1129,24 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261)
return ret;
}

static int aw88261_append_channel_suffix(const char *format, const char **name, struct aw88261 *aw88261)
{
char buf[64];
int channel = aw88261->aw_pa->channel;

snprintf(buf, sizeof(buf), format, *name, channel);
(*name) = devm_kstrdup(aw88261->aw_pa->dev, buf, GFP_KERNEL);
if (!(*name))
return -ENOMEM;
return 0;
}

static int aw88261_codec_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct snd_soc_dapm_widget *dapm_widgets = NULL;
struct snd_soc_dapm_route *audio_map = NULL;
struct snd_kcontrol_new *controls = NULL;
struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
int ret;

Expand All @@ -1142,19 +1157,81 @@ static int aw88261_codec_probe(struct snd_soc_component *component)
return dev_err_probe(aw88261->aw_pa->dev, ret,
"aw88261_request_firmware_file failed\n");

/* rename dapm widgets to avoid clash between left and right amps */
dapm_widgets = devm_kzalloc(aw88261->aw_pa->dev,
sizeof(struct snd_soc_dapm_widget) * ARRAY_SIZE(aw88261_dapm_widgets),
GFP_KERNEL);
if (!dapm_widgets)
return dev_err_probe(aw88261->aw_pa->dev, -ENOMEM, "could not allocate memory for dapm widgets\n");

memcpy(dapm_widgets, aw88261_dapm_widgets, sizeof(struct snd_soc_dapm_widget) * ARRAY_SIZE(aw88261_dapm_widgets));

for (int i = 0; i < ARRAY_SIZE(aw88261_dapm_widgets); i++) {
if (dapm_widgets[i].name) {
ret = aw88261_append_channel_suffix("%s_%d", &dapm_widgets[i].name, aw88261);
if (ret)
return dev_err_probe(aw88261->aw_pa->dev, ret, "could not change widget name\n");
}
if (dapm_widgets[i].sname) {
ret = aw88261_append_channel_suffix("%s_%d", &dapm_widgets[i].sname, aw88261);
if (ret)
return dev_err_probe(aw88261->aw_pa->dev, ret, "could not change widget sname\n");
}
}

/* add widgets */
ret = snd_soc_dapm_new_controls(dapm, aw88261_dapm_widgets,
ret = snd_soc_dapm_new_controls(dapm, dapm_widgets,
ARRAY_SIZE(aw88261_dapm_widgets));
if (ret)
return ret;

/* rename dapm routes to avoid clash between left and right amps */
audio_map = devm_kzalloc(aw88261->aw_pa->dev,
sizeof(struct snd_soc_dapm_route) * ARRAY_SIZE(aw88261_audio_map),
GFP_KERNEL);
if (!audio_map)
return dev_err_probe(aw88261->aw_pa->dev, -ENOMEM, "could not allocate memory for dapm routes\n");

memcpy(audio_map, aw88261_audio_map, sizeof(struct snd_soc_dapm_route) * ARRAY_SIZE(aw88261_audio_map));

for (int i = 0; i < ARRAY_SIZE(aw88261_audio_map); i++) {
if (audio_map[i].sink) {
ret = aw88261_append_channel_suffix("%s_%d", &audio_map[i].sink, aw88261);
if (ret)
return dev_err_probe(aw88261->aw_pa->dev, ret, "could not change route sink\n");
}
if (audio_map[i].source) {
ret = aw88261_append_channel_suffix("%s_%d", &audio_map[i].source, aw88261);
if (ret)
return dev_err_probe(aw88261->aw_pa->dev, ret, "could not change route source\n");
}
}

/* add route */
ret = snd_soc_dapm_add_routes(dapm, aw88261_audio_map,
ret = snd_soc_dapm_add_routes(dapm, audio_map,
ARRAY_SIZE(aw88261_audio_map));
if (ret)
return ret;

ret = snd_soc_add_component_controls(component, aw88261_controls,

/* rename kcontrols to avoid clash between left and right amps */
controls = devm_kzalloc(aw88261->aw_pa->dev,
sizeof(struct snd_kcontrol_new) * ARRAY_SIZE(aw88261_controls),
GFP_KERNEL);
if (!controls)
return dev_err_probe(aw88261->aw_pa->dev, -ENOMEM, "could not allocate memory for kcontrols\n");

memcpy(controls, aw88261_controls, sizeof(struct snd_kcontrol_new) * ARRAY_SIZE(aw88261_controls));

for (int i = 0; i < ARRAY_SIZE(aw88261_controls); i++) {
if (controls[i].name) {
ret = aw88261_append_channel_suffix("%s %d", &controls[i].name, aw88261);
if (ret)
return dev_err_probe(aw88261->aw_pa->dev, ret, "could not change kcontrol name\n");
}
}

ret = snd_soc_add_component_controls(component, controls,
ARRAY_SIZE(aw88261_controls));

return ret;
Expand Down Expand Up @@ -1229,6 +1306,7 @@ static int aw88261_init(struct aw88261 **aw88261, struct i2c_client *i2c, struct
static int aw88261_i2c_probe(struct i2c_client *i2c)
{
struct aw88261 *aw88261;
struct snd_soc_dai_driver *dai = NULL;
int ret;

ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
Expand All @@ -1254,9 +1332,32 @@ static int aw88261_i2c_probe(struct i2c_client *i2c)
if (ret)
return ret;

/* rename dai drivers to avoid clashes between left and right amps */
dai = devm_kzalloc(aw88261->aw_pa->dev,
sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(aw88261_dai),
GFP_KERNEL);
if (!dai)
return dev_err_probe(&i2c->dev, -ENOMEM, "could not allocate memory for dai\n");

memcpy(dai, aw88261_dai, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(aw88261_dai));

for (int i = 0; i < ARRAY_SIZE(aw88261_dai); i++) {
ret = aw88261_append_channel_suffix("%s-%d", &dai[i].name, aw88261);
if (ret)
return dev_err_probe(&i2c->dev, ret, "could not change dai name\n");

ret = aw88261_append_channel_suffix("%s_%d", &dai[i].playback.stream_name, aw88261);
if (ret)
return dev_err_probe(&i2c->dev, ret, "could not change dai playback name\n");

ret = aw88261_append_channel_suffix("%s-%d", &dai[i].capture.stream_name, aw88261);
if (ret)
return dev_err_probe(&i2c->dev, ret, "could not change dai capture name\n");
}

ret = devm_snd_soc_register_component(&i2c->dev,
&soc_codec_dev_aw88261,
aw88261_dai, ARRAY_SIZE(aw88261_dai));
dai, ARRAY_SIZE(aw88261_dai));
if (ret)
dev_err(&i2c->dev, "failed to register aw88261: %d", ret);

Expand Down
24 changes: 10 additions & 14 deletions sound/soc/qcom/qdsp6/q6asm-dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ static const struct snd_pcm_hardware q6asm_dai_hardware_playback = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE),
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE),
.rates = SNDRV_PCM_RATE_8000_192000,
.rate_min = 8000,
.rate_max = 192000,
Expand All @@ -129,19 +130,13 @@ static const struct snd_pcm_hardware q6asm_dai_hardware_playback = {
#define Q6ASM_FEDAI_DRIVER(num) { \
.playback = { \
.stream_name = "MultiMedia"#num" Playback", \
.rates = (SNDRV_PCM_RATE_8000_48000 | \
SNDRV_PCM_RATE_12000 | \
SNDRV_PCM_RATE_24000 | \
SNDRV_PCM_RATE_88200 | \
SNDRV_PCM_RATE_96000 | \
SNDRV_PCM_RATE_176400 | \
SNDRV_PCM_RATE_192000), \
.formats = (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE), \
.channels_min = 1, \
.channels_max = 8, \
.rate_min = 8000, \
.rate_max = 192000, \
.rates = (SNDRV_PCM_RATE_48000| \
SNDRV_PCM_RATE_KNOT), \
.formats = (SNDRV_PCM_FMTBIT_S32_LE), \
.channels_min = 2, \
.channels_max = 2, \
.rate_min = 48000, \
.rate_max = 48000, \
}, \
.capture = { \
.stream_name = "MultiMedia"#num" Capture", \
Expand Down Expand Up @@ -480,6 +475,7 @@ static int q6asm_dai_hw_params(struct snd_soc_component *component,
case SNDRV_PCM_FORMAT_S16_LE:
prtd->bits_per_sample = 16;
break;
case SNDRV_PCM_FORMAT_S32_LE:
case SNDRV_PCM_FORMAT_S24_LE:
prtd->bits_per_sample = 24;
break;
Expand Down
5 changes: 5 additions & 0 deletions sound/soc/qcom/qdsp6/q6routing.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,9 @@ int q6routing_stream_open(int fedai_id, int perf_mode,
session->channels = pdata->channels;
session->bits_per_sample = pdata->bits_per_sample;

printk(KERN_ERR "[qdsp6] q6routing_stream_open: stream_id=%d, port_id=%d, channels=%d path_type=%d\n",
stream_id, session->port_id, session->channels, session->path_type);

payload.num_copps = 0; /* only RX needs to use payload */
topology = NULL_COPP_TOPOLOGY;
copp = q6adm_open(routing_data->dev, session->port_id,
Expand Down Expand Up @@ -1085,6 +1088,8 @@ static int routing_hw_params(struct snd_soc_component *component,
case SNDRV_PCM_FORMAT_S24_LE:
session->bits_per_sample = 24;
break;
case SNDRV_PCM_FORMAT_S32_LE:
session->bits_per_sample = 24;
default:
break;
}
Expand Down
Loading