1
1
// SPDX-License-Identifier: GPL-2.0
2
2
// Copyright(c) 2020 Intel Corporation.
3
3
4
+ #include <linux/bits.h>
5
+ #include <linux/delay.h>
4
6
#include <linux/device.h>
5
7
#include <linux/errno.h>
8
+ #include <linux/iopoll.h>
6
9
#include <linux/module.h>
7
10
#include <linux/regmap.h>
8
11
#include <linux/soundwire/sdw.h>
9
12
#include <linux/soundwire/sdw_registers.h>
13
+ #include <sound/sdca_function.h>
10
14
#include "internal.h"
11
15
16
+ struct regmap_mbq_context {
17
+ struct device * dev ;
18
+
19
+ struct regmap_sdw_mbq_cfg cfg ;
20
+
21
+ int val_size ;
22
+ bool (* readable_reg )(struct device * dev , unsigned int reg );
23
+ };
24
+
25
+ static int regmap_sdw_mbq_size (struct regmap_mbq_context * ctx , unsigned int reg )
26
+ {
27
+ int size = ctx -> val_size ;
28
+
29
+ if (ctx -> cfg .mbq_size ) {
30
+ size = ctx -> cfg .mbq_size (ctx -> dev , reg );
31
+ if (!size || size > ctx -> val_size )
32
+ return - EINVAL ;
33
+ }
34
+
35
+ return size ;
36
+ }
37
+
38
+ static bool regmap_sdw_mbq_deferrable (struct regmap_mbq_context * ctx , unsigned int reg )
39
+ {
40
+ if (ctx -> cfg .deferrable )
41
+ return ctx -> cfg .deferrable (ctx -> dev , reg );
42
+
43
+ return false;
44
+ }
45
+
46
+ static int regmap_sdw_mbq_poll_busy (struct sdw_slave * slave , unsigned int reg ,
47
+ struct regmap_mbq_context * ctx )
48
+ {
49
+ struct device * dev = & slave -> dev ;
50
+ int val , ret = 0 ;
51
+
52
+ dev_dbg (dev , "Deferring transaction for 0x%x\n" , reg );
53
+
54
+ reg = SDW_SDCA_CTL (SDW_SDCA_CTL_FUNC (reg ), 0 ,
55
+ SDCA_CTL_ENTITY_0_FUNCTION_STATUS , 0 );
56
+
57
+ if (ctx -> readable_reg (dev , reg )) {
58
+ ret = read_poll_timeout (sdw_read_no_pm , val ,
59
+ val < 0 || !(val & SDCA_CTL_ENTITY_0_FUNCTION_BUSY ),
60
+ ctx -> cfg .timeout_us , ctx -> cfg .retry_us ,
61
+ false, slave , reg );
62
+ if (val < 0 )
63
+ return val ;
64
+ if (ret )
65
+ dev_err (dev , "Function busy timed out 0x%x: %d\n" , reg , val );
66
+ } else {
67
+ fsleep (ctx -> cfg .timeout_us );
68
+ }
69
+
70
+ return ret ;
71
+ }
72
+
73
+ static int regmap_sdw_mbq_write_impl (struct sdw_slave * slave ,
74
+ unsigned int reg , unsigned int val ,
75
+ int mbq_size , bool deferrable )
76
+ {
77
+ int shift = mbq_size * BITS_PER_BYTE ;
78
+ int ret ;
79
+
80
+ while (-- mbq_size > 0 ) {
81
+ shift -= BITS_PER_BYTE ;
82
+
83
+ ret = sdw_write_no_pm (slave , SDW_SDCA_MBQ_CTL (reg ),
84
+ (val >> shift ) & 0xff );
85
+ if (ret < 0 )
86
+ return ret ;
87
+ }
88
+
89
+ ret = sdw_write_no_pm (slave , reg , val & 0xff );
90
+ if (deferrable && ret == - ENODATA )
91
+ return - EAGAIN ;
92
+
93
+ return ret ;
94
+ }
95
+
12
96
static int regmap_sdw_mbq_write (void * context , unsigned int reg , unsigned int val )
13
97
{
14
- struct device * dev = context ;
98
+ struct regmap_mbq_context * ctx = context ;
99
+ struct device * dev = ctx -> dev ;
15
100
struct sdw_slave * slave = dev_to_sdw_dev (dev );
101
+ bool deferrable = regmap_sdw_mbq_deferrable (ctx , reg );
102
+ int mbq_size = regmap_sdw_mbq_size (ctx , reg );
16
103
int ret ;
17
104
18
- ret = sdw_write_no_pm (slave , SDW_SDCA_MBQ_CTL (reg ), (val >> 8 ) & 0xff );
19
- if (ret < 0 )
20
- return ret ;
105
+ if (mbq_size < 0 )
106
+ return mbq_size ;
107
+
108
+ /*
109
+ * Technically the spec does allow a device to set itself to busy for
110
+ * internal reasons, but since it doesn't provide any information on
111
+ * how to handle timeouts in that case, for now the code will only
112
+ * process a single wait/timeout on function busy and a single retry
113
+ * of the transaction.
114
+ */
115
+ ret = regmap_sdw_mbq_write_impl (slave , reg , val , mbq_size , deferrable );
116
+ if (ret == - EAGAIN ) {
117
+ ret = regmap_sdw_mbq_poll_busy (slave , reg , ctx );
118
+ if (ret )
119
+ return ret ;
120
+
121
+ ret = regmap_sdw_mbq_write_impl (slave , reg , val , mbq_size , false);
122
+ }
123
+
124
+ return ret ;
125
+ }
126
+
127
+ static int regmap_sdw_mbq_read_impl (struct sdw_slave * slave ,
128
+ unsigned int reg , unsigned int * val ,
129
+ int mbq_size , bool deferrable )
130
+ {
131
+ int shift = BITS_PER_BYTE ;
132
+ int read ;
133
+
134
+ read = sdw_read_no_pm (slave , reg );
135
+ if (read < 0 ) {
136
+ if (deferrable && read == - ENODATA )
137
+ return - EAGAIN ;
138
+
139
+ return read ;
140
+ }
141
+
142
+ * val = read ;
143
+
144
+ while (-- mbq_size > 0 ) {
145
+ read = sdw_read_no_pm (slave , SDW_SDCA_MBQ_CTL (reg ));
146
+ if (read < 0 )
147
+ return read ;
148
+
149
+ * val |= read << shift ;
150
+ shift += BITS_PER_BYTE ;
151
+ }
21
152
22
- return sdw_write_no_pm ( slave , reg , val & 0xff ) ;
153
+ return 0 ;
23
154
}
24
155
25
156
static int regmap_sdw_mbq_read (void * context , unsigned int reg , unsigned int * val )
26
157
{
27
- struct device * dev = context ;
158
+ struct regmap_mbq_context * ctx = context ;
159
+ struct device * dev = ctx -> dev ;
28
160
struct sdw_slave * slave = dev_to_sdw_dev (dev );
29
- int read0 ;
30
- int read1 ;
161
+ bool deferrable = regmap_sdw_mbq_deferrable (ctx , reg );
162
+ int mbq_size = regmap_sdw_mbq_size (ctx , reg );
163
+ int ret ;
31
164
32
- read0 = sdw_read_no_pm (slave , reg );
33
- if (read0 < 0 )
34
- return read0 ;
165
+ if (mbq_size < 0 )
166
+ return mbq_size ;
35
167
36
- read1 = sdw_read_no_pm (slave , SDW_SDCA_MBQ_CTL (reg ));
37
- if (read1 < 0 )
38
- return read1 ;
168
+ /*
169
+ * Technically the spec does allow a device to set itself to busy for
170
+ * internal reasons, but since it doesn't provide any information on
171
+ * how to handle timeouts in that case, for now the code will only
172
+ * process a single wait/timeout on function busy and a single retry
173
+ * of the transaction.
174
+ */
175
+ ret = regmap_sdw_mbq_read_impl (slave , reg , val , mbq_size , deferrable );
176
+ if (ret == - EAGAIN ) {
177
+ ret = regmap_sdw_mbq_poll_busy (slave , reg , ctx );
178
+ if (ret )
179
+ return ret ;
39
180
40
- * val = (read1 << 8 ) | read0 ;
181
+ ret = regmap_sdw_mbq_read_impl (slave , reg , val , mbq_size , false);
182
+ }
41
183
42
- return 0 ;
184
+ return ret ;
43
185
}
44
186
45
187
static const struct regmap_bus regmap_sdw_mbq = {
@@ -51,8 +193,7 @@ static const struct regmap_bus regmap_sdw_mbq = {
51
193
52
194
static int regmap_sdw_mbq_config_check (const struct regmap_config * config )
53
195
{
54
- /* MBQ-based controls are only 16-bits for now */
55
- if (config -> val_bits != 16 )
196
+ if (config -> val_bits > (sizeof (unsigned int ) * BITS_PER_BYTE ))
56
197
return - ENOTSUPP ;
57
198
58
199
/* Registers are 32 bits wide */
@@ -65,35 +206,69 @@ static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
65
206
return 0 ;
66
207
}
67
208
209
+ static struct regmap_mbq_context *
210
+ regmap_sdw_mbq_gen_context (struct device * dev ,
211
+ const struct regmap_config * config ,
212
+ const struct regmap_sdw_mbq_cfg * mbq_config )
213
+ {
214
+ struct regmap_mbq_context * ctx ;
215
+
216
+ ctx = devm_kzalloc (dev , sizeof (* ctx ), GFP_KERNEL );
217
+ if (!ctx )
218
+ return ERR_PTR (- ENOMEM );
219
+
220
+ ctx -> dev = dev ;
221
+
222
+ if (mbq_config )
223
+ ctx -> cfg = * mbq_config ;
224
+
225
+ ctx -> val_size = config -> val_bits / BITS_PER_BYTE ;
226
+ ctx -> readable_reg = config -> readable_reg ;
227
+
228
+ return ctx ;
229
+ }
230
+
68
231
struct regmap * __regmap_init_sdw_mbq (struct sdw_slave * sdw ,
69
232
const struct regmap_config * config ,
233
+ const struct regmap_sdw_mbq_cfg * mbq_config ,
70
234
struct lock_class_key * lock_key ,
71
235
const char * lock_name )
72
236
{
237
+ struct regmap_mbq_context * ctx ;
73
238
int ret ;
74
239
75
240
ret = regmap_sdw_mbq_config_check (config );
76
241
if (ret )
77
242
return ERR_PTR (ret );
78
243
79
- return __regmap_init (& sdw -> dev , & regmap_sdw_mbq ,
80
- & sdw -> dev , config , lock_key , lock_name );
244
+ ctx = regmap_sdw_mbq_gen_context (& sdw -> dev , config , mbq_config );
245
+ if (IS_ERR (ctx ))
246
+ return ERR_CAST (ctx );
247
+
248
+ return __regmap_init (& sdw -> dev , & regmap_sdw_mbq , ctx ,
249
+ config , lock_key , lock_name );
81
250
}
82
251
EXPORT_SYMBOL_GPL (__regmap_init_sdw_mbq );
83
252
84
253
struct regmap * __devm_regmap_init_sdw_mbq (struct sdw_slave * sdw ,
85
254
const struct regmap_config * config ,
255
+ const struct regmap_sdw_mbq_cfg * mbq_config ,
86
256
struct lock_class_key * lock_key ,
87
257
const char * lock_name )
88
258
{
259
+ struct regmap_mbq_context * ctx ;
89
260
int ret ;
90
261
91
262
ret = regmap_sdw_mbq_config_check (config );
92
263
if (ret )
93
264
return ERR_PTR (ret );
94
265
95
- return __devm_regmap_init (& sdw -> dev , & regmap_sdw_mbq ,
96
- & sdw -> dev , config , lock_key , lock_name );
266
+ ctx = regmap_sdw_mbq_gen_context (& sdw -> dev , config , mbq_config );
267
+ if (IS_ERR (ctx ))
268
+ return ERR_CAST (ctx );
269
+
270
+ return __devm_regmap_init (& sdw -> dev , & regmap_sdw_mbq , ctx ,
271
+ config , lock_key , lock_name );
97
272
}
98
273
EXPORT_SYMBOL_GPL (__devm_regmap_init_sdw_mbq );
99
274
0 commit comments