11// SPDX-License-Identifier: GPL-2.0
22// Copyright(c) 2020 Intel Corporation.
33
4+ #include <linux/bits.h>
5+ #include <linux/delay.h>
46#include <linux/device.h>
57#include <linux/errno.h>
8+ #include <linux/iopoll.h>
69#include <linux/module.h>
710#include <linux/regmap.h>
811#include <linux/soundwire/sdw.h>
912#include <linux/soundwire/sdw_registers.h>
13+ #include <sound/sdca_function.h>
1014#include "internal.h"
1115
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+
1296static int regmap_sdw_mbq_write (void * context , unsigned int reg , unsigned int val )
1397{
14- struct device * dev = context ;
98+ struct regmap_mbq_context * ctx = context ;
99+ struct device * dev = ctx -> dev ;
15100 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 );
16103 int ret ;
17104
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+ }
21152
22- return sdw_write_no_pm ( slave , reg , val & 0xff ) ;
153+ return 0 ;
23154}
24155
25156static int regmap_sdw_mbq_read (void * context , unsigned int reg , unsigned int * val )
26157{
27- struct device * dev = context ;
158+ struct regmap_mbq_context * ctx = context ;
159+ struct device * dev = ctx -> dev ;
28160 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 ;
31164
32- read0 = sdw_read_no_pm (slave , reg );
33- if (read0 < 0 )
34- return read0 ;
165+ if (mbq_size < 0 )
166+ return mbq_size ;
35167
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 ;
39180
40- * val = (read1 << 8 ) | read0 ;
181+ ret = regmap_sdw_mbq_read_impl (slave , reg , val , mbq_size , false);
182+ }
41183
42- return 0 ;
184+ return ret ;
43185}
44186
45187static const struct regmap_bus regmap_sdw_mbq = {
@@ -51,8 +193,7 @@ static const struct regmap_bus regmap_sdw_mbq = {
51193
52194static int regmap_sdw_mbq_config_check (const struct regmap_config * config )
53195{
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 ))
56197 return - ENOTSUPP ;
57198
58199 /* Registers are 32 bits wide */
@@ -65,35 +206,69 @@ static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
65206 return 0 ;
66207}
67208
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+
68231struct regmap * __regmap_init_sdw_mbq (struct sdw_slave * sdw ,
69232 const struct regmap_config * config ,
233+ const struct regmap_sdw_mbq_cfg * mbq_config ,
70234 struct lock_class_key * lock_key ,
71235 const char * lock_name )
72236{
237+ struct regmap_mbq_context * ctx ;
73238 int ret ;
74239
75240 ret = regmap_sdw_mbq_config_check (config );
76241 if (ret )
77242 return ERR_PTR (ret );
78243
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 );
81250}
82251EXPORT_SYMBOL_GPL (__regmap_init_sdw_mbq );
83252
84253struct regmap * __devm_regmap_init_sdw_mbq (struct sdw_slave * sdw ,
85254 const struct regmap_config * config ,
255+ const struct regmap_sdw_mbq_cfg * mbq_config ,
86256 struct lock_class_key * lock_key ,
87257 const char * lock_name )
88258{
259+ struct regmap_mbq_context * ctx ;
89260 int ret ;
90261
91262 ret = regmap_sdw_mbq_config_check (config );
92263 if (ret )
93264 return ERR_PTR (ret );
94265
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 );
97272}
98273EXPORT_SYMBOL_GPL (__devm_regmap_init_sdw_mbq );
99274
0 commit comments