]>
Commit | Line | Data |
---|---|---|
0e6eeba7 GKH |
1 | From a46eb523220e242affb9a6bc9bb8efc05f4f7459 Mon Sep 17 00:00:00 2001 |
2 | From: Curtis Malainey <cujomalainey@chromium.org> | |
3 | Date: Fri, 3 May 2019 12:32:14 -0700 | |
4 | Subject: ASoC: RT5677-SPI: Disable 16Bit SPI Transfers | |
5 | ||
6 | From: Curtis Malainey <cujomalainey@chromium.org> | |
7 | ||
8 | commit a46eb523220e242affb9a6bc9bb8efc05f4f7459 upstream. | |
9 | ||
10 | The current algorithm allows 3 types of transfers, 16bit, 32bit and | |
11 | burst. According to Realtek, 16bit transfers have a special restriction | |
12 | in that it is restricted to the memory region of | |
13 | 0x18020000 ~ 0x18021000. This region is the memory location of the I2C | |
14 | registers. The current algorithm does not uphold this restriction and | |
15 | therefore fails to complete writes. | |
16 | ||
17 | Since this has been broken for some time it likely no one is using it. | |
18 | Better to simply disable the 16 bit writes. This will allow users to | |
19 | properly load firmware over SPI without data corruption. | |
20 | ||
21 | Signed-off-by: Curtis Malainey <cujomalainey@chromium.org> | |
22 | Reviewed-by: Ben Zhang <benzh@chromium.org> | |
23 | Signed-off-by: Mark Brown <broonie@kernel.org> | |
24 | Cc: stable@vger.kernel.org | |
25 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
26 | ||
27 | --- | |
28 | sound/soc/codecs/rt5677-spi.c | 35 ++++++++++++++++------------------- | |
29 | 1 file changed, 16 insertions(+), 19 deletions(-) | |
30 | ||
31 | --- a/sound/soc/codecs/rt5677-spi.c | |
32 | +++ b/sound/soc/codecs/rt5677-spi.c | |
33 | @@ -60,13 +60,15 @@ static DEFINE_MUTEX(spi_mutex); | |
34 | * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes | |
35 | * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes | |
36 | * | |
37 | - * For example, reading 260 bytes at 0x60030002 uses the following commands: | |
38 | - * 0x60030002 RT5677_SPI_READ_16 2 bytes | |
39 | + * Note: | |
40 | + * 16 Bit writes and reads are restricted to the address range | |
41 | + * 0x18020000 ~ 0x18021000 | |
42 | + * | |
43 | + * For example, reading 256 bytes at 0x60030004 uses the following commands: | |
44 | * 0x60030004 RT5677_SPI_READ_32 4 bytes | |
45 | * 0x60030008 RT5677_SPI_READ_BURST 240 bytes | |
46 | * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes | |
47 | * 0x60030100 RT5677_SPI_READ_32 4 bytes | |
48 | - * 0x60030104 RT5677_SPI_READ_16 2 bytes | |
49 | * | |
50 | * Input: | |
51 | * @read: true for read commands; false for write commands | |
52 | @@ -81,15 +83,13 @@ static u8 rt5677_spi_select_cmd(bool rea | |
53 | { | |
54 | u8 cmd; | |
55 | ||
56 | - if (align == 2 || align == 6 || remain == 2) { | |
57 | - cmd = RT5677_SPI_READ_16; | |
58 | - *len = 2; | |
59 | - } else if (align == 4 || remain <= 6) { | |
60 | + if (align == 4 || remain <= 4) { | |
61 | cmd = RT5677_SPI_READ_32; | |
62 | *len = 4; | |
63 | } else { | |
64 | cmd = RT5677_SPI_READ_BURST; | |
65 | - *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN); | |
66 | + *len = (((remain - 1) >> 3) + 1) << 3; | |
67 | + *len = min_t(u32, *len, RT5677_SPI_BURST_LEN); | |
68 | } | |
69 | return read ? cmd : cmd + 1; | |
70 | } | |
71 | @@ -110,7 +110,7 @@ static void rt5677_spi_reverse(u8 *dst, | |
72 | } | |
73 | } | |
74 | ||
75 | -/* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */ | |
76 | +/* Read DSP address space using SPI. addr and len have to be 4-byte aligned. */ | |
77 | int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) | |
78 | { | |
79 | u32 offset; | |
80 | @@ -126,7 +126,7 @@ int rt5677_spi_read(u32 addr, void *rxbu | |
81 | if (!g_spi) | |
82 | return -ENODEV; | |
83 | ||
84 | - if ((addr & 1) || (len & 1)) { | |
85 | + if ((addr & 3) || (len & 3)) { | |
86 | dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len); | |
87 | return -EACCES; | |
88 | } | |
89 | @@ -161,13 +161,13 @@ int rt5677_spi_read(u32 addr, void *rxbu | |
90 | } | |
91 | EXPORT_SYMBOL_GPL(rt5677_spi_read); | |
92 | ||
93 | -/* Write DSP address space using SPI. addr has to be 2-byte aligned. | |
94 | - * If len is not 2-byte aligned, an extra byte of zero is written at the end | |
95 | +/* Write DSP address space using SPI. addr has to be 4-byte aligned. | |
96 | + * If len is not 4-byte aligned, then extra zeros are written at the end | |
97 | * as padding. | |
98 | */ | |
99 | int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) | |
100 | { | |
101 | - u32 offset, len_with_pad = len; | |
102 | + u32 offset; | |
103 | int status = 0; | |
104 | struct spi_transfer t; | |
105 | struct spi_message m; | |
106 | @@ -180,22 +180,19 @@ int rt5677_spi_write(u32 addr, const voi | |
107 | if (!g_spi) | |
108 | return -ENODEV; | |
109 | ||
110 | - if (addr & 1) { | |
111 | + if (addr & 3) { | |
112 | dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len); | |
113 | return -EACCES; | |
114 | } | |
115 | ||
116 | - if (len & 1) | |
117 | - len_with_pad = len + 1; | |
118 | - | |
119 | memset(&t, 0, sizeof(t)); | |
120 | t.tx_buf = buf; | |
121 | t.speed_hz = RT5677_SPI_FREQ; | |
122 | spi_message_init_with_transfers(&m, &t, 1); | |
123 | ||
124 | - for (offset = 0; offset < len_with_pad;) { | |
125 | + for (offset = 0; offset < len;) { | |
126 | spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7, | |
127 | - len_with_pad - offset, &t.len); | |
128 | + len - offset, &t.len); | |
129 | ||
130 | /* Construct SPI message header */ | |
131 | buf[0] = spi_cmd; |