Revert "TEMP: asoc: tegra-alt: disable SLGC"
[linux-3.10.git] / sound / soc / tegra / tegra210_amixer.c
1 /*
2  * tegra210_amixer.c - Tegra210 AMIXER driver.
3  *
4  * Author: Rahul Mittal <rmittal@nvidia.com>
5  *
6  * Copyright (C) 2014, NVIDIA CORPORATION. All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23
24 /*
25 #define VERBOSE_DEBUG
26 #define DEBUG
27 */
28
29 #include <linux/clk.h>
30 #include <linux/of.h>
31 #include <linux/module.h>
32 #include <linux/device.h>
33 #include <linux/platform_device.h>
34 #include <linux/io.h>
35 #include <linux/slab.h>
36 #include <linux/pm_runtime.h>
37 #include <linux/regmap.h>
38 #include <linux/delay.h>
39
40 #include "tegra210_amixer.h"
41 #include "tegra210_axbar.h"
42 #include "tegra210_ahub_utils.h"
43
44 #define DRV_NAME "tegra210-amixer"
45
46 /* TEGRA210 AMIXER driver context */
47 struct tegra210_amixer_ctx {
48         struct device   *dev;
49         void __iomem    *regs;
50         struct regmap   *regmap;
51         int             in_use;
52 };
53
54 static struct tegra210_amixer_ctx *tegra210_amixer;
55
56 /* AMIXER APIs definition */
57 /**
58  *  tegra210_amixer_get - gets amixer before use
59  */
60 int tegra210_amixer_get()
61 {
62         if (!tegra210_amixer->in_use) {
63                 dev_vdbg(tegra210_amixer->dev, "%s", __func__);
64                 pm_runtime_get_sync(tegra210_amixer->dev);
65         }
66
67         tegra210_amixer->in_use++;
68         return 0;
69 }
70 EXPORT_SYMBOL_GPL(tegra210_amixer_get);
71
72 /**
73  *  tegra210_amixer_put - frees amixer after use
74  */
75 int tegra210_amixer_put()
76 {
77         tegra210_amixer->in_use--;
78         if (!tegra210_amixer->in_use) {
79                 dev_vdbg(tegra210_amixer->dev, "%s", __func__);
80                 pm_runtime_put_sync(tegra210_amixer->dev);
81         }
82
83         return 0;
84 }
85 EXPORT_SYMBOL_GPL(tegra210_amixer_put);
86
87 /**
88  *  tegra210_amixer_enable - enables/disables amixer globally
89  *  @en : enable/disable flag
90  */
91 int tegra210_amixer_enable(bool en)
92 {
93         dev_vdbg(tegra210_amixer->dev, "%s enable %d", __func__, en);
94
95         regmap_update_bits(tegra210_amixer->regmap,
96                         TEGRA210_AMIXER_ENABLE,
97                         TEGRA210_AMIXER_ENABLE_EN,
98                         en ? TEGRA210_AMIXER_ENABLE_EN : 0);
99
100         return 0;
101 }
102 EXPORT_SYMBOL_GPL(tegra210_amixer_enable);
103
104 /**
105  *  tegra210_amixer_reset - soft resets amixer globally
106  */
107 int tegra210_amixer_reset()
108 {
109         u32 val = 0;
110         int cnt = AHUB_OP_MAX_RETRY;
111
112         dev_vdbg(tegra210_amixer->dev, "%s reset amixer", __func__);
113         regmap_update_bits(tegra210_amixer->regmap,
114                         TEGRA210_AMIXER_SOFT_RESET,
115                         TEGRA210_AMIXER_SOFT_RESET_EN,
116                         TEGRA210_AMIXER_SOFT_RESET_EN);
117
118         do {
119                 udelay(AHUB_OP_SLEEP_US);
120                 regmap_read(tegra210_amixer->regmap, TEGRA210_AMIXER_SOFT_RESET,
121                                 &val);
122         } while ((val & TEGRA210_AMIXER_SOFT_RESET_EN) && cnt--);
123
124         if (!cnt) {
125                 dev_err(tegra210_amixer->dev, "%s Failed to reset amixer",
126                                 __func__);
127                 return -ETIMEDOUT;
128         }
129
130         return 0;
131 }
132 EXPORT_SYMBOL_GPL(tegra210_amixer_reset);
133
134 /**
135  *  tegra210_amixer_set_slcg - sets second level clock gating of amixer
136  *  @en : enable/disable flag
137  */
138 int tegra210_amixer_set_slcg(bool en)
139 {
140         dev_vdbg(tegra210_amixer->dev, "%s amixer slcg enable %d",
141                         __func__, en);
142
143         regmap_update_bits(tegra210_amixer->regmap,
144                         TEGRA210_AMIXER_CG,
145                         TEGRA210_AMIXER_CG_SLCG_EN,
146                         en ? TEGRA210_AMIXER_CG_SLCG_EN : 0);
147
148         return 0;
149 }
150 EXPORT_SYMBOL_GPL(tegra210_amixer_set_slcg);
151
152 /**
153  *  tegra210_amixer_enable_bypass_mode - sets amixer global bypass mode
154  *  @en : enable/disable flag
155  */
156 int tegra210_amixer_enable_bypass_mode(bool en)
157 {
158         dev_vdbg(tegra210_amixer->dev, "%s bypass mode enable %d",
159                         __func__, en);
160
161         regmap_update_bits(tegra210_amixer->regmap,
162                         TEGRA210_AMIXER_CTRL,
163                         TEGRA210_AMIXER_CTRL_BYPASS_MODE_EN,
164                         en ? TEGRA210_AMIXER_CTRL_BYPASS_MODE_EN : 0);
165
166         return 0;
167 }
168 EXPORT_SYMBOL_GPL(tegra210_amixer_enable_bypass_mode);
169
170 /**
171  *  tegra210_amixer_set_acif_param - sets acif params of an amixer input/output
172  *  @cif : mixer cif
173  *  @acif : acif param values
174  */
175 int tegra210_amixer_set_acif_param(enum tegra210_ahub_cifs cif,
176                                 struct tegra210_axbar_cif_param *acif)
177 {
178         u32 reg;
179         dev_vdbg(tegra210_amixer->dev, "%s amixer cif %d", __func__, cif);
180
181         reg = IS_MIXER_RX(cif) ?
182                 TEGRA210_AMIXER_RX_CIF_CTRL +
183                         (MIXER_CIF_ID(cif) * TEGRA210_AMIXER_RX_STRIDE) :
184                 TEGRA210_AMIXER_TX_CIF_CTRL +
185                         (MIXER_CIF_ID(cif) * TEGRA210_AMIXER_TX_STRIDE);
186
187         return tegra210_set_axbar_cif_param(tegra210_amixer->dev, reg, acif);
188 }
189 EXPORT_SYMBOL_GPL(tegra210_amixer_set_acif_param);
190
191 /**
192  *  tegra210_amixer_get_acif_param - gets acif params of an amixer input/output
193  *  @cif : mixer cif
194  *  @acif : acif ptr to be populated
195  */
196 int tegra210_amixer_get_acif_param(enum tegra210_ahub_cifs cif,
197                                 struct tegra210_axbar_cif_param *acif)
198 {
199         u32 reg;
200         dev_vdbg(tegra210_amixer->dev, "%s amixer cif %d", __func__, cif);
201
202         reg = IS_MIXER_RX(cif) ?
203                 TEGRA210_AMIXER_RX_CIF_CTRL +
204                         (MIXER_CIF_ID(cif) * TEGRA210_AMIXER_RX_STRIDE) :
205                 TEGRA210_AMIXER_TX_CIF_CTRL +
206                         (MIXER_CIF_ID(cif) * TEGRA210_AMIXER_TX_STRIDE);
207
208         return tegra210_get_axbar_cif_param(tegra210_amixer->dev, reg, acif);
209 }
210 EXPORT_SYMBOL_GPL(tegra210_amixer_get_acif_param);
211
212 /**
213  *  tegra210_amixer_rx_reset - soft resets an input
214  *  @cif : mixer rxcif
215  */
216 int tegra210_amixer_rx_reset(enum tegra210_ahub_cifs cif)
217 {
218         u32 val = 0, reg, cif_id = MIXER_CIF_ID(cif);
219         int cnt = AHUB_OP_MAX_RETRY;
220
221         dev_vdbg(tegra210_amixer->dev, "%s reset rx %d", __func__, cif_id);
222         reg = TEGRA210_AMIXER_RX_SOFT_RESET +
223                 (cif_id * TEGRA210_AMIXER_RX_STRIDE);
224
225         regmap_update_bits(tegra210_amixer->regmap, reg,
226                         TEGRA210_AMIXER_RX_SOFT_RESET_EN,
227                         TEGRA210_AMIXER_RX_SOFT_RESET_EN);
228
229         do {
230                 udelay(AHUB_OP_SLEEP_US);
231                 regmap_read(tegra210_amixer->regmap, reg, &val);
232         } while ((val & TEGRA210_AMIXER_RX_SOFT_RESET_EN) && cnt--);
233
234         if (!cnt) {
235                 dev_err(tegra210_amixer->dev, "%s Failed to reset rx %d",
236                                         __func__, cif_id);
237                 return -ETIMEDOUT;
238         }
239
240         return 0;
241 }
242 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_reset);
243
244 /**
245  *  tegra210_amixer_rx_set_act_threshold - sets activation threshold of an input
246  *  @cif : mixer rxcif
247  *  @act_th : activation threshold (in terms of number of frames)
248  */
249 int tegra210_amixer_rx_set_act_threshold(enum tegra210_ahub_cifs cif,
250                                                 int act_th)
251 {
252         u32 reg, cif_id = MIXER_CIF_ID(cif);
253         dev_vdbg(tegra210_amixer->dev, "%s rx %d act_threshold %d", __func__,
254                         cif_id, act_th);
255
256         reg = TEGRA210_AMIXER_RX_CTRL + (cif_id * TEGRA210_AMIXER_RX_STRIDE);
257
258         regmap_update_bits(tegra210_amixer->regmap, reg,
259                 TEGRA210_AMIXER_RX_CTRL_ACT_THRESHOLD_MASK,
260                 act_th << TEGRA210_AMIXER_RX_CTRL_ACT_THRESHOLD_SHIFT);
261
262         return 0;
263 }
264 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_set_act_threshold);
265
266 /**
267  *  tegra210_amixer_rx_set_deact_threshold - sets deactivation threshold of an input
268  *  @cif : mixer rxcif
269  *  @deact_th : deactivation threshold (in terms of mixer clock cycles)
270  */
271 int tegra210_amixer_rx_set_deact_threshold(enum tegra210_ahub_cifs cif,
272                                                 int deact_th)
273 {
274         u32 reg, cif_id = MIXER_CIF_ID(cif);
275         dev_vdbg(tegra210_amixer->dev, "%s rx %d deact_threshold %d", __func__,
276                         cif_id, deact_th);
277
278         reg = TEGRA210_AMIXER_RX_CTRL + (cif_id * TEGRA210_AMIXER_RX_STRIDE);
279
280         regmap_update_bits(tegra210_amixer->regmap, reg,
281                 TEGRA210_AMIXER_RX_CTRL_DEACT_THRESHOLD_MASK,
282                 deact_th << TEGRA210_AMIXER_RX_CTRL_DEACT_THRESHOLD_SHIFT);
283
284         return 0;
285 }
286 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_set_deact_threshold);
287
288 /**
289  *  tegra210_amixer_rx_reset_sample_counter - resets sample count of an input
290  *  @cif : mixer rxcif
291  */
292 int tegra210_amixer_rx_reset_sample_counter(enum tegra210_ahub_cifs cif)
293 {
294         u32 reg, cif_id = MIXER_CIF_ID(cif);
295         dev_vdbg(tegra210_amixer->dev, "%s rx %d", __func__, cif_id);
296
297         reg = TEGRA210_AMIXER_RX_CTRL + (cif_id * TEGRA210_AMIXER_RX_STRIDE);
298
299         regmap_update_bits(tegra210_amixer->regmap, reg,
300                         TEGRA210_AMIXER_RX_CTRL_SAMPLE_COUNTER_RESET_EN,
301                         TEGRA210_AMIXER_RX_CTRL_SAMPLE_COUNTER_RESET_EN);
302
303         udelay(AHUB_OP_SLEEP_US);
304         regmap_update_bits(tegra210_amixer->regmap, reg,
305                         TEGRA210_AMIXER_RX_CTRL_SAMPLE_COUNTER_RESET_EN, 0);
306
307         return 0;
308 }
309 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_reset_sample_counter);
310
311 /**
312  *  tegra210_amixer_rx_bypass_gain - bypasses gain application on an input
313  *  @cif : mixer rxcif
314  *  @en : enable/disable flag
315  */
316 int tegra210_amixer_rx_bypass_gain(enum tegra210_ahub_cifs cif, bool en)
317 {
318         u32 reg, cif_id = MIXER_CIF_ID(cif);
319         dev_vdbg(tegra210_amixer->dev, "%s rx %d bypass %d", __func__,
320                         cif_id, en);
321
322         reg = TEGRA210_AMIXER_RX_CTRL + (cif_id * TEGRA210_AMIXER_RX_STRIDE);
323
324         regmap_update_bits(tegra210_amixer->regmap, reg,
325                         TEGRA210_AMIXER_RX_CTRL_GAIN_BYPASS_EN,
326                         en ? TEGRA210_AMIXER_RX_CTRL_GAIN_BYPASS_EN : 0);
327
328         return 0;
329 }
330 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_bypass_gain);
331
332 /**
333  *  tegra210_amixer_rx_set_gain_coef - sets gain ram coefficients for an input
334  *  @cif : mixer rxcif
335  *  @coef : ptr to coefficients
336  */
337 int tegra210_amixer_rx_set_gain_coef(enum tegra210_ahub_cifs cif, u32 *coef)
338 {
339         u32 cif_id = MIXER_CIF_ID(cif);
340         dev_vdbg(tegra210_amixer->dev, "%s rx %d", __func__, cif_id);
341
342         tegra210_ahubram_write(tegra210_amixer->dev,
343                         TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_CTRL,
344                         TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_DATA,
345                         cif_id * TEGRA210_AMIXER_GAIN_COEF_DEPTH,
346                         coef, TEGRA210_AMIXER_GAIN_COEF_DEPTH);
347
348         return 0;
349 }
350 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_set_gain_coef);
351
352 /**
353  *  tegra210_amixer_rx_set_peak_ctrl - sets peak type and window size on an input
354  *  @cif : mixer rxcif
355  *  @type : peak type (WINDOW_BASED = 0, RESET_ON_READ = 1)
356  *  @win_size : Window size (only applicable for WINDOW_BASED peak type)
357  */
358 int tegra210_amixer_rx_set_peak_ctrl(enum tegra210_ahub_cifs cif, int type,
359                                         unsigned int win_size)
360 {
361         u32 reg, cif_id = MIXER_CIF_ID(cif);
362         dev_vdbg(tegra210_amixer->dev, "%s rx %d peak_type %d win_size %d",
363                                 __func__, cif_id, type, win_size);
364
365         reg = TEGRA210_AMIXER_RX_PEAK_CTRL +
366                 (cif_id * TEGRA210_AMIXER_RX_STRIDE);
367
368         if (type == PEAK_WINDOW_BASED) {
369                 if (win_size > TEGRA210_AMIXER_MAX_PEAK_WIN_SIZE) {
370                         dev_err(tegra210_amixer->dev, "%s Invalid win_size %d",
371                                         __func__, win_size);
372                         return -EINVAL;
373                 }
374
375                 regmap_update_bits(tegra210_amixer->regmap, reg,
376                   TEGRA210_AMIXER_RX_PEAK_CTRL_WIN_SIZE_MASK,
377                   win_size << TEGRA210_AMIXER_RX_PEAK_CTRL_WIN_SIZE_SHIFT);
378         }
379
380         if ((type == PEAK_WINDOW_BASED) || (type == PEAK_RESET_ON_READ))
381                 regmap_update_bits(tegra210_amixer->regmap, reg,
382                         TEGRA210_AMIXER_RX_PEAK_CTRL_PEAK_TYPE_MASK,
383                         type << TEGRA210_AMIXER_RX_PEAK_CTRL_PEAK_TYPE_SHIFT);
384
385         return 0;
386 }
387 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_set_peak_ctrl);
388
389 /**
390  *  tegra210_amixer_rx_get_peak_values - gets peak values on an input for all channels
391  *  @cif : mixer rxcif
392  *  @peak : ptr to be populated with peaks
393  */
394 int tegra210_amixer_rx_get_peak_values(enum tegra210_ahub_cifs cif, u32 *peak)
395 {
396         u32 cif_id = MIXER_CIF_ID(cif);
397         dev_vdbg(tegra210_amixer->dev, "%s rx %d", __func__, cif_id);
398
399         tegra210_ahubram_read(tegra210_amixer->dev,
400                         TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_CTRL,
401                         TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_DATA,
402                         cif_id * TEGRA210_AMIXER_MAX_CHANNEL_COUNT,
403                         peak, TEGRA210_AMIXER_MAX_CHANNEL_COUNT);
404
405         return 0;
406 }
407 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_get_peak_values);
408
409 /**
410  *  tegra210_amixer_rx_get_sample_count - gets sample count on an input
411  *  @cif : mixer rxcif
412  */
413 u32 tegra210_amixer_rx_get_sample_count(enum tegra210_ahub_cifs cif)
414 {
415         u32 reg, sample_cnt = 0, cif_id = MIXER_CIF_ID(cif);
416         dev_vdbg(tegra210_amixer->dev, "%s rx %d", __func__, cif_id);
417
418         reg = TEGRA210_AMIXER_RX_SAMPLE_COUNT +
419                 (cif_id * TEGRA210_AMIXER_RX_STRIDE);
420
421         regmap_read(tegra210_amixer->regmap, reg, &sample_cnt);
422         return sample_cnt;
423 }
424 EXPORT_SYMBOL_GPL(tegra210_amixer_rx_get_sample_count);
425
426 /**
427  *  tegra210_amixer_tx_enable - enables/disables an output
428  *  @cif : mixer txcif
429  *  @en : enable/disable flag
430  */
431 int tegra210_amixer_tx_enable(enum tegra210_ahub_cifs cif, bool en)
432 {
433         u32 reg, cif_id = MIXER_CIF_ID(cif);
434         dev_vdbg(tegra210_amixer->dev, "%s tx %d enable %d", __func__,
435                         cif_id, en);
436
437         reg = TEGRA210_AMIXER_TX_ENABLE + (cif_id * TEGRA210_AMIXER_TX_STRIDE);
438
439         regmap_update_bits(tegra210_amixer->regmap, reg,
440                         TEGRA210_AMIXER_TX_ENABLE_EN,
441                         en ? TEGRA210_AMIXER_TX_ENABLE_EN : 0);
442
443         return 0;
444 }
445 EXPORT_SYMBOL_GPL(tegra210_amixer_tx_enable);
446
447 /**
448  *  tegra210_amixer_tx_reset - soft resets an output
449  *  @cif : mixer txcif
450  */
451 int tegra210_amixer_tx_reset(enum tegra210_ahub_cifs cif)
452 {
453         u32 val = 0, reg, cif_id = MIXER_CIF_ID(cif);
454         int cnt = AHUB_OP_MAX_RETRY;
455
456         dev_vdbg(tegra210_amixer->dev, "%s reset tx %d", __func__, cif_id);
457         reg = TEGRA210_AMIXER_TX_SOFT_RESET +
458                 (cif_id * TEGRA210_AMIXER_TX_STRIDE);
459
460         regmap_update_bits(tegra210_amixer->regmap, reg,
461                         TEGRA210_AMIXER_TX_SOFT_RESET_EN,
462                         TEGRA210_AMIXER_TX_SOFT_RESET_EN);
463
464         do {
465                 udelay(AHUB_OP_SLEEP_US);
466                 regmap_read(tegra210_amixer->regmap, reg, &val);
467         } while ((val & TEGRA210_AMIXER_TX_SOFT_RESET_EN) && cnt--);
468
469         if (!cnt) {
470                 dev_err(tegra210_amixer->dev, "%s Failed to reset tx %d",
471                                         __func__, cif_id);
472                 return -ETIMEDOUT;
473         }
474
475         return 0;
476 }
477 EXPORT_SYMBOL_GPL(tegra210_amixer_tx_reset);
478
479 /**
480  *  tegra210_amixer_tx_enable_input - enables/disables input to be mixed on an output
481  *  @txcif : mixer txcif
482  *  @rxcif : mixer rxcif
483  *  @en : enable/disable flag
484  */
485 int tegra210_amixer_tx_enable_input(enum tegra210_ahub_cifs txcif,
486                                         enum tegra210_ahub_cifs rxcif, bool en)
487 {
488         u32 reg, txcif_id = MIXER_CIF_ID(txcif), rxcif_id = MIXER_CIF_ID(rxcif);
489         dev_vdbg(tegra210_amixer->dev, "%s tx %d : rx %d enable %d",
490                                 __func__, txcif_id, rxcif_id, en);
491
492         reg = TEGRA210_AMIXER_TX_ADDER_CONFIG +
493                 (txcif_id * TEGRA210_AMIXER_TX_STRIDE);
494
495         regmap_update_bits(tegra210_amixer->regmap, reg,
496           TEGRA210_AMIXER_TX_ADDER_CONFIG_INPUT_ENABLE(rxcif_id),
497           en ? TEGRA210_AMIXER_TX_ADDER_CONFIG_INPUT_ENABLE(rxcif_id) : 0);
498
499         return 0;
500 }
501 EXPORT_SYMBOL_GPL(tegra210_amixer_tx_enable_input);
502
503 /* Regmap callback functions */
504 static bool tegra210_amixer_wr_reg(struct device *dev, unsigned int reg)
505 {
506         if (reg < TEGRA210_AMIXER_RX_LIMIT)
507                 reg %= TEGRA210_AMIXER_RX_STRIDE;
508         else if (reg < TEGRA210_AMIXER_TX_LIMIT)
509                 reg = (reg % TEGRA210_AMIXER_TX_STRIDE) +
510                         TEGRA210_AMIXER_TX_ENABLE;
511
512         switch (reg) {
513         case TEGRA210_AMIXER_RX_SOFT_RESET:
514         case TEGRA210_AMIXER_RX_CIF_CTRL:
515         case TEGRA210_AMIXER_RX_CTRL:
516         case TEGRA210_AMIXER_RX_PEAK_CTRL:
517
518         case TEGRA210_AMIXER_TX_ENABLE:
519         case TEGRA210_AMIXER_TX_SOFT_RESET:
520         case TEGRA210_AMIXER_TX_INT_MASK:
521         case TEGRA210_AMIXER_TX_INT_SET:
522         case TEGRA210_AMIXER_TX_INT_CLEAR:
523         case TEGRA210_AMIXER_TX_CIF_CTRL:
524         case TEGRA210_AMIXER_TX_ADDER_CONFIG:
525
526         case TEGRA210_AMIXER_ENABLE:
527         case TEGRA210_AMIXER_SOFT_RESET:
528         case TEGRA210_AMIXER_CG:
529         case TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_CTRL:
530         case TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_DATA:
531         case TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_CTRL:
532         case TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_DATA:
533         case TEGRA210_AMIXER_CTRL:
534                 return true;
535         default:
536                 return false;
537         };
538 }
539
540 static bool tegra210_amixer_rd_reg(struct device *dev, unsigned int reg)
541 {
542         if (reg < TEGRA210_AMIXER_RX_LIMIT)
543                 reg %= TEGRA210_AMIXER_RX_STRIDE;
544         else if (reg < TEGRA210_AMIXER_TX_LIMIT)
545                 reg = (reg % TEGRA210_AMIXER_TX_STRIDE) +
546                         TEGRA210_AMIXER_TX_ENABLE;
547
548         switch (reg) {
549         case TEGRA210_AMIXER_RX_SOFT_RESET:
550         case TEGRA210_AMIXER_RX_STATUS:
551         case TEGRA210_AMIXER_RX_CIF_CTRL:
552         case TEGRA210_AMIXER_RX_CTRL:
553         case TEGRA210_AMIXER_RX_PEAK_CTRL:
554         case TEGRA210_AMIXER_RX_SAMPLE_COUNT:
555
556         case TEGRA210_AMIXER_TX_ENABLE:
557         case TEGRA210_AMIXER_TX_SOFT_RESET:
558         case TEGRA210_AMIXER_TX_STATUS:
559         case TEGRA210_AMIXER_TX_INT_STATUS:
560         case TEGRA210_AMIXER_TX_INT_MASK:
561         case TEGRA210_AMIXER_TX_INT_SET:
562         case TEGRA210_AMIXER_TX_INT_CLEAR:
563         case TEGRA210_AMIXER_TX_CIF_CTRL:
564         case TEGRA210_AMIXER_TX_ADDER_CONFIG:
565
566         case TEGRA210_AMIXER_ENABLE:
567         case TEGRA210_AMIXER_SOFT_RESET:
568         case TEGRA210_AMIXER_CG:
569         case TEGRA210_AMIXER_STATUS:
570         case TEGRA210_AMIXER_INT_STATUS:
571         case TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_CTRL:
572         case TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_DATA:
573         case TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_CTRL:
574         case TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_DATA:
575         case TEGRA210_AMIXER_CTRL:
576                 return true;
577         default:
578                 return false;
579         };
580 }
581
582 static bool tegra210_amixer_volatile_reg(struct device *dev, unsigned int reg)
583 {
584         if (reg < TEGRA210_AMIXER_RX_LIMIT)
585                 reg %= TEGRA210_AMIXER_RX_STRIDE;
586         else if (reg < TEGRA210_AMIXER_TX_LIMIT)
587                 reg = (reg % TEGRA210_AMIXER_TX_STRIDE) +
588                         TEGRA210_AMIXER_TX_ENABLE;
589
590         switch (reg) {
591         case TEGRA210_AMIXER_RX_SOFT_RESET:
592         case TEGRA210_AMIXER_RX_STATUS:
593
594         case TEGRA210_AMIXER_TX_SOFT_RESET:
595         case TEGRA210_AMIXER_TX_STATUS:
596         case TEGRA210_AMIXER_TX_INT_STATUS:
597         case TEGRA210_AMIXER_TX_INT_SET:
598
599         case TEGRA210_AMIXER_SOFT_RESET:
600         case TEGRA210_AMIXER_STATUS:
601         case TEGRA210_AMIXER_INT_STATUS:
602         case TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_CTRL:
603         case TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_DATA:
604         case TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_CTRL:
605         case TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_DATA:
606                 return true;
607         default:
608                 return false;
609         };
610 }
611
612 static bool tegra210_amixer_precious_reg(struct device *dev, unsigned int reg)
613 {
614         switch (reg) {
615         case TEGRA210_AMIXER_AHUBRAMCTL_GAIN_CONFIG_DATA:
616         case TEGRA210_AMIXER_AHUBRAMCTL_PEAKM_DATA:
617                 return true;
618         default:
619                 return false;
620         };
621 }
622
623 static const struct regmap_config tegra210_amixer_regmap_config = {
624         .reg_bits = 32,
625         .reg_stride = 4,
626         .val_bits = 32,
627         .max_register = TEGRA210_AMIXER_CTRL,
628         .writeable_reg = tegra210_amixer_wr_reg,
629         .readable_reg = tegra210_amixer_rd_reg,
630         .volatile_reg = tegra210_amixer_volatile_reg,
631         .precious_reg = tegra210_amixer_precious_reg,
632         .cache_type = REGCACHE_RBTREE,
633 };
634
635 /* PM runtime callback functions */
636 static int tegra210_amixer_runtime_suspend(struct device *dev)
637 {
638         struct tegra210_amixer_ctx *amixer = dev_get_drvdata(dev);
639
640         dev_dbg(amixer->dev, "%s amixer", __func__);
641         tegra210_axbar_disable_clk();
642         regcache_cache_only(amixer->regmap, true);
643
644         return 0;
645 }
646
647 static int tegra210_amixer_runtime_resume(struct device *dev)
648 {
649         struct tegra210_amixer_ctx *amixer = dev_get_drvdata(dev);
650
651         dev_dbg(amixer->dev, "%s amixer", __func__);
652         tegra210_axbar_enable_clk();
653         regcache_cache_only(amixer->regmap, false);
654
655         return 0;
656 }
657
658 /* AMIXER driver probe and remove functions */
659 static int tegra210_amixer_probe(struct platform_device *pdev)
660 {
661         struct resource *res, *region;
662         struct tegra210_amixer_ctx *amixer;
663         int ret = 0;
664
665         if (!pdev->dev.of_node) {
666                 dev_err(&pdev->dev, "%s fail, no DT node for AMIXER", __func__);
667                 return -EINVAL;
668         }
669
670         of_property_read_u32(pdev->dev.of_node, "nvidia,ahub-amixer-id",
671                                                  &pdev->id);
672
673         dev_dbg(&pdev->dev, "%s amixer : starting probe", __func__);
674
675         tegra210_amixer = devm_kzalloc(&pdev->dev,
676                            sizeof(struct tegra210_amixer_ctx), GFP_KERNEL);
677         if (!tegra210_amixer) {
678                 dev_err(&pdev->dev, "Can't allocate amixer context\n");
679                 ret = -ENOMEM;
680                 goto exit;
681         }
682         tegra210_amixer->dev = &pdev->dev;
683
684         amixer = tegra210_amixer;
685         dev_set_drvdata(&pdev->dev, amixer);
686
687         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
688         if (!res) {
689                 dev_err(&pdev->dev, "No memory 0 resource\n");
690                 ret = -ENODEV;
691                 goto err_free;
692         }
693
694         region = devm_request_mem_region(&pdev->dev, res->start,
695                         resource_size(res), pdev->name);
696         if (!region) {
697                 dev_err(&pdev->dev, "Memory region 0 already claimed\n");
698                 ret = -EBUSY;
699                 goto err_free;
700         }
701
702         amixer->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
703         if (!amixer->regs) {
704                 dev_err(&pdev->dev, "ioremap 0 failed\n");
705                 ret = -ENOMEM;
706                 goto err_free;
707         }
708
709         amixer->regmap = devm_regmap_init_mmio(&pdev->dev, amixer->regs,
710                                             &tegra210_amixer_regmap_config);
711         if (IS_ERR(amixer->regmap)) {
712                 dev_err(&pdev->dev, "regmap init failed\n");
713                 ret = PTR_ERR(amixer->regmap);
714                 goto err_free;
715         }
716         regcache_cache_only(amixer->regmap, true);
717
718         pm_runtime_enable(&pdev->dev);
719         if (!pm_runtime_enabled(&pdev->dev)) {
720                 ret = tegra210_amixer_runtime_resume(&pdev->dev);
721                 if (ret)
722                         goto err_pm_disable;
723         }
724
725         dev_dbg(amixer->dev, "%s amixer probe successful", __func__);
726
727         return 0;
728
729 err_pm_disable:
730         pm_runtime_disable(&pdev->dev);
731 err_free:
732         tegra210_amixer = NULL;
733 exit:
734         dev_dbg(&pdev->dev, "%s amixer probe failed with %d", __func__, ret);
735         return ret;
736 }
737
738 static int tegra210_amixer_remove(struct platform_device *pdev)
739 {
740         struct tegra210_amixer_ctx *amixer;
741
742         pm_runtime_disable(&pdev->dev);
743         if (!pm_runtime_status_suspended(&pdev->dev))
744                 tegra210_amixer_runtime_suspend(&pdev->dev);
745
746         amixer = platform_get_drvdata(pdev);
747         tegra210_amixer = NULL;
748
749         dev_dbg(&pdev->dev, "%s amixer %d removed",
750                 __func__, pdev->id);
751
752         return 0;
753 }
754
755 static const struct of_device_id tegra210_amixer_of_match[] = {
756         { .compatible = "nvidia,tegra210-amixer",},
757         {},
758 };
759
760 static const struct dev_pm_ops tegra210_amixer_pm_ops = {
761         SET_RUNTIME_PM_OPS(tegra210_amixer_runtime_suspend,
762                            tegra210_amixer_runtime_resume, NULL)
763 };
764
765 static struct platform_driver tegra210_amixer_driver = {
766         .driver = {
767                 .name = DRV_NAME,
768                 .owner = THIS_MODULE,
769                 .of_match_table = tegra210_amixer_of_match,
770                 .pm = &tegra210_amixer_pm_ops,
771         },
772         .probe = tegra210_amixer_probe,
773         .remove = tegra210_amixer_remove,
774 };
775 module_platform_driver(tegra210_amixer_driver);
776
777 MODULE_AUTHOR("Rahul Mittal <rmittal@nvidia.com>");
778 MODULE_DESCRIPTION("Tegra210 AMIXER driver");
779 MODULE_LICENSE("GPL");
780 MODULE_ALIAS("platform:" DRV_NAME);