| From e1a00b5b253a4f97216b9a33199a863987075162 Mon Sep 17 00:00:00 2001 |
| From: Takashi Sakamoto <o-takashi@sakamocchi.jp> |
| Date: Tue, 10 Sep 2019 22:51:52 +0900 |
| Subject: ALSA: firewire-tascam: check intermediate state of clock status and retry |
| |
| From: Takashi Sakamoto <o-takashi@sakamocchi.jp> |
| |
| commit e1a00b5b253a4f97216b9a33199a863987075162 upstream. |
| |
| 2 bytes in MSB of register for clock status is zero during intermediate |
| state after changing status of sampling clock in models of TASCAM FireWire |
| series. The duration of this state differs depending on cases. During the |
| state, it's better to retry reading the register for current status of |
| the clock. |
| |
| In current implementation, the intermediate state is checked only when |
| getting current sampling transmission frequency, then retry reading. |
| This care is required for the other operations to read the register. |
| |
| This commit moves the codes of check and retry into helper function |
| commonly used for operations to read the register. |
| |
| Fixes: e453df44f0d6 ("ALSA: firewire-tascam: add PCM functionality") |
| Cc: <stable@vger.kernel.org> # v4.4+ |
| Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> |
| Link: https://lore.kernel.org/r/20190910135152.29800-3-o-takashi@sakamocchi.jp |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/firewire/tascam/tascam-stream.c | 42 ++++++++++++++++++++++------------ |
| 1 file changed, 28 insertions(+), 14 deletions(-) |
| |
| --- a/sound/firewire/tascam/tascam-stream.c |
| +++ b/sound/firewire/tascam/tascam-stream.c |
| @@ -9,20 +9,37 @@ |
| #include <linux/delay.h> |
| #include "tascam.h" |
| |
| +#define CLOCK_STATUS_MASK 0xffff0000 |
| +#define CLOCK_CONFIG_MASK 0x0000ffff |
| + |
| #define CALLBACK_TIMEOUT 500 |
| |
| static int get_clock(struct snd_tscm *tscm, u32 *data) |
| { |
| + int trial = 0; |
| __be32 reg; |
| int err; |
| |
| - err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST, |
| - TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS, |
| - ®, sizeof(reg), 0); |
| - if (err >= 0) |
| + while (trial++ < 5) { |
| + err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST, |
| + TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS, |
| + ®, sizeof(reg), 0); |
| + if (err < 0) |
| + return err; |
| + |
| *data = be32_to_cpu(reg); |
| + if (*data & CLOCK_STATUS_MASK) |
| + break; |
| + |
| + // In intermediate state after changing clock status. |
| + msleep(50); |
| + } |
| |
| - return err; |
| + // Still in the intermediate state. |
| + if (trial >= 5) |
| + return -EAGAIN; |
| + |
| + return 0; |
| } |
| |
| static int set_clock(struct snd_tscm *tscm, unsigned int rate, |
| @@ -35,7 +52,7 @@ static int set_clock(struct snd_tscm *ts |
| err = get_clock(tscm, &data); |
| if (err < 0) |
| return err; |
| - data &= 0x0000ffff; |
| + data &= CLOCK_CONFIG_MASK; |
| |
| if (rate > 0) { |
| data &= 0x000000ff; |
| @@ -80,17 +97,14 @@ static int set_clock(struct snd_tscm *ts |
| |
| int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate) |
| { |
| - u32 data = 0x0; |
| - unsigned int trials = 0; |
| + u32 data; |
| int err; |
| |
| - while (data == 0x0 || trials++ < 5) { |
| - err = get_clock(tscm, &data); |
| - if (err < 0) |
| - return err; |
| + err = get_clock(tscm, &data); |
| + if (err < 0) |
| + return err; |
| |
| - data = (data & 0xff000000) >> 24; |
| - } |
| + data = (data & 0xff000000) >> 24; |
| |
| /* Check base rate. */ |
| if ((data & 0x0f) == 0x01) |