blob: 5d74469d5cbfd06c09ddc90a88ae3b326aa3ebe2 [file] [log] [blame]
Joonwoo Park11133b82013-01-03 17:26:38 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Joonwoo Parka8890262012-10-15 12:04:27 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/firmware.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/device.h>
18#include <linux/printk.h>
19#include <linux/ratelimit.h>
20#include <linux/debugfs.h>
21#include <linux/mfd/wcd9xxx/core.h>
22#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
23#include <linux/mfd/wcd9xxx/wcd9320_registers.h>
24#include <linux/mfd/wcd9xxx/pdata.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28#include <sound/soc-dapm.h>
29#include <sound/tlv.h>
30#include <linux/bitops.h>
31#include <linux/delay.h>
32#include <linux/pm_runtime.h>
33#include <linux/kernel.h>
34#include <linux/gpio.h>
35#include "wcd9xxx-resmgr.h"
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -070036#include "msm8x10_wcd_registers.h"
Joonwoo Parka8890262012-10-15 12:04:27 -070037
38static char wcd9xxx_event_string[][64] = {
39 "WCD9XXX_EVENT_INVALID",
40
41 "WCD9XXX_EVENT_PRE_RCO_ON",
42 "WCD9XXX_EVENT_POST_RCO_ON",
43 "WCD9XXX_EVENT_PRE_RCO_OFF",
44 "WCD9XXX_EVENT_POST_RCO_OFF",
45
46 "WCD9XXX_EVENT_PRE_MCLK_ON",
47 "WCD9XXX_EVENT_POST_MCLK_ON",
48 "WCD9XXX_EVENT_PRE_MCLK_OFF",
49 "WCD9XXX_EVENT_POST_MCLK_OFF",
50
51 "WCD9XXX_EVENT_PRE_BG_OFF",
52 "WCD9XXX_EVENT_POST_BG_OFF",
53 "WCD9XXX_EVENT_PRE_BG_AUDIO_ON",
54 "WCD9XXX_EVENT_POST_BG_AUDIO_ON",
55 "WCD9XXX_EVENT_PRE_BG_MBHC_ON",
56 "WCD9XXX_EVENT_POST_BG_MBHC_ON",
57
58 "WCD9XXX_EVENT_PRE_MICBIAS_1_OFF",
59 "WCD9XXX_EVENT_POST_MICBIAS_1_OFF",
60 "WCD9XXX_EVENT_PRE_MICBIAS_2_OFF",
61 "WCD9XXX_EVENT_POST_MICBIAS_2_OFF",
62 "WCD9XXX_EVENT_PRE_MICBIAS_3_OFF",
63 "WCD9XXX_EVENT_POST_MICBIAS_3_OFF",
64 "WCD9XXX_EVENT_PRE_MICBIAS_4_OFF",
65 "WCD9XXX_EVENT_POST_MICBIAS_4_OFF",
66 "WCD9XXX_EVENT_PRE_MICBIAS_1_ON",
67 "WCD9XXX_EVENT_POST_MICBIAS_1_ON",
68 "WCD9XXX_EVENT_PRE_MICBIAS_2_ON",
69 "WCD9XXX_EVENT_POST_MICBIAS_2_ON",
70 "WCD9XXX_EVENT_PRE_MICBIAS_3_ON",
71 "WCD9XXX_EVENT_POST_MICBIAS_3_ON",
72 "WCD9XXX_EVENT_PRE_MICBIAS_4_ON",
73 "WCD9XXX_EVENT_POST_MICBIAS_4_ON",
74
75 "WCD9XXX_EVENT_PRE_CFILT_1_OFF",
76 "WCD9XXX_EVENT_POST_CFILT_1_OFF",
77 "WCD9XXX_EVENT_PRE_CFILT_2_OFF",
78 "WCD9XXX_EVENT_POST_CFILT_2_OFF",
79 "WCD9XXX_EVENT_PRE_CFILT_3_OFF",
80 "WCD9XXX_EVENT_POST_CFILT_3_OFF",
81 "WCD9XXX_EVENT_PRE_CFILT_1_ON",
82 "WCD9XXX_EVENT_POST_CFILT_1_ON",
83 "WCD9XXX_EVENT_PRE_CFILT_2_ON",
84 "WCD9XXX_EVENT_POST_CFILT_2_ON",
85 "WCD9XXX_EVENT_PRE_CFILT_3_ON",
86 "WCD9XXX_EVENT_POST_CFILT_3_ON",
87
88 "WCD9XXX_EVENT_PRE_HPHL_PA_ON",
89 "WCD9XXX_EVENT_POST_HPHL_PA_OFF",
90 "WCD9XXX_EVENT_PRE_HPHR_PA_ON",
91 "WCD9XXX_EVENT_POST_HPHR_PA_OFF",
92
93 "WCD9XXX_EVENT_POST_RESUME",
94
95 "WCD9XXX_EVENT_LAST",
96};
97
Joonwoo Parkcc52d472013-01-28 10:10:12 -080098struct wcd9xxx_resmgr_cond_entry {
99 unsigned short reg;
100 int shift;
101 bool invert;
102 enum wcd9xxx_resmgr_cond cond;
103 struct list_head list;
104};
105
Joonwoo Parka8890262012-10-15 12:04:27 -0700106static enum wcd9xxx_clock_type wcd9xxx_save_clock(struct wcd9xxx_resmgr
107 *resmgr);
108static void wcd9xxx_restore_clock(struct wcd9xxx_resmgr *resmgr,
109 enum wcd9xxx_clock_type type);
110
111const char *wcd9xxx_get_event_string(enum wcd9xxx_notify_event type)
112{
113 return wcd9xxx_event_string[type];
114}
115
116void wcd9xxx_resmgr_notifier_call(struct wcd9xxx_resmgr *resmgr,
117 const enum wcd9xxx_notify_event e)
118{
119 pr_debug("%s: notifier call event %d\n", __func__, e);
120 blocking_notifier_call_chain(&resmgr->notifier, e, resmgr);
121}
122
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -0700123static void wcd9xxx_disable_bg(struct wcd9xxx_resmgr *resmgr)
Joonwoo Parka8890262012-10-15 12:04:27 -0700124{
125 /* Notify bg mode change */
126 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_OFF);
127 /* Disable bg */
Joonwoo Park11133b82013-01-03 17:26:38 -0800128 snd_soc_update_bits(resmgr->codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
129 0x03, 0x00);
Joonwoo Parka8890262012-10-15 12:04:27 -0700130 usleep_range(100, 100);
131 /* Notify bg mode change */
132 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_OFF);
133}
134
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -0700135/*
136 * BG enablement should always enable in slow mode.
137 * The fast mode doesn't need to be enabled as fast mode BG is to be driven
138 * by MBHC override.
139 */
140static void wcd9xxx_enable_bg(struct wcd9xxx_resmgr *resmgr)
Joonwoo Parka8890262012-10-15 12:04:27 -0700141{
142 struct snd_soc_codec *codec = resmgr->codec;
143
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -0700144 /* Enable BG in slow mode and precharge */
Joonwoo Parka8890262012-10-15 12:04:27 -0700145 snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x80, 0x80);
146 snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x04, 0x04);
147 snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x01, 0x01);
148 usleep_range(1000, 1000);
149 snd_soc_update_bits(codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x80, 0x00);
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -0700150}
151
152static void wcd9xxx_enable_bg_audio(struct wcd9xxx_resmgr *resmgr)
153{
154 /* Notify bandgap mode change */
155 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_AUDIO_ON);
156 wcd9xxx_enable_bg(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700157 /* Notify bandgap mode change */
158 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_AUDIO_ON);
159}
160
161static void wcd9xxx_enable_bg_mbhc(struct wcd9xxx_resmgr *resmgr)
162{
163 struct snd_soc_codec *codec = resmgr->codec;
164
165 /* Notify bandgap mode change */
166 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_MBHC_ON);
167
168 /*
Joonwoo Parka8890262012-10-15 12:04:27 -0700169 * mclk should be off or clk buff source souldn't be VBG
170 * Let's turn off mclk always
171 */
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700172 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
173 WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
174
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -0700175 wcd9xxx_enable_bg(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700176 /* Notify bandgap mode change */
177 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_MBHC_ON);
178}
179
Joonwoo Parka8890262012-10-15 12:04:27 -0700180static void wcd9xxx_disable_clock_block(struct wcd9xxx_resmgr *resmgr)
181{
182 struct snd_soc_codec *codec = resmgr->codec;
183
184 pr_debug("%s: enter\n", __func__);
Joonwoo Park533b3682013-06-13 11:41:21 -0700185 WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700186
187 /* Notify */
188 if (resmgr->clk_type == WCD9XXX_CLK_RCO)
189 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_RCO_OFF);
190 else
191 wcd9xxx_resmgr_notifier_call(resmgr,
192 WCD9XXX_EVENT_PRE_MCLK_OFF);
193 /* Disable clock */
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700194 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
195 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
196 usleep_range(50, 50);
197 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
198 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
199 usleep_range(50, 50);
200 }
Joonwoo Parka8890262012-10-15 12:04:27 -0700201 /* Notify */
Bhalchandra Gajarebe8bba02013-09-25 16:36:34 -0700202 if (resmgr->clk_type == WCD9XXX_CLK_RCO) {
Joonwoo Parka8890262012-10-15 12:04:27 -0700203 wcd9xxx_resmgr_notifier_call(resmgr,
204 WCD9XXX_EVENT_POST_RCO_OFF);
Bhalchandra Gajarebe8bba02013-09-25 16:36:34 -0700205 } else {
206 if (resmgr->codec_type == WCD9XXX_CDC_TYPE_HELICON)
207 snd_soc_update_bits(codec,
208 MSM8X10_WCD_A_CDC_CLK_PDM_CTL, 0x03, 0x00);
209
Joonwoo Parka8890262012-10-15 12:04:27 -0700210 wcd9xxx_resmgr_notifier_call(resmgr,
211 WCD9XXX_EVENT_POST_MCLK_OFF);
Bhalchandra Gajarebe8bba02013-09-25 16:36:34 -0700212 }
Joonwoo Parka8890262012-10-15 12:04:27 -0700213 pr_debug("%s: leave\n", __func__);
214}
215
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800216void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr)
217{
218 int old_bg_audio_users, old_bg_mbhc_users;
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -0800219 int old_clk_rco_users, old_clk_mclk_users;
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800220
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -0800221 pr_debug("%s: enter\n", __func__);
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800222
Joonwoo Park973fd352013-06-19 11:38:53 -0700223 WCD9XXX_BG_CLK_LOCK(resmgr);
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800224 old_bg_audio_users = resmgr->bg_audio_users;
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800225 old_bg_mbhc_users = resmgr->bg_mbhc_users;
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -0800226 old_clk_rco_users = resmgr->clk_rco_users;
227 old_clk_mclk_users = resmgr->clk_mclk_users;
228 resmgr->bg_audio_users = 0;
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800229 resmgr->bg_mbhc_users = 0;
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -0800230 resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
231 resmgr->clk_rco_users = 0;
232 resmgr->clk_mclk_users = 0;
233 resmgr->clk_type = WCD9XXX_CLK_OFF;
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800234
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -0800235 if (old_bg_audio_users) {
236 while (old_bg_audio_users--)
237 wcd9xxx_resmgr_get_bandgap(resmgr,
238 WCD9XXX_BANDGAP_AUDIO_MODE);
239 }
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800240
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -0800241 if (old_bg_mbhc_users) {
242 while (old_bg_mbhc_users--)
243 wcd9xxx_resmgr_get_bandgap(resmgr,
244 WCD9XXX_BANDGAP_MBHC_MODE);
245 }
246
247 if (old_clk_mclk_users) {
248 while (old_clk_mclk_users--)
249 wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_MCLK);
250 }
251
252 if (old_clk_rco_users) {
253 while (old_clk_rco_users--)
254 wcd9xxx_resmgr_get_clk_block(resmgr, WCD9XXX_CLK_RCO);
255 }
Joonwoo Park973fd352013-06-19 11:38:53 -0700256 WCD9XXX_BG_CLK_UNLOCK(resmgr);
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -0800257 pr_debug("%s: leave\n", __func__);
Ravishankar Sarawadi839fcf32012-11-14 12:13:00 -0800258}
259
Joonwoo Parka8890262012-10-15 12:04:27 -0700260/*
261 * wcd9xxx_resmgr_get_bandgap : Vote for bandgap ref
262 * choice : WCD9XXX_BANDGAP_AUDIO_MODE, WCD9XXX_BANDGAP_MBHC_MODE
263 */
264void wcd9xxx_resmgr_get_bandgap(struct wcd9xxx_resmgr *resmgr,
265 const enum wcd9xxx_bandgap_type choice)
266{
267 enum wcd9xxx_clock_type clock_save;
268
269 pr_debug("%s: enter, wants %d\n", __func__, choice);
270
Joonwoo Park533b3682013-06-13 11:41:21 -0700271 WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700272 switch (choice) {
273 case WCD9XXX_BANDGAP_AUDIO_MODE:
274 resmgr->bg_audio_users++;
275 if (resmgr->bg_audio_users == 1 && resmgr->bg_mbhc_users) {
276 /*
277 * Current bg is MBHC mode, about to switch to
278 * audio mode.
279 */
280 WARN_ON(resmgr->bandgap_type !=
281 WCD9XXX_BANDGAP_MBHC_MODE);
282
283 /* BG mode can be changed only with clock off */
284 clock_save = wcd9xxx_save_clock(resmgr);
285 /* Swtich BG mode */
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -0700286 wcd9xxx_disable_bg(resmgr);
287 wcd9xxx_enable_bg_audio(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700288 /* restore clock */
289 wcd9xxx_restore_clock(resmgr, clock_save);
290 } else if (resmgr->bg_audio_users == 1) {
291 /* currently off, just enable it */
292 WARN_ON(resmgr->bandgap_type != WCD9XXX_BANDGAP_OFF);
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -0700293 wcd9xxx_enable_bg_audio(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700294 }
295 resmgr->bandgap_type = WCD9XXX_BANDGAP_AUDIO_MODE;
296 break;
297 case WCD9XXX_BANDGAP_MBHC_MODE:
298 resmgr->bg_mbhc_users++;
299 if (resmgr->bandgap_type == WCD9XXX_BANDGAP_MBHC_MODE ||
300 resmgr->bandgap_type == WCD9XXX_BANDGAP_AUDIO_MODE)
301 /* do nothing */
302 break;
303
304 /* bg mode can be changed only with clock off */
305 clock_save = wcd9xxx_save_clock(resmgr);
306 /* enable bg with MBHC mode */
307 wcd9xxx_enable_bg_mbhc(resmgr);
308 /* restore clock */
309 wcd9xxx_restore_clock(resmgr, clock_save);
310 /* save current mode */
311 resmgr->bandgap_type = WCD9XXX_BANDGAP_MBHC_MODE;
312 break;
313 default:
314 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
315 break;
316 }
317
318 pr_debug("%s: bg users audio %d, mbhc %d\n", __func__,
319 resmgr->bg_audio_users, resmgr->bg_mbhc_users);
320}
321
322/*
323 * wcd9xxx_resmgr_put_bandgap : Unvote bandgap ref that has been voted
324 * choice : WCD9XXX_BANDGAP_AUDIO_MODE, WCD9XXX_BANDGAP_MBHC_MODE
325 */
326void wcd9xxx_resmgr_put_bandgap(struct wcd9xxx_resmgr *resmgr,
327 enum wcd9xxx_bandgap_type choice)
328{
329 enum wcd9xxx_clock_type clock_save;
330
331 pr_debug("%s: enter choice %d\n", __func__, choice);
332
Joonwoo Park533b3682013-06-13 11:41:21 -0700333 WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700334 switch (choice) {
335 case WCD9XXX_BANDGAP_AUDIO_MODE:
336 if (--resmgr->bg_audio_users == 0) {
337 if (resmgr->bg_mbhc_users) {
338 /* bg mode can be changed only with clock off */
339 clock_save = wcd9xxx_save_clock(resmgr);
340 /* switch to MBHC mode */
341 wcd9xxx_enable_bg_mbhc(resmgr);
342 /* restore clock */
343 wcd9xxx_restore_clock(resmgr, clock_save);
344 resmgr->bandgap_type =
345 WCD9XXX_BANDGAP_MBHC_MODE;
346 } else {
347 /* turn off */
348 wcd9xxx_disable_bg(resmgr);
349 resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
350 }
351 }
352 break;
353 case WCD9XXX_BANDGAP_MBHC_MODE:
354 WARN(resmgr->bandgap_type == WCD9XXX_BANDGAP_OFF,
355 "Unexpected bandgap type %d\n", resmgr->bandgap_type);
356 if (--resmgr->bg_mbhc_users == 0 &&
357 resmgr->bandgap_type == WCD9XXX_BANDGAP_MBHC_MODE) {
358 wcd9xxx_disable_bg(resmgr);
359 resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
360 }
361 break;
362 default:
363 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
364 break;
365 }
366
367 pr_debug("%s: bg users audio %d, mbhc %d\n", __func__,
368 resmgr->bg_audio_users, resmgr->bg_mbhc_users);
369}
370
371void wcd9xxx_resmgr_enable_rx_bias(struct wcd9xxx_resmgr *resmgr, u32 enable)
372{
373 struct snd_soc_codec *codec = resmgr->codec;
374
375 if (enable) {
376 resmgr->rx_bias_count++;
377 if (resmgr->rx_bias_count == 1)
378 snd_soc_update_bits(codec, WCD9XXX_A_RX_COM_BIAS,
379 0x80, 0x80);
380 } else {
381 resmgr->rx_bias_count--;
382 if (!resmgr->rx_bias_count)
383 snd_soc_update_bits(codec, WCD9XXX_A_RX_COM_BIAS,
384 0x80, 0x00);
385 }
386}
387
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700388int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr, int enable)
Joonwoo Parka8890262012-10-15 12:04:27 -0700389{
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700390 struct snd_soc_codec *codec = resmgr->codec;
391
Joonwoo Parka8890262012-10-15 12:04:27 -0700392 pr_debug("%s: enable = %d\n", __func__, enable);
393 if (enable) {
394 snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0);
395 /* bandgap mode to fast */
396 snd_soc_write(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17);
397 usleep_range(5, 5);
398 snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x80);
399 snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x80);
400 usleep_range(10, 10);
401 snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0);
402 usleep_range(10000, 10000);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700403 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
404 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
405 0x08, 0x08);
406 else
407 snd_soc_update_bits(codec,
408 MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
409 0x20, 0x20);
Joonwoo Parka8890262012-10-15 12:04:27 -0700410 } else {
411 snd_soc_update_bits(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x1, 0);
412 snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700413 if (resmgr->codec_type == WCD9XXX_CDC_TYPE_HELICON)
414 snd_soc_update_bits(codec,
415 MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
416 0x20, 0x00);
Joonwoo Parka8890262012-10-15 12:04:27 -0700417 }
418
419 return 0;
420}
421
422static void wcd9xxx_enable_clock_block(struct wcd9xxx_resmgr *resmgr,
423 int config_mode)
424{
425 struct snd_soc_codec *codec = resmgr->codec;
426
427 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700428
Joonwoo Parka8890262012-10-15 12:04:27 -0700429 /* transit to RCO requires mclk off */
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700430 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
431 WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
432
Joonwoo Parka8890262012-10-15 12:04:27 -0700433 if (config_mode) {
434 /* Notify */
435 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_RCO_ON);
436 /* enable RCO and switch to it */
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700437 wcd9xxx_resmgr_enable_config_mode(resmgr, 1);
438 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
439 snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
Joonwoo Parka8890262012-10-15 12:04:27 -0700440 usleep_range(1000, 1000);
441 } else {
442 /* Notify */
443 wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_MCLK_ON);
444 /* switch to MCLK */
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700445 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
446 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
447 0x08, 0x00);
448 } else {
449 snd_soc_update_bits(codec,
450 MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
451 0x03, 0x03);
452 snd_soc_update_bits(codec,
453 MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
454 0x0f, 0x0d);
455 }
Joonwoo Parka8890262012-10-15 12:04:27 -0700456 /* if RCO is enabled, switch from it */
457 if (snd_soc_read(codec, WCD9XXX_A_RC_OSC_FREQ) & 0x80) {
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700458 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
459 snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2,
460 0x02);
461 wcd9xxx_resmgr_enable_config_mode(resmgr, 0);
Joonwoo Parka8890262012-10-15 12:04:27 -0700462 }
Bhalchandra Gajare27259302013-03-28 16:56:59 -0700463 /* clk source to ext clk and clk buff ref to VBG */
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700464 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
465 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
466 0x0C, 0x04);
Joonwoo Parka8890262012-10-15 12:04:27 -0700467 }
468
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700469 if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
470 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
471 /* sleep required by codec hardware to enable clock buffer */
472 usleep_range(1000, 1200);
473 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
474 /* on MCLK */
475 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
476 snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL,
477 0x01, 0x01);
478 } else {
479 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
480 0x01, 0x01);
481 }
Joonwoo Parka8890262012-10-15 12:04:27 -0700482 usleep_range(50, 50);
483
484 /* Notify */
485 if (config_mode)
486 wcd9xxx_resmgr_notifier_call(resmgr,
487 WCD9XXX_EVENT_POST_RCO_ON);
488 else
489 wcd9xxx_resmgr_notifier_call(resmgr,
490 WCD9XXX_EVENT_POST_MCLK_ON);
491}
492
493/*
494 * disable clock and return previous clock state
495 */
496static enum wcd9xxx_clock_type wcd9xxx_save_clock(struct wcd9xxx_resmgr *resmgr)
497{
Joonwoo Park533b3682013-06-13 11:41:21 -0700498 WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700499 if (resmgr->clk_type != WCD9XXX_CLK_OFF)
500 wcd9xxx_disable_clock_block(resmgr);
501 return resmgr->clk_type != WCD9XXX_CLK_OFF;
502}
503
504static void wcd9xxx_restore_clock(struct wcd9xxx_resmgr *resmgr,
505 enum wcd9xxx_clock_type type)
506{
507 if (type != WCD9XXX_CLK_OFF)
508 wcd9xxx_enable_clock_block(resmgr, type == WCD9XXX_CLK_RCO);
509}
510
511void wcd9xxx_resmgr_get_clk_block(struct wcd9xxx_resmgr *resmgr,
512 enum wcd9xxx_clock_type type)
513{
514 pr_debug("%s: current %d, requested %d, rco_users %d, mclk_users %d\n",
515 __func__, resmgr->clk_type, type,
516 resmgr->clk_rco_users, resmgr->clk_mclk_users);
Joonwoo Park533b3682013-06-13 11:41:21 -0700517 WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700518 switch (type) {
519 case WCD9XXX_CLK_RCO:
520 if (++resmgr->clk_rco_users == 1 &&
521 resmgr->clk_type == WCD9XXX_CLK_OFF) {
522 /* enable RCO and switch to it */
523 wcd9xxx_enable_clock_block(resmgr, 1);
524 resmgr->clk_type = WCD9XXX_CLK_RCO;
525 }
526 break;
527 case WCD9XXX_CLK_MCLK:
528 if (++resmgr->clk_mclk_users == 1 &&
529 resmgr->clk_type == WCD9XXX_CLK_OFF) {
530 /* switch to MCLK */
531 wcd9xxx_enable_clock_block(resmgr, 0);
532 resmgr->clk_type = WCD9XXX_CLK_MCLK;
533 } else if (resmgr->clk_mclk_users == 1 &&
534 resmgr->clk_type == WCD9XXX_CLK_RCO) {
535 /* if RCO is enabled, switch from it */
536 WARN_ON(!(snd_soc_read(resmgr->codec,
537 WCD9XXX_A_RC_OSC_FREQ) & 0x80));
538 /* disable clock block */
539 wcd9xxx_disable_clock_block(resmgr);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700540 /* switch to MCLK */
Joonwoo Parka8890262012-10-15 12:04:27 -0700541 wcd9xxx_enable_clock_block(resmgr, 0);
542 resmgr->clk_type = WCD9XXX_CLK_MCLK;
543 }
544 break;
545 default:
546 pr_err("%s: Error, Invalid clock get request %d\n", __func__,
547 type);
548 break;
549 }
550 pr_debug("%s: leave\n", __func__);
551}
552
553void wcd9xxx_resmgr_put_clk_block(struct wcd9xxx_resmgr *resmgr,
554 enum wcd9xxx_clock_type type)
555{
556 pr_debug("%s: current %d, put %d\n", __func__, resmgr->clk_type, type);
557
Joonwoo Park533b3682013-06-13 11:41:21 -0700558 WCD9XXX_BG_CLK_ASSERT_LOCKED(resmgr);
Joonwoo Parka8890262012-10-15 12:04:27 -0700559 switch (type) {
560 case WCD9XXX_CLK_RCO:
561 if (--resmgr->clk_rco_users == 0 &&
562 resmgr->clk_type == WCD9XXX_CLK_RCO) {
563 wcd9xxx_disable_clock_block(resmgr);
Phani Kumar Uppalapati2feeade2013-09-17 16:32:30 -0700564 snd_soc_update_bits(resmgr->codec,
565 WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x00);
Joonwoo Parka8890262012-10-15 12:04:27 -0700566 resmgr->clk_type = WCD9XXX_CLK_OFF;
567 }
568 break;
569 case WCD9XXX_CLK_MCLK:
570 if (--resmgr->clk_mclk_users == 0 &&
571 resmgr->clk_rco_users == 0) {
572 wcd9xxx_disable_clock_block(resmgr);
573 resmgr->clk_type = WCD9XXX_CLK_OFF;
574 } else if (resmgr->clk_mclk_users == 0 &&
575 resmgr->clk_rco_users) {
576 /* disable clock */
577 wcd9xxx_disable_clock_block(resmgr);
578 /* switch to RCO */
579 wcd9xxx_enable_clock_block(resmgr, 1);
580 resmgr->clk_type = WCD9XXX_CLK_RCO;
581 }
582 break;
583 default:
584 pr_err("%s: Error, Invalid clock get request %d\n", __func__,
585 type);
586 break;
587 }
588 WARN_ON(resmgr->clk_rco_users < 0);
589 WARN_ON(resmgr->clk_mclk_users < 0);
590
591 pr_debug("%s: new rco_users %d, mclk_users %d\n", __func__,
592 resmgr->clk_rco_users, resmgr->clk_mclk_users);
593}
594
595static void wcd9xxx_resmgr_update_cfilt_usage(struct wcd9xxx_resmgr *resmgr,
596 enum wcd9xxx_cfilt_sel cfilt_sel,
597 bool inc)
598{
599 u16 micb_cfilt_reg;
600 enum wcd9xxx_notify_event e_pre_on, e_post_off;
601 struct snd_soc_codec *codec = resmgr->codec;
602
603 switch (cfilt_sel) {
604 case WCD9XXX_CFILT1_SEL:
605 micb_cfilt_reg = WCD9XXX_A_MICB_CFILT_1_CTL;
606 e_pre_on = WCD9XXX_EVENT_PRE_CFILT_1_ON;
607 e_post_off = WCD9XXX_EVENT_POST_CFILT_1_OFF;
608 break;
609 case WCD9XXX_CFILT2_SEL:
610 micb_cfilt_reg = WCD9XXX_A_MICB_CFILT_2_CTL;
611 e_pre_on = WCD9XXX_EVENT_PRE_CFILT_2_ON;
612 e_post_off = WCD9XXX_EVENT_POST_CFILT_2_OFF;
613 break;
614 case WCD9XXX_CFILT3_SEL:
615 micb_cfilt_reg = WCD9XXX_A_MICB_CFILT_3_CTL;
616 e_pre_on = WCD9XXX_EVENT_PRE_CFILT_3_ON;
617 e_post_off = WCD9XXX_EVENT_POST_CFILT_3_OFF;
618 break;
619 default:
620 WARN(1, "Invalid CFILT selection %d\n", cfilt_sel);
621 return; /* should not happen */
622 }
623
624 if (inc) {
625 if ((resmgr->cfilt_users[cfilt_sel]++) == 0) {
626 /* Notify */
627 wcd9xxx_resmgr_notifier_call(resmgr, e_pre_on);
628 /* Enable CFILT */
629 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
630 }
631 } else {
632 /*
633 * Check if count not zero, decrease
634 * then check if zero, go ahead disable cfilter
635 */
636 WARN(resmgr->cfilt_users[cfilt_sel] == 0,
637 "Invalid CFILT use count 0\n");
638 if ((--resmgr->cfilt_users[cfilt_sel]) == 0) {
639 /* Disable CFILT */
640 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
641 /* Notify MBHC so MBHC can switch CFILT to fast mode */
642 wcd9xxx_resmgr_notifier_call(resmgr, e_post_off);
643 }
644 }
645}
646
647void wcd9xxx_resmgr_cfilt_get(struct wcd9xxx_resmgr *resmgr,
648 enum wcd9xxx_cfilt_sel cfilt_sel)
649{
650 return wcd9xxx_resmgr_update_cfilt_usage(resmgr, cfilt_sel, true);
651}
652
653void wcd9xxx_resmgr_cfilt_put(struct wcd9xxx_resmgr *resmgr,
654 enum wcd9xxx_cfilt_sel cfilt_sel)
655{
656 return wcd9xxx_resmgr_update_cfilt_usage(resmgr, cfilt_sel, false);
657}
658
659int wcd9xxx_resmgr_get_k_val(struct wcd9xxx_resmgr *resmgr,
660 unsigned int cfilt_mv)
661{
662 int rc = -EINVAL;
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700663 unsigned int ldoh_v = resmgr->micbias_pdata->ldoh_v;
Joonwoo Parka8890262012-10-15 12:04:27 -0700664 unsigned min_mv, max_mv;
665
666 switch (ldoh_v) {
667 case WCD9XXX_LDOH_1P95_V:
668 min_mv = 160;
669 max_mv = 1800;
670 break;
671 case WCD9XXX_LDOH_2P35_V:
672 min_mv = 200;
673 max_mv = 2200;
674 break;
675 case WCD9XXX_LDOH_2P75_V:
676 min_mv = 240;
677 max_mv = 2600;
678 break;
679 case WCD9XXX_LDOH_3P0_V:
680 min_mv = 260;
681 max_mv = 2875;
682 break;
683 default:
684 goto done;
685 }
686
687 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
688 goto done;
689
690 for (rc = 4; rc <= 44; rc++) {
691 min_mv = max_mv * (rc) / 44;
692 if (min_mv >= cfilt_mv) {
693 rc -= 4;
694 break;
695 }
696 }
697done:
698 return rc;
699}
700
Joonwoo Park3b268ca2013-07-17 13:11:43 -0700701static void wcd9xxx_resmgr_cond_trigger_cond(struct wcd9xxx_resmgr *resmgr,
702 enum wcd9xxx_resmgr_cond cond)
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800703{
704 struct list_head *l;
705 struct wcd9xxx_resmgr_cond_entry *e;
706 bool set;
707
708 pr_debug("%s: enter\n", __func__);
Joonwoo Park3b268ca2013-07-17 13:11:43 -0700709 /* update bit if cond isn't available or cond is set */
710 set = !test_bit(cond, &resmgr->cond_avail_flags) ||
711 !!test_bit(cond, &resmgr->cond_flags);
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800712 list_for_each(l, &resmgr->update_bit_cond_h) {
713 e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
714 if (e->cond == cond)
715 snd_soc_update_bits(resmgr->codec, e->reg,
716 1 << e->shift,
717 (set ? !e->invert : e->invert)
718 << e->shift);
719 }
720 pr_debug("%s: leave\n", __func__);
721}
722
Joonwoo Park3b268ca2013-07-17 13:11:43 -0700723/*
724 * wcd9xxx_regmgr_cond_register : notify resmgr conditions in the condbits are
725 * avaliable and notified.
726 * condbits : contains bitmask of enum wcd9xxx_resmgr_cond
727 */
728void wcd9xxx_regmgr_cond_register(struct wcd9xxx_resmgr *resmgr,
729 unsigned long condbits)
730{
731 unsigned int cond;
732
733 for_each_set_bit(cond, &condbits, BITS_PER_BYTE * sizeof(condbits)) {
734 mutex_lock(&resmgr->update_bit_cond_lock);
735 WARN(test_bit(cond, &resmgr->cond_avail_flags),
736 "Condition 0x%0x is already registered\n", cond);
737 set_bit(cond, &resmgr->cond_avail_flags);
738 wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
739 mutex_unlock(&resmgr->update_bit_cond_lock);
740 pr_debug("%s: Condition 0x%x is registered\n", __func__, cond);
741 }
742}
743
744void wcd9xxx_regmgr_cond_deregister(struct wcd9xxx_resmgr *resmgr,
745 unsigned long condbits)
746{
747 unsigned int cond;
748
749 for_each_set_bit(cond, &condbits, BITS_PER_BYTE * sizeof(condbits)) {
750 mutex_lock(&resmgr->update_bit_cond_lock);
751 WARN(!test_bit(cond, &resmgr->cond_avail_flags),
752 "Condition 0x%0x isn't registered\n", cond);
753 clear_bit(cond, &resmgr->cond_avail_flags);
754 wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
755 mutex_unlock(&resmgr->update_bit_cond_lock);
756 pr_debug("%s: Condition 0x%x is deregistered\n", __func__,
757 cond);
758 }
759}
760
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800761void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
762 enum wcd9xxx_resmgr_cond cond, bool set)
763{
Joonwoo Parkccccba72013-04-26 11:19:46 -0700764 mutex_lock(&resmgr->update_bit_cond_lock);
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800765 if ((set && !test_and_set_bit(cond, &resmgr->cond_flags)) ||
766 (!set && test_and_clear_bit(cond, &resmgr->cond_flags))) {
767 pr_debug("%s: Resource %d condition changed to %s\n", __func__,
768 cond, set ? "set" : "clear");
769 wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
770 }
Joonwoo Parkccccba72013-04-26 11:19:46 -0700771 mutex_unlock(&resmgr->update_bit_cond_lock);
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800772}
773
774int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
775 enum wcd9xxx_resmgr_cond cond,
776 unsigned short reg, int shift,
777 bool invert)
778{
779 struct wcd9xxx_resmgr_cond_entry *entry;
780
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800781 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
782 if (!entry)
783 return -ENOMEM;
784
785 entry->cond = cond;
786 entry->reg = reg;
787 entry->shift = shift;
788 entry->invert = invert;
Joonwoo Park3edb9892013-03-05 17:44:54 -0800789
Joonwoo Parkccccba72013-04-26 11:19:46 -0700790 mutex_lock(&resmgr->update_bit_cond_lock);
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800791 list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
792
793 wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
Joonwoo Parkccccba72013-04-26 11:19:46 -0700794 mutex_unlock(&resmgr->update_bit_cond_lock);
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800795
796 return 0;
797}
798
799/*
800 * wcd9xxx_resmgr_rm_cond_update_bits :
801 * Clear bit and remove from the conditional bit update list
802 */
803int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
804 enum wcd9xxx_resmgr_cond cond,
805 unsigned short reg, int shift,
806 bool invert)
807{
808 struct list_head *l, *next;
809 struct wcd9xxx_resmgr_cond_entry *e = NULL;
810
811 pr_debug("%s: enter\n", __func__);
Joonwoo Parkccccba72013-04-26 11:19:46 -0700812 mutex_lock(&resmgr->update_bit_cond_lock);
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800813 list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
814 e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
815 if (e->reg == reg && e->shift == shift && e->invert == invert) {
816 snd_soc_update_bits(resmgr->codec, e->reg,
817 1 << e->shift,
818 e->invert << e->shift);
819 list_del(&e->list);
Joonwoo Parkccccba72013-04-26 11:19:46 -0700820 mutex_unlock(&resmgr->update_bit_cond_lock);
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800821 kfree(e);
822 return 0;
823 }
824 }
Joonwoo Parkccccba72013-04-26 11:19:46 -0700825 mutex_unlock(&resmgr->update_bit_cond_lock);
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800826 pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
827 __func__, e ? e->reg : 0, e ? e->shift : 0);
828
829 return -EINVAL;
830}
831
Joonwoo Parka8890262012-10-15 12:04:27 -0700832int wcd9xxx_resmgr_register_notifier(struct wcd9xxx_resmgr *resmgr,
833 struct notifier_block *nblock)
834{
835 return blocking_notifier_chain_register(&resmgr->notifier, nblock);
836}
837
838int wcd9xxx_resmgr_unregister_notifier(struct wcd9xxx_resmgr *resmgr,
839 struct notifier_block *nblock)
840{
841 return blocking_notifier_chain_unregister(&resmgr->notifier, nblock);
842}
843
844int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
845 struct snd_soc_codec *codec,
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -0700846 struct wcd9xxx_core_resource *core_res,
Joonwoo Parka8890262012-10-15 12:04:27 -0700847 struct wcd9xxx_pdata *pdata,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700848 struct wcd9xxx_micbias_setting *micbias_pdata,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700849 struct wcd9xxx_reg_address *reg_addr,
850 enum wcd9xxx_cdc_type cdc_type)
Joonwoo Parka8890262012-10-15 12:04:27 -0700851{
852 WARN(ARRAY_SIZE(wcd9xxx_event_string) != WCD9XXX_EVENT_LAST + 1,
853 "Event string table isn't up to date!, %d != %d\n",
854 ARRAY_SIZE(wcd9xxx_event_string), WCD9XXX_EVENT_LAST + 1);
855
856 resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
857 resmgr->codec = codec;
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700858 resmgr->codec_type = cdc_type;
Joonwoo Parka8890262012-10-15 12:04:27 -0700859 /* This gives access of core handle to lock/unlock suspend */
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -0700860 resmgr->core_res = core_res;
Joonwoo Parka8890262012-10-15 12:04:27 -0700861 resmgr->pdata = pdata;
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700862 resmgr->micbias_pdata = micbias_pdata;
Joonwoo Parka8890262012-10-15 12:04:27 -0700863 resmgr->reg_addr = reg_addr;
864
Joonwoo Parkcc52d472013-01-28 10:10:12 -0800865 INIT_LIST_HEAD(&resmgr->update_bit_cond_h);
866
Joonwoo Parka8890262012-10-15 12:04:27 -0700867 BLOCKING_INIT_NOTIFIER_HEAD(&resmgr->notifier);
868
869 mutex_init(&resmgr->codec_resource_lock);
Joonwoo Park533b3682013-06-13 11:41:21 -0700870 mutex_init(&resmgr->codec_bg_clk_lock);
Joonwoo Parkccccba72013-04-26 11:19:46 -0700871 mutex_init(&resmgr->update_bit_cond_lock);
Joonwoo Parka8890262012-10-15 12:04:27 -0700872
873 return 0;
874}
875
876void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr)
877{
Joonwoo Parkccccba72013-04-26 11:19:46 -0700878 mutex_destroy(&resmgr->update_bit_cond_lock);
Joonwoo Park533b3682013-06-13 11:41:21 -0700879 mutex_destroy(&resmgr->codec_bg_clk_lock);
Joonwoo Parka8890262012-10-15 12:04:27 -0700880 mutex_destroy(&resmgr->codec_resource_lock);
881}
882
883void wcd9xxx_resmgr_bcl_lock(struct wcd9xxx_resmgr *resmgr)
884{
885 mutex_lock(&resmgr->codec_resource_lock);
886}
887
888void wcd9xxx_resmgr_bcl_unlock(struct wcd9xxx_resmgr *resmgr)
889{
890 mutex_unlock(&resmgr->codec_resource_lock);
891}
892
893MODULE_DESCRIPTION("wcd9xxx resmgr module");
894MODULE_LICENSE("GPL v2");