~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/tfa989x.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /sound/soc/codecs/tfa989x.c (Version linux-6.12-rc7) and /sound/soc/codecs/tfa989x.c (Version linux-4.18.20)


  1 // SPDX-License-Identifier: GPL-2.0-only            1 
  2 /*                                                
  3  * Copyright (C) 2021 Stephan Gerhold             
  4  *                                                
  5  * Register definitions/sequences taken from v    
  6  * Copyright (C) 2014-2020 NXP Semiconductors,    
  7  * Copyright (C) 2013 Sony Mobile Communicatio    
  8  */                                               
  9                                                   
 10 #include <linux/gpio/consumer.h>                  
 11 #include <linux/i2c.h>                            
 12 #include <linux/module.h>                         
 13 #include <linux/regmap.h>                         
 14 #include <linux/regulator/consumer.h>             
 15 #include <sound/soc.h>                            
 16                                                   
 17 #define TFA989X_STATUSREG               0x00      
 18 #define TFA989X_BATTERYVOLTAGE          0x01      
 19 #define TFA989X_TEMPERATURE             0x02      
 20 #define TFA989X_REVISIONNUMBER          0x03      
 21 #define TFA989X_REVISIONNUMBER_REV_MSK  GENMAS    
 22 #define TFA989X_I2SREG                  0x04      
 23 #define TFA989X_I2SREG_RCV              2         
 24 #define TFA989X_I2SREG_CHSA             6         
 25 #define TFA989X_I2SREG_CHSA_MSK         GENMAS    
 26 #define TFA989X_I2SREG_I2SSR            12        
 27 #define TFA989X_I2SREG_I2SSR_MSK        GENMAS    
 28 #define TFA989X_BAT_PROT                0x05      
 29 #define TFA989X_AUDIO_CTR               0x06      
 30 #define TFA989X_DCDCBOOST               0x07      
 31 #define TFA989X_SPKR_CALIBRATION        0x08      
 32 #define TFA989X_SYS_CTRL                0x09      
 33 #define TFA989X_SYS_CTRL_PWDN           0         
 34 #define TFA989X_SYS_CTRL_I2CR           1         
 35 #define TFA989X_SYS_CTRL_CFE            2         
 36 #define TFA989X_SYS_CTRL_AMPE           3         
 37 #define TFA989X_SYS_CTRL_DCA            4         
 38 #define TFA989X_SYS_CTRL_SBSL           5         
 39 #define TFA989X_SYS_CTRL_AMPC           6         
 40 #define TFA989X_I2S_SEL_REG             0x0a      
 41 #define TFA989X_I2S_SEL_REG_SPKR_MSK    GENMAS    
 42 #define TFA989X_I2S_SEL_REG_DCFG_MSK    GENMAS    
 43 #define TFA989X_HIDE_UNHIDE_KEY 0x40              
 44 #define TFA989X_PWM_CONTROL             0x41      
 45 #define TFA989X_CURRENTSENSE1           0x46      
 46 #define TFA989X_CURRENTSENSE2           0x47      
 47 #define TFA989X_CURRENTSENSE3           0x48      
 48 #define TFA989X_CURRENTSENSE4           0x49      
 49                                                   
 50 #define TFA9890_REVISION                0x80      
 51 #define TFA9895_REVISION                0x12      
 52 #define TFA9897_REVISION                0x97      
 53                                                   
 54 struct tfa989x_rev {                              
 55         unsigned int rev;                         
 56         int (*init)(struct regmap *regmap);       
 57 };                                                
 58                                                   
 59 struct tfa989x {                                  
 60         const struct tfa989x_rev *rev;            
 61         struct regulator *vddd_supply;            
 62         struct gpio_desc *rcv_gpiod;              
 63 };                                                
 64                                                   
 65 static bool tfa989x_writeable_reg(struct devic    
 66 {                                                 
 67         return reg > TFA989X_REVISIONNUMBER;      
 68 }                                                 
 69                                                   
 70 static bool tfa989x_volatile_reg(struct device    
 71 {                                                 
 72         return reg < TFA989X_REVISIONNUMBER;      
 73 }                                                 
 74                                                   
 75 static const struct regmap_config tfa989x_regm    
 76         .reg_bits = 8,                            
 77         .val_bits = 16,                           
 78                                                   
 79         .writeable_reg  = tfa989x_writeable_re    
 80         .volatile_reg   = tfa989x_volatile_reg    
 81         .cache_type     = REGCACHE_RBTREE,        
 82 };                                                
 83                                                   
 84 static const char * const chsa_text[] = { "Lef    
 85 static SOC_ENUM_SINGLE_DECL(chsa_enum, TFA989X    
 86 static const struct snd_kcontrol_new chsa_mux     
 87                                                   
 88 static const struct snd_soc_dapm_widget tfa989    
 89         SND_SOC_DAPM_OUTPUT("OUT"),               
 90         SND_SOC_DAPM_SUPPLY("POWER", TFA989X_S    
 91         SND_SOC_DAPM_OUT_DRV("AMPE", TFA989X_S    
 92                                                   
 93         SND_SOC_DAPM_MUX("Amp Input", SND_SOC_    
 94         SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Pl    
 95         SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Pl    
 96 };                                                
 97                                                   
 98 static const struct snd_soc_dapm_route tfa989x    
 99         {"OUT", NULL, "AMPE"},                    
100         {"AMPE", NULL, "POWER"},                  
101         {"AMPE", NULL, "Amp Input"},              
102         {"Amp Input", "Left", "AIFINL"},          
103         {"Amp Input", "Right", "AIFINR"},         
104 };                                                
105                                                   
106 static int tfa989x_put_mode(struct snd_kcontro    
107 {                                                 
108         struct snd_soc_component *component =     
109         struct tfa989x *tfa989x = snd_soc_comp    
110                                                   
111         gpiod_set_value_cansleep(tfa989x->rcv_    
112                                                   
113         return snd_soc_put_enum_double(kcontro    
114 }                                                 
115                                                   
116 static const char * const mode_text[] = { "Spe    
117 static SOC_ENUM_SINGLE_DECL(mode_enum, TFA989X    
118 static const struct snd_kcontrol_new tfa989x_m    
119         SOC_ENUM_EXT("Mode", mode_enum, snd_so    
120 };                                                
121                                                   
122 static int tfa989x_probe(struct snd_soc_compon    
123 {                                                 
124         struct tfa989x *tfa989x = snd_soc_comp    
125                                                   
126         if (tfa989x->rev->rev == TFA9897_REVIS    
127                 return snd_soc_add_component_c    
128                                                   
129                                                   
130         return 0;                                 
131 }                                                 
132                                                   
133 static const struct snd_soc_component_driver t    
134         .probe                  = tfa989x_prob    
135         .dapm_widgets           = tfa989x_dapm    
136         .num_dapm_widgets       = ARRAY_SIZE(t    
137         .dapm_routes            = tfa989x_dapm    
138         .num_dapm_routes        = ARRAY_SIZE(t    
139         .use_pmdown_time        = 1,              
140         .endianness             = 1,              
141 };                                                
142                                                   
143 static const unsigned int tfa989x_rates[] = {     
144         8000, 11025, 12000, 16000, 22050, 2400    
145 };                                                
146                                                   
147 static int tfa989x_find_sample_rate(unsigned i    
148 {                                                 
149         int i;                                    
150                                                   
151         for (i = 0; i < ARRAY_SIZE(tfa989x_rat    
152                 if (tfa989x_rates[i] == rate)     
153                         return i;                 
154                                                   
155         return -EINVAL;                           
156 }                                                 
157                                                   
158 static int tfa989x_hw_params(struct snd_pcm_su    
159                              struct snd_pcm_hw    
160                              struct snd_soc_da    
161 {                                                 
162         struct snd_soc_component *component =     
163         int sr;                                   
164                                                   
165         sr = tfa989x_find_sample_rate(params_r    
166         if (sr < 0)                               
167                 return sr;                        
168                                                   
169         return snd_soc_component_update_bits(c    
170                                              T    
171                                              s    
172 }                                                 
173                                                   
174 static const struct snd_soc_dai_ops tfa989x_da    
175         .hw_params = tfa989x_hw_params,           
176 };                                                
177                                                   
178 static struct snd_soc_dai_driver tfa989x_dai =    
179         .name = "tfa989x-hifi",                   
180         .playback = {                             
181                 .stream_name    = "HiFi Playba    
182                 .formats        = SNDRV_PCM_FM    
183                 .rates          = SNDRV_PCM_RA    
184                 .rate_min       = 8000,           
185                 .rate_max       = 48000,          
186                 .channels_min   = 1,              
187                 .channels_max   = 2,              
188         },                                        
189         .ops = &tfa989x_dai_ops,                  
190 };                                                
191                                                   
192 static int tfa9890_init(struct regmap *regmap)    
193 {                                                 
194         int ret;                                  
195                                                   
196         /* temporarily allow access to hidden     
197         ret = regmap_write(regmap, TFA989X_HID    
198         if (ret)                                  
199                 return ret;                       
200                                                   
201         /* update PLL registers */                
202         ret = regmap_set_bits(regmap, 0x59, 0x    
203         if (ret)                                  
204                 return ret;                       
205                                                   
206         /* hide registers again */                
207         ret = regmap_write(regmap, TFA989X_HID    
208         if (ret)                                  
209                 return ret;                       
210                                                   
211         return regmap_write(regmap, TFA989X_CU    
212 }                                                 
213                                                   
214 static const struct tfa989x_rev tfa9890_rev =     
215         .rev    = TFA9890_REVISION,               
216         .init   = tfa9890_init,                   
217 };                                                
218                                                   
219 static const struct reg_sequence tfa9895_reg_i    
220         /* some other registers must be set fo    
221         { TFA989X_BAT_PROT, 0x13ab },             
222         { TFA989X_AUDIO_CTR, 0x001f },            
223                                                   
224         /* peak voltage protection is always o    
225         { TFA989X_SPKR_CALIBRATION, 0x3c4e },     
226                                                   
227         /* TFA989X_SYSCTRL_DCA = 0 */             
228         { TFA989X_SYS_CTRL, 0x024d },             
229         { TFA989X_PWM_CONTROL, 0x0308 },          
230         { TFA989X_CURRENTSENSE4, 0x0e82 },        
231 };                                                
232                                                   
233 static int tfa9895_init(struct regmap *regmap)    
234 {                                                 
235         return regmap_multi_reg_write(regmap,     
236                                       ARRAY_SI    
237 }                                                 
238                                                   
239 static const struct tfa989x_rev tfa9895_rev =     
240         .rev    = TFA9895_REVISION,               
241         .init   = tfa9895_init,                   
242 };                                                
243                                                   
244 static int tfa9897_init(struct regmap *regmap)    
245 {                                                 
246         int ret;                                  
247                                                   
248         /* Reduce slewrate by clearing iddqtes    
249         ret = regmap_write(regmap, TFA989X_CUR    
250         if (ret)                                  
251                 return ret;                       
252                                                   
253         /* Enable clipping */                     
254         ret = regmap_clear_bits(regmap, TFA989    
255         if (ret)                                  
256                 return ret;                       
257                                                   
258         /* Set required TDM configuration */      
259         return regmap_write(regmap, 0x14, 0x0)    
260 }                                                 
261                                                   
262 static const struct tfa989x_rev tfa9897_rev =     
263         .rev    = TFA9897_REVISION,               
264         .init   = tfa9897_init,                   
265 };                                                
266                                                   
267 /*                                                
268  * Note: At the moment this driver bypasses th    
269  * TFA989X amplifiers. Unfortunately, there se    
270  * no documentation for it - the public "short    
271  * any information about the DSP or available     
272  *                                                
273  * Usually the TFA989X amplifiers are configur    
274  * libraries. There are also some (rather comp    
275  * rely on obscure firmware blobs for configur    
276  * They seem to contain different "profiles" w    
277  * rates and volume steps (which would be bett    
278  *                                                
279  * Bypassing the DSP disables volume control (    
280  * optimization?), but at least allows using t    
281  * kernel drivers and firmware.                   
282  *                                                
283  * Ideally NXP (or now Goodix) should release     
284  * amplifiers so that support for the "CoolFlu    
285  */                                               
286 static int tfa989x_dsp_bypass(struct regmap *r    
287 {                                                 
288         int ret;                                  
289                                                   
290         /* Clear CHSA to bypass DSP and take i    
291         ret = regmap_clear_bits(regmap, TFA989    
292         if (ret)                                  
293                 return ret;                       
294                                                   
295         /* Set DCDC compensation to off and sp    
296         ret = regmap_update_bits(regmap, TFA98    
297                                  TFA989X_I2S_S    
298                                  TFA989X_I2S_S    
299                                  TFA989X_I2S_S    
300         if (ret)                                  
301                 return ret;                       
302                                                   
303         /* Set DCDC to follower mode and disab    
304         return regmap_clear_bits(regmap, TFA98    
305                                  BIT(TFA989X_S    
306                                  BIT(TFA989X_S    
307                                  BIT(TFA989X_S    
308 }                                                 
309                                                   
310 static void tfa989x_regulator_disable(void *da    
311 {                                                 
312         struct tfa989x *tfa989x = data;           
313                                                   
314         regulator_disable(tfa989x->vddd_supply    
315 }                                                 
316                                                   
317 static int tfa989x_i2c_probe(struct i2c_client    
318 {                                                 
319         struct device *dev = &i2c->dev;           
320         const struct tfa989x_rev *rev;            
321         struct tfa989x *tfa989x;                  
322         struct regmap *regmap;                    
323         unsigned int val;                         
324         int ret;                                  
325                                                   
326         rev = device_get_match_data(dev);         
327         if (!rev) {                               
328                 dev_err(dev, "unknown device r    
329                 return -ENODEV;                   
330         }                                         
331                                                   
332         tfa989x = devm_kzalloc(dev, sizeof(*tf    
333         if (!tfa989x)                             
334                 return -ENOMEM;                   
335                                                   
336         tfa989x->rev = rev;                       
337         i2c_set_clientdata(i2c, tfa989x);         
338                                                   
339         tfa989x->vddd_supply = devm_regulator_    
340         if (IS_ERR(tfa989x->vddd_supply))         
341                 return dev_err_probe(dev, PTR_    
342                                      "Failed t    
343                                                   
344         if (tfa989x->rev->rev == TFA9897_REVIS    
345                 tfa989x->rcv_gpiod = devm_gpio    
346                 if (IS_ERR(tfa989x->rcv_gpiod)    
347                         return PTR_ERR(tfa989x    
348         }                                         
349                                                   
350         regmap = devm_regmap_init_i2c(i2c, &tf    
351         if (IS_ERR(regmap))                       
352                 return PTR_ERR(regmap);           
353                                                   
354         ret = regulator_enable(tfa989x->vddd_s    
355         if (ret) {                                
356                 dev_err(dev, "Failed to enable    
357                 return ret;                       
358         }                                         
359                                                   
360         ret = devm_add_action_or_reset(dev, tf    
361         if (ret)                                  
362                 return ret;                       
363                                                   
364         /* Bypass regcache for reset and init     
365         regcache_cache_bypass(regmap, true);      
366                                                   
367         /* Dummy read to generate i2c clocks,     
368         regmap_read(regmap, TFA989X_REVISIONNU    
369                                                   
370         ret = regmap_read(regmap, TFA989X_REVI    
371         if (ret) {                                
372                 dev_err(dev, "failed to read r    
373                 return ret;                       
374         }                                         
375                                                   
376         val &= TFA989X_REVISIONNUMBER_REV_MSK;    
377         if (val != rev->rev) {                    
378                 dev_err(dev, "invalid revision    
379                         rev->rev, val);           
380                 return -ENODEV;                   
381         }                                         
382                                                   
383         ret = regmap_write(regmap, TFA989X_SYS    
384         if (ret) {                                
385                 dev_err(dev, "failed to reset     
386                 return ret;                       
387         }                                         
388                                                   
389         ret = rev->init(regmap);                  
390         if (ret) {                                
391                 dev_err(dev, "failed to initia    
392                 return ret;                       
393         }                                         
394                                                   
395         ret = tfa989x_dsp_bypass(regmap);         
396         if (ret) {                                
397                 dev_err(dev, "failed to enable    
398                 return ret;                       
399         }                                         
400         regcache_cache_bypass(regmap, false);     
401                                                   
402         return devm_snd_soc_register_component    
403                                                   
404 }                                                 
405                                                   
406 static const struct of_device_id tfa989x_of_ma    
407         { .compatible = "nxp,tfa9890", .data =    
408         { .compatible = "nxp,tfa9895", .data =    
409         { .compatible = "nxp,tfa9897", .data =    
410         { }                                       
411 };                                                
412 MODULE_DEVICE_TABLE(of, tfa989x_of_match);        
413                                                   
414 static struct i2c_driver tfa989x_i2c_driver =     
415         .driver = {                               
416                 .name = "tfa989x",                
417                 .of_match_table = tfa989x_of_m    
418         },                                        
419         .probe = tfa989x_i2c_probe,               
420 };                                                
421 module_i2c_driver(tfa989x_i2c_driver);            
422                                                   
423 MODULE_DESCRIPTION("ASoC NXP/Goodix TFA989X (T    
424 MODULE_AUTHOR("Stephan Gerhold <stephan@gerhol    
425 MODULE_LICENSE("GPL");                            
426                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php