blob: 5ffda8ad700d3c1f456972b61418ea3c781c44c1 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -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 */
13#include <linux/module.h>
14#include <linux/mutex.h>
15#include <linux/platform_device.h>
16#include <linux/io.h>
17#include <linux/err.h>
18#include <linux/delay.h>
19#include <linux/clk.h>
20#include <mach/qdsp5v2/lpa.h>
21#include <mach/qdsp5v2/lpa_hw.h>
22#include <mach/qdsp5v2/msm_lpa.h>
23#include <mach/debug_mm.h>
24
25#define LPA_REG_WRITEL(drv, val, reg) writel(val, drv->baseaddr + reg)
26#define LPA_REG_READL(drv, reg) readl(drv->baseaddr + reg)
27
28/* bit 2:0 is reserved because watermarks have to be 64-bit aligned */
29#define LLB_WATERMARK_VAL_MASK 0x00000003
30
31#define LPA_STATUS_SBUF_EN 0x01
32
33struct lpa_drv {
34 void __iomem *baseaddr;
35 u32 obuf_hlb_size;
36 u32 dsp_proc_id;
37 u32 app_proc_id;
38 struct lpa_mem_config nosb_config;
39 struct lpa_mem_config sb_config;
40 u32 status;
41 u32 watermark_bytes;
42 u32 watermark_aheadtime;
43 u32 sample_boundary;
44};
45
46struct lpa_state {
47 struct lpa_drv lpa_drv; /* One instance for now */
48 u32 assigned;
49 struct mutex lpa_lock;
50};
51
52struct lpa_state the_lpa_state;
53
54static void lpa_enable_codec(struct lpa_drv *lpa, bool enable)
55{
56 u32 val;
57
58 val = LPA_REG_READL(lpa, LPA_OBUF_CODEC);
59 val = enable ? (val | LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK) :
60 (val & ~LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK);
61 val |= LPA_OBUF_CODEC_LOAD_BMSK;
62 LPA_REG_WRITEL(lpa, val, LPA_OBUF_CODEC);
63 mb();
64}
65
66static void lpa_reset(struct lpa_drv *lpa)
67{
68 u32 status;
69 struct clk *adsp_clk;
70 /* Need to make sure not disable clock while other device is enabled */
71 adsp_clk = clk_get(NULL, "adsp_clk");
72 if (!adsp_clk) {
73 MM_ERR("failed to get adsp clk\n");
74 goto error;
75 }
Vinay Vakac82b9b82012-07-02 15:33:38 +053076 clk_prepare_enable(adsp_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070077 lpa_enable_codec(lpa, 0);
78 LPA_REG_WRITEL(lpa, (LPA_OBUF_RESETS_MISR_RESET |
79 LPA_OBUF_RESETS_OVERALL_RESET), LPA_OBUF_RESETS);
80 do {
81 status = LPA_REG_READL(lpa, LPA_OBUF_STATUS);
82 } while (!(status & LPA_OBUF_STATUS_RESET_DONE));
83
84 LPA_REG_WRITEL(lpa, LPA_OBUF_ACK_RESET_DONE_BMSK, LPA_OBUF_ACK);
85 mb();
Vinay Vakac82b9b82012-07-02 15:33:38 +053086 clk_disable_unprepare(adsp_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087 clk_put(adsp_clk);
88error:
89 return;
90}
91
92static void lpa_config_hlb_addr(struct lpa_drv *lpa)
93{
94 u32 val, min_addr = 0, max_addr = min_addr + lpa->obuf_hlb_size;
95
96 val = (min_addr & LPA_OBUF_HLB_MIN_ADDR_SEG_BMSK) |
97 LPA_OBUF_HLB_MIN_ADDR_LOAD_BMSK;
98 LPA_REG_WRITEL(lpa, val, LPA_OBUF_HLB_MIN_ADDR);
99 val = max_addr & LPA_OBUF_HLB_MAX_ADDR_SEG_BMSK;
100 LPA_REG_WRITEL(lpa, val, LPA_OBUF_HLB_MAX_ADDR);
101}
102
103static void lpa_powerup_mem_bank(struct lpa_drv *lpa,
104 struct lpa_mem_bank_select *bank)
105{
106 u32 status, val;
107
108 status = LPA_REG_READL(lpa, LPA_OBUF_MEMORY_CONTROL);
109 val = ((*((u32 *) bank)) << LPA_OBUF_MEM_CTL_PWRUP_SHFT) &
110 LPA_OBUF_MEM_CTL_PWRUP_BMSK;
111 val |= status;
112 LPA_REG_WRITEL(lpa, val, LPA_OBUF_MEMORY_CONTROL);
113}
114
115static void lpa_enable_interrupt(struct lpa_drv *lpa, u32 proc_id)
116{
117 u32 val;
118
119 proc_id &= LPA_OBUF_INTR_EN_BMSK;
120 val = 0x1 << proc_id;
121 LPA_REG_WRITEL(lpa, val, LPA_OBUF_INTR_ENABLE);
122}
123
124static void lpa_config_llb_addr(struct lpa_drv *lpa, u32 min_addr, u32 max_addr)
125{
126 u32 val;
127
128 val = (min_addr & LPA_OBUF_LLB_MIN_ADDR_SEG_BMSK) |
129 LPA_OBUF_LLB_MIN_ADDR_LOAD_BMSK;
130 LPA_REG_WRITEL(lpa, val, LPA_OBUF_LLB_MIN_ADDR);
131 val = max_addr & LPA_OBUF_LLB_MAX_ADDR_SEG_BMSK;
132 LPA_REG_WRITEL(lpa, val, LPA_OBUF_LLB_MAX_ADDR);
133}
134
135static void lpa_config_sb_addr(struct lpa_drv *lpa, u32 min_addr, u32 max_addr)
136{
137 u32 val;
138
139 val = (min_addr & LPA_OBUF_SB_MIN_ADDR_SEG_BMSK) |
140 LPA_OBUF_SB_MIN_ADDR_LOAD_BMSK;
141 LPA_REG_WRITEL(lpa, val, LPA_OBUF_SB_MIN_ADDR);
142 val = max_addr & LPA_OBUF_SB_MAX_ADDR_SEG_BMSK;
143 LPA_REG_WRITEL(lpa, val, LPA_OBUF_SB_MAX_ADDR);
144}
145
146static void lpa_switch_sb(struct lpa_drv *lpa)
147{
148 if (lpa->status & LPA_STATUS_SBUF_EN) {
149 lpa_config_llb_addr(lpa, lpa->sb_config.llb_min_addr,
150 lpa->sb_config.llb_max_addr);
151 lpa_config_sb_addr(lpa, lpa->sb_config.sb_min_addr,
152 lpa->sb_config.sb_max_addr);
153 } else {
154 lpa_config_llb_addr(lpa, lpa->nosb_config.llb_min_addr,
155 lpa->nosb_config.llb_max_addr);
156 lpa_config_sb_addr(lpa, lpa->nosb_config.sb_min_addr,
157 lpa->nosb_config.sb_max_addr);
158 }
159}
160
161static u8 lpa_req_wmark_id(struct lpa_drv *lpa)
162{
163 return (u8) (LPA_REG_READL(lpa, LPA_OBUF_WMARK_ASSIGN) &
164 LPA_OBUF_WMARK_ASSIGN_BMSK);
165}
166
167static void lpa_enable_llb_wmark(struct lpa_drv *lpa, u32 wmark_ctrl,
168 u32 wmark_id, u32 cpu_id)
169{
170 u32 val;
171
172 wmark_id = (wmark_id > 3) ? 0 : wmark_id;
173 val = LPA_REG_READL(lpa, LPA_OBUF_WMARK_n_LLB_ADDR(wmark_id));
174 val &= ~LPA_OBUF_LLB_WMARK_CTRL_BMSK;
175 val &= ~LPA_OBUF_LLB_WMARK_MAP_BMSK;
176 val |= (wmark_ctrl << LPA_OBUF_LLB_WMARK_CTRL_SHFT) &
177 LPA_OBUF_LLB_WMARK_CTRL_BMSK;
178 val |= (cpu_id << LPA_OBUF_LLB_WMARK_MAP_SHFT) &
179 LPA_OBUF_LLB_WMARK_MAP_BMSK;
180 LPA_REG_WRITEL(lpa, val, LPA_OBUF_WMARK_n_LLB_ADDR(wmark_id));
181}
182
183static void lpa_enable_sb_wmark(struct lpa_drv *lpa, u32 wmark_ctrl,
184 u32 cpu_id)
185{
186 u32 val;
187
188 val = LPA_REG_READL(lpa, LPA_OBUF_WMARK_SB);
189 val &= ~LPA_OBUF_SB_WMARK_CTRL_BMSK;
190 val &= ~LPA_OBUF_SB_WMARK_MAP_BMSK;
191 val |= (wmark_ctrl << LPA_OBUF_SB_WMARK_CTRL_SHFT) &
192 LPA_OBUF_SB_WMARK_CTRL_BMSK;
193 val |= (cpu_id << LPA_OBUF_SB_WMARK_MAP_SHFT) &
194 LPA_OBUF_SB_WMARK_MAP_BMSK;
195 LPA_REG_WRITEL(lpa, val, LPA_OBUF_WMARK_SB);
196}
197static void lpa_enable_hlb_wmark(struct lpa_drv *lpa, u32 wmark_ctrl,
198 u32 cpu_id)
199{
200 u32 val;
201
202 val = LPA_REG_READL(lpa, LPA_OBUF_WMARK_HLB);
203 val &= ~LPA_OBUF_HLB_WMARK_CTRL_BMSK;
204 val &= ~LPA_OBUF_HLB_WMARK_MAP_BMSK;
205 val |= (wmark_ctrl << LPA_OBUF_HLB_WMARK_CTRL_SHFT) &
206 LPA_OBUF_HLB_WMARK_CTRL_BMSK;
207 val |= (cpu_id << LPA_OBUF_HLB_WMARK_MAP_SHFT) &
208 LPA_OBUF_HLB_WMARK_MAP_BMSK;
209 LPA_REG_WRITEL(lpa, val, LPA_OBUF_WMARK_HLB);
210}
211
212static void lpa_enable_utc(struct lpa_drv *lpa, bool enable, u32 cpu_id)
213{
214 u32 val;
215
216 val = (cpu_id << LPA_OBUF_UTC_CONFIG_MAP_SHFT) &
217 LPA_OBUF_UTC_CONFIG_MAP_BMSK;
218 enable = (enable ? 1 : 0);
219 val = (enable << LPA_OBUF_UTC_CONFIG_EN_SHFT) &
220 LPA_OBUF_UTC_CONFIG_EN_BMSK;
221 LPA_REG_WRITEL(lpa, val, LPA_OBUF_UTC_CONFIG);
222}
223
224static void lpa_enable_mixing(struct lpa_drv *lpa, bool enable)
225{
226 u32 val;
227
228 val = LPA_REG_READL(lpa, LPA_OBUF_CONTROL);
229 val = (enable ? val | LPA_OBUF_CONTROL_LLB_EN_BMSK :
230 val & ~LPA_OBUF_CONTROL_LLB_EN_BMSK);
231 LPA_REG_WRITEL(lpa, val, LPA_OBUF_CONTROL);
232}
233
234static void lpa_enable_mixer_saturation(struct lpa_drv *lpa, u32 buf_id,
235 bool enable)
236{
237 u32 val;
238
239 val = LPA_REG_READL(lpa, LPA_OBUF_CONTROL);
240
241 switch (buf_id) {
242 case LPA_BUF_ID_LLB:
243 val = enable ? (val | LPA_OBUF_CONTROL_LLB_SAT_EN_BMSK) :
244 (val & ~LPA_OBUF_CONTROL_LLB_SAT_EN_BMSK);
245 break;
246
247 case LPA_BUF_ID_SB:
248 val = enable ? (val | LPA_OBUF_CONTROL_SB_SAT_EN_BMSK) :
249 (val & ~LPA_OBUF_CONTROL_SB_SAT_EN_BMSK);
250 break;
251 }
252
253 LPA_REG_WRITEL(lpa, val, LPA_OBUF_CONTROL);
254}
255
256static void lpa_enable_obuf(struct lpa_drv *lpa, u32 buf_id, bool enable)
257{
258 u32 val;
259
260 val = LPA_REG_READL(lpa, LPA_OBUF_CONTROL);
261
262 switch (buf_id) {
263 case LPA_BUF_ID_HLB:
264 val = enable ? (val | LPA_OBUF_CONTROL_HLB_EN_BMSK) :
265 (val & ~LPA_OBUF_CONTROL_HLB_EN_BMSK);
266 break;
267
268 case LPA_BUF_ID_LLB:
269 val = enable ? (val | LPA_OBUF_CONTROL_LLB_EN_BMSK) :
270 (val & ~LPA_OBUF_CONTROL_LLB_EN_BMSK);
271 break;
272
273 case LPA_BUF_ID_SB:
274 val = enable ? (val | LPA_OBUF_CONTROL_SB_EN_BMSK) :
275 (val & ~LPA_OBUF_CONTROL_SB_EN_BMSK);
276 break;
277 }
278 LPA_REG_WRITEL(lpa, val, LPA_OBUF_CONTROL);
279}
280
281struct lpa_drv *lpa_get(void)
282{
283 struct lpa_mem_bank_select mem_bank;
284 struct lpa_drv *ret_lpa = &the_lpa_state.lpa_drv;
285
286 mutex_lock(&the_lpa_state.lpa_lock);
287 if (the_lpa_state.assigned) {
288 MM_ERR("LPA HW accupied\n");
289 ret_lpa = ERR_PTR(-EBUSY);
290 goto error;
291 }
292 /* perform initialization */
293 lpa_reset(ret_lpa);
294 /* Config adec param */
295 /* Initialize LLB/SB min/max address */
296 lpa_switch_sb(ret_lpa);
297 /* Config HLB minx/max address */
298 lpa_config_hlb_addr(ret_lpa);
299
300 /* Power up all memory bank for now */
301 mem_bank.b0 = 1;
302 mem_bank.b1 = 1;
303 mem_bank.b2 = 1;
304 mem_bank.b3 = 1;
305 mem_bank.b4 = 1;
306 mem_bank.b5 = 1;
307 mem_bank.b6 = 1;
308 mem_bank.b7 = 1;
309 mem_bank.b8 = 1;
310 mem_bank.b9 = 1;
311 mem_bank.b10 = 1;
312 mem_bank.llb = 1;
313 lpa_powerup_mem_bank(ret_lpa, &mem_bank);
314
315 while
316 (lpa_req_wmark_id(ret_lpa) != LPA_OBUF_WMARK_ASSIGN_DONE);
317
318 lpa_enable_llb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED, 0,
319 ret_lpa->dsp_proc_id);
320 lpa_enable_llb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED, 1,
321 ret_lpa->dsp_proc_id);
322 lpa_enable_llb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED, 2,
323 ret_lpa->app_proc_id);
324 lpa_enable_llb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED, 3,
325 ret_lpa->app_proc_id);
326 lpa_enable_hlb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED,
327 ret_lpa->dsp_proc_id);
328 lpa_enable_sb_wmark(ret_lpa, LPA_WMARK_CTL_DISABLED,
329 ret_lpa->dsp_proc_id);
330 lpa_enable_utc(ret_lpa, 0, LPA_OBUF_UTC_CONFIG_NO_INTR);
331
332 lpa_enable_mixing(ret_lpa, 1);
333 lpa_enable_mixer_saturation(ret_lpa, LPA_BUF_ID_LLB, 1);
334
335 lpa_enable_obuf(ret_lpa, LPA_BUF_ID_HLB, 0);
336 lpa_enable_obuf(ret_lpa, LPA_BUF_ID_LLB, 1);
337 if (ret_lpa->status & LPA_STATUS_SBUF_EN) {
338 lpa_enable_mixer_saturation(ret_lpa, LPA_BUF_ID_SB, 1);
339 lpa_enable_obuf(ret_lpa, LPA_BUF_ID_SB, 1);
340 }
341
342 lpa_enable_interrupt(ret_lpa, ret_lpa->dsp_proc_id);
343 mb();
344 the_lpa_state.assigned++;
345error:
346 mutex_unlock(&the_lpa_state.lpa_lock);
347 return ret_lpa;
348}
349EXPORT_SYMBOL(lpa_get);
350
351void lpa_put(struct lpa_drv *lpa)
352{
353
354 mutex_lock(&the_lpa_state.lpa_lock);
355 if (!lpa || &the_lpa_state.lpa_drv != lpa) {
356 MM_ERR("invalid arg\n");
357 goto error;
358 }
359 /* Deinitialize */
360 the_lpa_state.assigned--;
361error:
362 mutex_unlock(&the_lpa_state.lpa_lock);
363}
364EXPORT_SYMBOL(lpa_put);
365
366int lpa_cmd_codec_config(struct lpa_drv *lpa,
367 struct lpa_codec_config *config_ptr)
368{
369 u32 sample_rate;
370 u32 num_channels;
371 u32 width;
372 u32 val = 0;
373
374 if (!lpa || !config_ptr) {
375 MM_ERR("invalid parameters\n");
376 return -EINVAL;
377 }
378
379 switch (config_ptr->num_channels) {
380 case 8:
381 num_channels = LPA_NUM_CHAN_7P1;
382 break;
383 case 6:
384 num_channels = LPA_NUM_CHAN_5P1;
385 break;
386 case 4:
387 num_channels = LPA_NUM_CHAN_4_CHANNEL;
388 break;
389 case 2:
390 num_channels = LPA_NUM_CHAN_STEREO;
391 break;
392 case 1:
393 num_channels = LPA_NUM_CHAN_MONO;
394 break;
395 default:
396 MM_ERR("unsupported number of channel\n");
397 goto error;
398 }
399 val |= (num_channels << LPA_OBUF_CODEC_NUM_CHAN_SHFT) &
400 LPA_OBUF_CODEC_NUM_CHAN_BMSK;
401
402 switch (config_ptr->sample_rate) {
403 case 96000:
404 sample_rate = LPA_SAMPLE_RATE_96KHZ;
405 break;
406 case 64000:
407 sample_rate = LPA_SAMPLE_RATE_64KHZ;
408 break;
409 case 48000:
410 sample_rate = LPA_SAMPLE_RATE_48KHZ;
411 break;
412 case 44100:
413 sample_rate = LPA_SAMPLE_RATE_44P1KHZ;
414 break;
415 case 32000:
416 sample_rate = LPA_SAMPLE_RATE_32KHZ;
417 break;
418 case 22050:
419 sample_rate = LPA_SAMPLE_RATE_22P05KHZ;
420 break;
421 case 16000:
422 sample_rate = LPA_SAMPLE_RATE_16KHZ;
423 break;
424 case 11025:
425 sample_rate = LPA_SAMPLE_RATE_11P025KHZ;
426 break;
427 case 8000:
428 sample_rate = LPA_SAMPLE_RATE_8KHZ;
429 break;
430 default:
431 MM_ERR("unsupported sample rate \n");
432 goto error;
433 }
434 val |= (sample_rate << LPA_OBUF_CODEC_SAMP_SHFT) &
435 LPA_OBUF_CODEC_SAMP_BMSK;
436 switch (config_ptr->sample_width) {
437 case 32:
438 width = LPA_BITS_PER_CHAN_32BITS;
439 break;
440 case 24:
441 width = LPA_BITS_PER_CHAN_24BITS;
442 break;
443 case 16:
444 width = LPA_BITS_PER_CHAN_16BITS;
445 break;
446 default:
447 MM_ERR("unsupported sample width \n");
448 goto error;
449 }
450 val |= (width << LPA_OBUF_CODEC_BITS_PER_CHAN_SHFT) &
451 LPA_OBUF_CODEC_BITS_PER_CHAN_BMSK;
452
453 val |= LPA_OBUF_CODEC_LOAD_BMSK;
454 val |= (config_ptr->output_interface << LPA_OBUF_CODEC_INTF_SHFT) &
455 LPA_OBUF_CODEC_INTF_BMSK;
456
457 LPA_REG_WRITEL(lpa, val, LPA_OBUF_CODEC);
458 mb();
459
460 return 0;
461error:
462 return -EINVAL;
463}
464EXPORT_SYMBOL(lpa_cmd_codec_config);
465
466static int lpa_check_llb_clear(struct lpa_drv *lpa)
467{
468 u32 val;
469 val = LPA_REG_READL(lpa, LPA_OBUF_STATUS);
470
471 return !(val & LPA_OBUF_STATUS_LLB_CLR_BMSK);
472}
473
474static void lpa_clear_llb(struct lpa_drv *lpa)
475{
476 u32 val;
477
478 val = LPA_REG_READL(lpa, LPA_OBUF_CONTROL);
479 LPA_REG_WRITEL(lpa, (val | LPA_OBUF_CONTROL_LLB_CLR_CMD_BMSK),
480 LPA_OBUF_CONTROL);
481 lpa_enable_obuf(lpa, LPA_BUF_ID_LLB, 0);
482
483 while (!lpa_check_llb_clear(lpa))
484 udelay(100);
485 LPA_REG_WRITEL(lpa, val, LPA_OBUF_CONTROL);
486}
487
488int lpa_cmd_enable_codec(struct lpa_drv *lpa, bool enable)
489{
490 u32 val;
491 struct lpa_mem_bank_select mem_bank;
492
493 MM_DBG(" %s\n", (enable ? "enable" : "disable"));
494
495 if (!lpa)
496 return -EINVAL;
497
498 val = LPA_REG_READL(lpa, LPA_OBUF_CODEC);
499
500 if (enable) {
501 if (val & LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK)
502 return -EBUSY;
503 /* Power up all memory bank for now */
504 mem_bank.b0 = 1;
505 mem_bank.b1 = 1;
506 mem_bank.b2 = 1;
507 mem_bank.b3 = 1;
508 mem_bank.b4 = 1;
509 mem_bank.b5 = 1;
510 mem_bank.b6 = 1;
511 mem_bank.b7 = 1;
512 mem_bank.b8 = 1;
513 mem_bank.b9 = 1;
514 mem_bank.b10 = 1;
515 mem_bank.llb = 1;
516 lpa_powerup_mem_bank(lpa, &mem_bank);
517
518 /*clear LLB*/
519 lpa_clear_llb(lpa);
520
521 lpa_enable_codec(lpa, 1);
522 MM_DBG("LPA codec is enabled\n");
523 } else {
524 if (val & LPA_OBUF_CODEC_CODEC_INTF_EN_BMSK) {
525 lpa_enable_codec(lpa, 0);
526 MM_DBG("LPA codec is disabled\n");
527 } else
528 MM_ERR("LPA codec is already disable\n");
529 }
530 mb();
531 return 0;
532}
533EXPORT_SYMBOL(lpa_cmd_enable_codec);
534
535static int lpa_probe(struct platform_device *pdev)
536{
537 int rc = 0;
538 struct resource *mem_src;
539 struct msm_lpa_platform_data *pdata;
540
541 MM_INFO("lpa probe\n");
542
543 if (!pdev || !pdev->dev.platform_data) {
544 MM_ERR("no plaform data\n");
545 rc = -ENODEV;
546 goto error;
547 }
548
549 mem_src = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpa");
550 if (!mem_src) {
551 MM_ERR("LPA base address undefined\n");
552 rc = -ENODEV;
553 goto error;
554 }
555
556 pdata = pdev->dev.platform_data;
557 the_lpa_state.lpa_drv.baseaddr = ioremap(mem_src->start,
558 (mem_src->end - mem_src->start) + 1);
559 if (!the_lpa_state.lpa_drv.baseaddr) {
560 rc = -ENOMEM;
561 goto error;
562 }
563
564 the_lpa_state.lpa_drv.obuf_hlb_size = pdata->obuf_hlb_size;
565 the_lpa_state.lpa_drv.dsp_proc_id = pdata->dsp_proc_id;
566 the_lpa_state.lpa_drv.app_proc_id = pdata->app_proc_id;
567 the_lpa_state.lpa_drv.nosb_config = pdata->nosb_config;
568 the_lpa_state.lpa_drv.sb_config = pdata->sb_config;
569 /* default to enable summing buffer */
570 the_lpa_state.lpa_drv.status = LPA_STATUS_SBUF_EN;
571
572error:
573 return rc;
574
575}
576
577static int lpa_remove(struct platform_device *pdev)
578{
579 iounmap(the_lpa_state.lpa_drv.baseaddr);
580 return 0;
581}
582
583static struct platform_driver lpa_driver = {
584 .probe = lpa_probe,
585 .remove = lpa_remove,
586 .driver = {
587 .name = "lpa",
588 .owner = THIS_MODULE,
589 },
590};
591
592static int __init lpa_init(void)
593{
594 the_lpa_state.assigned = 0;
595 mutex_init(&the_lpa_state.lpa_lock);
596 return platform_driver_register(&lpa_driver);
597}
598
599static void __exit lpa_exit(void)
600{
601 platform_driver_unregister(&lpa_driver);
602}
603
604module_init(lpa_init);
605module_exit(lpa_exit);
606
607MODULE_DESCRIPTION("MSM LPA driver");
608MODULE_LICENSE("GPL v2");