Skip to content

bcm2835-audio: Backport upstream commits #2948

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 44 commits into from
Apr 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
126b2ed
Revert "bcm2835: interpolate audio delay"
popcornmix Apr 29, 2019
5924be6
Revert "staging: bcm2835-audio: Enable compile test"
popcornmix Apr 29, 2019
7dcce97
Revert "staging: bcm2835-audio: use module_platform_driver() macro"
popcornmix Apr 29, 2019
3c7c70f
staging: bcm2835-audio: Clean up mutex locks
tiwai Sep 4, 2018
19b8715
staging: bcm2835-audio: Remove redundant spdif stream ctls
tiwai Sep 4, 2018
c683dfb
staging: bcm2835-audio: Clean up include files in bcm2835-ctl.c
tiwai Sep 4, 2018
f865f02
staging: bcm2835-audio: Remove redundant substream mask checks
tiwai Sep 4, 2018
191cf50
staging: bcm2835-audio: Fix mute controls, volume handling cleanup
tiwai Sep 4, 2018
13630e7
staging: bcm2835-audio: Remove redundant function calls
tiwai Sep 4, 2018
cf559a6
staging: bcm2835-audio: Remove superfluous open flag
tiwai Sep 4, 2018
34a41da
staging: bcm2835-audio: Drop useless running flag and check
tiwai Sep 4, 2018
5a3470e
staging: bcm2835-audio: Fix incorrect draining handling
tiwai Sep 4, 2018
e88a687
staging: bcm2835-audio: Kill unused spinlock
tiwai Sep 4, 2018
fe0a549
staging: bcm2835-audio: Use PCM runtime values instead
tiwai Sep 4, 2018
7b220ed
staging: bcm2835-audio: Drop unnecessary pcm indirect setup
tiwai Sep 4, 2018
3b6340c
staging: bcm2835-audio: Drop useless NULL check
tiwai Sep 4, 2018
7cf7818
staging: bcm2835-audio: Propagate parameter setup error
tiwai Sep 4, 2018
6b62164
staging: bcm2835-audio: Drop debug messages in bcm2835-pcm.c
tiwai Sep 4, 2018
48f2ec3
staging: bcm2835-audio: Drop superfluous mutex lock during prepare
tiwai Sep 4, 2018
607328a
staging: bcm2835-audio: Add 10ms period constraint
tiwai Sep 4, 2018
1e33528
staging: bcm2835-audio: Make single vchi handle
tiwai Sep 4, 2018
1e33d5e
staging: bcm2835-audio: Code refactoring of vchiq accessor codes
tiwai Sep 4, 2018
9aa8fef
staging: bcm2835-audio: Operate non-atomic PCM ops
tiwai Sep 4, 2018
64e0a53
staging: bcm2835-audio: Use card->private_data
tiwai Sep 4, 2018
b21cf54
staging: bcm2835-audio: Use standard error print helpers
tiwai Sep 4, 2018
df54f1a
staging: bcm2835-audio: Remove unnecessary header file includes
tiwai Sep 4, 2018
2eeb586
staging: bcm2835-audio: Move module parameter description
tiwai Sep 4, 2018
d0bd18f
staging: bcm2835-audio: Use coherent device buffers
tiwai Sep 4, 2018
ad1baeb
staging: bcm2835-audio: Set SNDRV_PCM_INFO_SYNC_APPLPTR
tiwai Sep 4, 2018
e054cc5
staging: bcm2835-audio: Simplify PCM creation helpers
tiwai Sep 4, 2018
196c5ee
staging: bcm2835-audio: Simplify kctl creation helpers
tiwai Sep 4, 2018
37bed09
staging: bcm2835-audio: Simplify card object management
tiwai Sep 4, 2018
6b0d0cf
staging: bcm2835-audio: unify FOURCC command definitions
Oct 17, 2018
af98ced
staging: bcm2835-audio: don't initialize memory twice
Oct 17, 2018
768b85f
staging: bcm2835-audio: reorder variable declarations & remove trivia…
Oct 17, 2018
c773e7e
staging: bcm2835-audio: use anonymous union in struct vc_audio_msg
Oct 17, 2018
4ee1f90
staging: bcm2835-audio: more generic probe function name
Oct 17, 2018
5c1043f
staging: bcm2835-audio: rename platform_driver structure
Oct 17, 2018
bb45b7e
staging: bcm2835-audio: update TODO
Oct 17, 2018
9ec974f
staging: bcm2835-audio: interpolate audio delay
mikebrady Oct 22, 2018
d09f55f
staging: bcm2835-audio: Enable compile test
lategoodbye Dec 6, 2018
0a734ff
staging: bcm2835-audio: use module_platform_driver() macro
lategoodbye Dec 6, 2018
bb93ffc
staging: bcm2835-audio: Drop DT dependency
lategoodbye Dec 6, 2018
85c603a
staging: bcm2835-audio: double free in init error path
Dec 17, 2018
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
25 changes: 3 additions & 22 deletions drivers/staging/vc04_services/bcm2835-audio/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,7 @@
* *
*****************************************************************************

1) Revisit multi-cards options and PCM route mixer control (as per comment
https://lkml.org/lkml/2018/9/8/200)

1) Document the device tree node

The downstream tree(the tree that the driver was imported from) at
http://www.github.com/raspberrypi/linux uses this node:

audio: audio {
compatible = "brcm,bcm2835-audio";
brcm,pwm-channels = <8>;
};

Since the driver requires the use of VCHIQ, it may be useful to have a link
in the device tree to the VCHIQ driver.

2) Gracefully handle the case where VCHIQ is missing from the device tree or
it has not been initialized yet.

3) Review error handling and remove duplicate code.

4) Cleanup the logging mechanism. The driver should probably be using the
standard kernel logging mechanisms such as dev_info, dev_dbg, and friends.

5) Fix the remaining checkpatch.pl errors and warnings.
2) Fix the remaining checkpatch.pl errors and warnings.
235 changes: 61 additions & 174 deletions drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2011 Broadcom Corporation. All rights reserved. */

#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>

#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/rawmidi.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/asoundef.h>

Expand All @@ -27,6 +12,21 @@
#define CTRL_VOL_MAX 400
#define CTRL_VOL_MIN -10239 /* originally -10240 */

static int bcm2835_audio_set_chip_ctls(struct bcm2835_chip *chip)
{
int i, err = 0;

/* change ctls for all substreams */
for (i = 0; i < MAX_SUBSTREAMS; i++) {
if (chip->alsa_stream[i]) {
err = bcm2835_audio_set_ctls(chip->alsa_stream[i]);
if (err < 0)
break;
}
}
return err;
}

static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
Expand All @@ -49,41 +49,15 @@ static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
return 0;
}

/* toggles mute on or off depending on the value of nmute, and returns
* 1 if the mute value was changed, otherwise 0
*/
static int toggle_mute(struct bcm2835_chip *chip, int nmute)
{
/* if settings are ok, just return 0 */
if (chip->mute == nmute)
return 0;

/* if the sound is muted then we need to unmute */
if (chip->mute == CTRL_VOL_MUTE) {
chip->volume = chip->old_volume; /* copy the old volume back */
audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
} else /* otherwise we mute */ {
chip->old_volume = chip->volume;
chip->volume = 26214; /* set volume to minimum level AKA mute */
audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
}

chip->mute = nmute;
return 1;
}

static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);

if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;

BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
mutex_lock(&chip->audio_mutex);

if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
ucontrol->value.integer.value[0] = chip->volume;
else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
ucontrol->value.integer.value[0] = chip->mute;
else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
Expand All @@ -97,79 +71,60 @@ static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
int val, *valp;
int changed = 0;

if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;

if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
if (chip->mute == CTRL_VOL_MUTE) {
/* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
goto unlock;
}
if (changed || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
changed = 1;
}

} else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
/* Now implemented */
audio_info(" Mute attempted\n");
changed = toggle_mute(chip, ucontrol->value.integer.value[0]);

} else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
if (ucontrol->value.integer.value[0] != chip->dest) {
chip->dest = ucontrol->value.integer.value[0];
changed = 1;
}
if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
valp = &chip->volume;
else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
valp = &chip->mute;
else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
valp = &chip->dest;
else
return -EINVAL;

val = ucontrol->value.integer.value[0];
mutex_lock(&chip->audio_mutex);
if (val != *valp) {
*valp = val;
changed = 1;
if (bcm2835_audio_set_chip_ctls(chip))
dev_err(chip->card->dev, "Failed to set ALSA controls..\n");
}

if (changed && bcm2835_audio_set_ctls(chip))
dev_err(chip->card->dev, "Failed to set ALSA controls..\n");

unlock:
mutex_unlock(&chip->audio_mutex);
return changed;
}

static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);

static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
static const struct snd_kcontrol_new snd_bcm2835_ctl[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Volume",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.private_value = PCM_PLAYBACK_VOLUME,
.info = snd_bcm2835_ctl_info,
.get = snd_bcm2835_ctl_get,
.put = snd_bcm2835_ctl_put,
.count = 1,
.tlv = {.p = snd_bcm2835_db_scale}
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = PCM_PLAYBACK_MUTE,
.info = snd_bcm2835_ctl_info,
.get = snd_bcm2835_ctl_get,
.put = snd_bcm2835_ctl_put,
.count = 1,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Route",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = PCM_PLAYBACK_DEVICE,
.info = snd_bcm2835_ctl_info,
.get = snd_bcm2835_ctl_get,
.put = snd_bcm2835_ctl_put,
.count = 1,
},
};

Expand All @@ -187,8 +142,7 @@ static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
int i;

if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
mutex_lock(&chip->audio_mutex);

for (i = 0; i < 4; i++)
ucontrol->value.iec958.status[i] =
Expand All @@ -205,8 +159,7 @@ static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
unsigned int val = 0;
int i, change;

if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;
mutex_lock(&chip->audio_mutex);

for (i = 0; i < 4; i++)
val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
Expand Down Expand Up @@ -237,51 +190,7 @@ static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
return 0;
}

static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}

static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
int i;

if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;

for (i = 0; i < 4; i++)
ucontrol->value.iec958.status[i] =
(chip->spdif_status >> (i * 8)) & 0xff;

mutex_unlock(&chip->audio_mutex);
return 0;
}

static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
unsigned int val = 0;
int i, change;

if (mutex_lock_interruptible(&chip->audio_mutex))
return -EINTR;

for (i = 0; i < 4; i++)
val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
change = val != chip->spdif_status;
chip->spdif_status = val;

mutex_unlock(&chip->audio_mutex);
return change;
}

static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
static const struct snd_kcontrol_new snd_bcm2835_spdif[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
Expand All @@ -296,39 +205,34 @@ static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
.info = snd_bcm2835_spdif_mask_info,
.get = snd_bcm2835_spdif_mask_get,
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
.info = snd_bcm2835_spdif_stream_info,
.get = snd_bcm2835_spdif_stream_get,
.put = snd_bcm2835_spdif_stream_put,
},
};

int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
static int create_ctls(struct bcm2835_chip *chip, size_t size,
const struct snd_kcontrol_new *kctls)
{
int err;
unsigned int idx;
int i, err;

strcpy(chip->card->mixername, "Broadcom Mixer");
for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
err = snd_ctl_add(chip->card,
snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
if (err < 0)
return err;
}
for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
err = snd_ctl_add(chip->card,
snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
for (i = 0; i < size; i++) {
err = snd_ctl_add(chip->card, snd_ctl_new1(&kctls[i], chip));
if (err < 0)
return err;
}
return 0;
}

static struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
{
int err;

strcpy(chip->card->mixername, "Broadcom Mixer");
err = create_ctls(chip, ARRAY_SIZE(snd_bcm2835_ctl), snd_bcm2835_ctl);
if (err < 0)
return err;
return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_spdif),
snd_bcm2835_spdif);
}

static const struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Headphone Playback Volume",
Expand Down Expand Up @@ -357,21 +261,12 @@ static struct snd_kcontrol_new snd_bcm2835_headphones_ctl[] = {

int snd_bcm2835_new_headphones_ctl(struct bcm2835_chip *chip)
{
int err;
unsigned int idx;

strcpy(chip->card->mixername, "Broadcom Mixer");
for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_headphones_ctl); idx++) {
err = snd_ctl_add(chip->card,
snd_ctl_new1(&snd_bcm2835_headphones_ctl[idx],
chip));
if (err)
return err;
}
return 0;
return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_headphones_ctl),
snd_bcm2835_headphones_ctl);
}

static struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
static const struct snd_kcontrol_new snd_bcm2835_hdmi[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "HDMI Playback Volume",
Expand Down Expand Up @@ -400,16 +295,8 @@ static struct snd_kcontrol_new snd_bcm2835_hdmi[] = {

int snd_bcm2835_new_hdmi_ctl(struct bcm2835_chip *chip)
{
int err;
unsigned int idx;

strcpy(chip->card->mixername, "Broadcom Mixer");
for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_hdmi); idx++) {
err = snd_ctl_add(chip->card,
snd_ctl_new1(&snd_bcm2835_hdmi[idx], chip));
if (err)
return err;
}
return 0;
return create_ctls(chip, ARRAY_SIZE(snd_bcm2835_hdmi),
snd_bcm2835_hdmi);
}

Loading