0cc0f8848dfa2d1a6331ad8e8bc221b6e7425caf
[lede.git] / target / linux / brcm2708 / patches-4.9 / 0121-bcm2835-i2s-Changes-for-allowing-asymmetric-sample-f.patch
1 From 425ee76116894c97d5d97ad4883eb2612b8692f3 Mon Sep 17 00:00:00 2001
2 From: Giedrius Trainavicius <giedrius@blokas.io>
3 Date: Sun, 8 Jan 2017 15:58:54 +0200
4 Subject: [PATCH] bcm2835-i2s: Changes for allowing asymmetric sample formats.
5
6 This is achieved by making changes only to the requested
7 stream direction format, keeping the other stream direction
8 configuration intact.
9
10 Signed-off-by: Giedrius Trainavicius <giedrius@blokas.io>
11 ---
12  sound/soc/bcm/bcm2835-i2s.c | 54 +++++++++++++++++++++++++++++++--------------
13  1 file changed, 38 insertions(+), 16 deletions(-)
14
15 --- a/sound/soc/bcm/bcm2835-i2s.c
16 +++ b/sound/soc/bcm/bcm2835-i2s.c
17 @@ -237,7 +237,9 @@ static int bcm2835_i2s_hw_params(struct
18         unsigned int sampling_rate = params_rate(params);
19         unsigned int data_length, data_delay, bclk_ratio;
20         unsigned int ch1pos, ch2pos, mode, format;
21 +       unsigned int previous_ftxp, previous_frxp;
22         uint32_t csreg;
23 +       bool packed;
24  
25         /*
26          * If a stream is already enabled,
27 @@ -320,26 +322,46 @@ static int bcm2835_i2s_hw_params(struct
28                 return -EINVAL;
29         }
30  
31 -       /*
32 -        * Set format for both streams.
33 -        * We cannot set another frame length
34 -        * (and therefore word length) anyway,
35 -        * so the format will be the same.
36 -        */
37 -       regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format);
38 -       regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format);
39 +       /* Set the format for the matching stream direction. */
40 +       switch (substream->stream) {
41 +       case SNDRV_PCM_STREAM_PLAYBACK:
42 +               regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format);
43 +               break;
44 +       case SNDRV_PCM_STREAM_CAPTURE:
45 +               regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format);
46 +               break;
47 +       default:
48 +               return -EINVAL;
49 +       }
50  
51         /* Setup the I2S mode */
52 +       /* Keep existing FTXP and FRXP values. */
53 +       regmap_read(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, &mode);
54 +
55 +       previous_ftxp = mode & BCM2835_I2S_FTXP;
56 +       previous_frxp = mode & BCM2835_I2S_FRXP;
57 +
58         mode = 0;
59  
60 -       if (data_length <= 16) {
61 -               /*
62 -                * Use frame packed mode (2 channels per 32 bit word)
63 -                * We cannot set another frame length in the second stream
64 -                * (and therefore word length) anyway,
65 -                * so the format will be the same.
66 -                */
67 -               mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP;
68 +       /*
69 +        * Retain the frame packed mode (2 channels per 32 bit word)
70 +        * of the other direction stream intact. The formats of each
71 +        * direction can be different as long as the frame length is
72 +        * shared for both.
73 +        */
74 +       packed = data_length <= 16;
75 +
76 +       switch (substream->stream) {
77 +       case SNDRV_PCM_STREAM_PLAYBACK:
78 +               mode |= previous_frxp;
79 +               mode |= packed ? BCM2835_I2S_FTXP : 0;
80 +               break;
81 +       case SNDRV_PCM_STREAM_CAPTURE:
82 +               mode |= previous_ftxp;
83 +               mode |= packed ? BCM2835_I2S_FRXP : 0;
84 +               break;
85 +       default:
86 +               return -EINVAL;
87         }
88  
89         mode |= BCM2835_I2S_FLEN(bclk_ratio - 1);