1 /** 2 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. 3 * 4 * This source file is released under GPL v2 license (no other versions). 5 * See the COPYING file included in the main directory of this source 6 * distribution for the license terms and conditions. 7 * 8 * @File ctamixer.c 9 * 10 * @Brief 11 * This file contains the implementation of the Audio Mixer 12 * resource management object. 13 * 14 * @Author Liu Chun 15 * @Date May 21 2008 16 * 17 */ 18 19 #include "ctamixer.h" 20 #include "cthardware.h" 21 #include <linux/slab.h> 22 23 #define AMIXER_RESOURCE_NUM 256 24 #define SUM_RESOURCE_NUM 256 25 26 #define AMIXER_Y_IMMEDIATE 1 27 28 #define BLANK_SLOT 4094 29 30 static int amixer_master(struct rsc *rsc) 31 { 32 rsc->conj = 0; 33 return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0]; 34 } 35 36 static int amixer_next_conj(struct rsc *rsc) 37 { 38 rsc->conj++; 39 return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; 40 } 41 42 static int amixer_index(const struct rsc *rsc) 43 { 44 return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; 45 } 46 47 static int amixer_output_slot(const struct rsc *rsc) 48 { 49 return (amixer_index(rsc) << 4) + 0x4; 50 } 51 52 static struct rsc_ops amixer_basic_rsc_ops = { 53 .master = amixer_master, 54 .next_conj = amixer_next_conj, 55 .index = amixer_index, 56 .output_slot = amixer_output_slot, 57 }; 58 59 static int amixer_set_input(struct amixer *amixer, struct rsc *rsc) 60 { 61 struct hw *hw = NULL; 62 63 hw = (struct hw *)amixer->rsc.hw; 64 hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE); 65 amixer->input = rsc; 66 if (NULL == rsc) 67 hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT); 68 else 69 hw->amixer_set_x(amixer->rsc.ctrl_blk, 70 rsc->ops->output_slot(rsc)); 71 72 return 0; 73 } 74 75 /* y is a 14-bit immediate constant */ 76 static int amixer_set_y(struct amixer *amixer, unsigned int y) 77 { 78 struct hw *hw = NULL; 79 80 hw = (struct hw *)amixer->rsc.hw; 81 hw->amixer_set_y(amixer->rsc.ctrl_blk, y); 82 83 return 0; 84 } 85 86 static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv) 87 { 88 struct hw *hw = NULL; 89 90 hw = (struct hw *)amixer->rsc.hw; 91 hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv); 92 93 return 0; 94 } 95 96 static int amixer_set_sum(struct amixer *amixer, struct sum *sum) 97 { 98 struct hw *hw = NULL; 99 100 hw = (struct hw *)amixer->rsc.hw; 101 amixer->sum = sum; 102 if (NULL == sum) { 103 hw->amixer_set_se(amixer->rsc.ctrl_blk, 0); 104 } else { 105 hw->amixer_set_se(amixer->rsc.ctrl_blk, 1); 106 hw->amixer_set_sadr(amixer->rsc.ctrl_blk, 107 sum->rsc.ops->index(&sum->rsc)); 108 } 109 110 return 0; 111 } 112 113 static int amixer_commit_write(struct amixer *amixer) 114 { 115 struct hw *hw = NULL; 116 unsigned int index = 0; 117 int i = 0; 118 struct rsc *input = NULL; 119 struct sum *sum = NULL; 120 121 hw = (struct hw *)amixer->rsc.hw; 122 input = amixer->input; 123 sum = amixer->sum; 124 125 /* Program master and conjugate resources */ 126 amixer->rsc.ops->master(&amixer->rsc); 127 if (NULL != input) 128 input->ops->master(input); 129 130 if (NULL != sum) 131 sum->rsc.ops->master(&sum->rsc); 132 133 for (i = 0; i < amixer->rsc.msr; i++) { 134 hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk); 135 if (NULL != input) { 136 hw->amixer_set_x(amixer->rsc.ctrl_blk, 137 input->ops->output_slot(input)); 138 input->ops->next_conj(input); 139 } 140 if (NULL != sum) { 141 hw->amixer_set_sadr(amixer->rsc.ctrl_blk, 142 sum->rsc.ops->index(&sum->rsc)); 143 sum->rsc.ops->next_conj(&sum->rsc); 144 } 145 index = amixer->rsc.ops->output_slot(&amixer->rsc); 146 hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); 147 amixer->rsc.ops->next_conj(&amixer->rsc); 148 } 149 amixer->rsc.ops->master(&amixer->rsc); 150 if (NULL != input) 151 input->ops->master(input); 152 153 if (NULL != sum) 154 sum->rsc.ops->master(&sum->rsc); 155 156 return 0; 157 } 158 159 static int amixer_commit_raw_write(struct amixer *amixer) 160 { 161 struct hw *hw = NULL; 162 unsigned int index = 0; 163 164 hw = (struct hw *)amixer->rsc.hw; 165 index = amixer->rsc.ops->output_slot(&amixer->rsc); 166 hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); 167 168 return 0; 169 } 170 171 static int amixer_get_y(struct amixer *amixer) 172 { 173 struct hw *hw = NULL; 174 175 hw = (struct hw *)amixer->rsc.hw; 176 return hw->amixer_get_y(amixer->rsc.ctrl_blk); 177 } 178 179 static int amixer_setup(struct amixer *amixer, struct rsc *input, 180 unsigned int scale, struct sum *sum) 181 { 182 amixer_set_input(amixer, input); 183 amixer_set_y(amixer, scale); 184 amixer_set_sum(amixer, sum); 185 amixer_commit_write(amixer); 186 return 0; 187 } 188 189 static struct amixer_rsc_ops amixer_ops = { 190 .set_input = amixer_set_input, 191 .set_invalid_squash = amixer_set_invalid_squash, 192 .set_scale = amixer_set_y, 193 .set_sum = amixer_set_sum, 194 .commit_write = amixer_commit_write, 195 .commit_raw_write = amixer_commit_raw_write, 196 .setup = amixer_setup, 197 .get_scale = amixer_get_y, 198 }; 199 200 static int amixer_rsc_init(struct amixer *amixer, 201 const struct amixer_desc *desc, 202 struct amixer_mgr *mgr) 203 { 204 int err = 0; 205 206 err = rsc_init(&amixer->rsc, amixer->idx[0], 207 AMIXER, desc->msr, mgr->mgr.hw); 208 if (err) 209 return err; 210 211 /* Set amixer specific operations */ 212 amixer->rsc.ops = &amixer_basic_rsc_ops; 213 amixer->ops = &amixer_ops; 214 amixer->input = NULL; 215 amixer->sum = NULL; 216 217 amixer_setup(amixer, NULL, 0, NULL); 218 219 return 0; 220 } 221 222 static int amixer_rsc_uninit(struct amixer *amixer) 223 { 224 amixer_setup(amixer, NULL, 0, NULL); 225 rsc_uninit(&amixer->rsc); 226 amixer->ops = NULL; 227 amixer->input = NULL; 228 amixer->sum = NULL; 229 return 0; 230 } 231 232 static int get_amixer_rsc(struct amixer_mgr *mgr, 233 const struct amixer_desc *desc, 234 struct amixer **ramixer) 235 { 236 int err = 0, i = 0; 237 unsigned int idx = 0; 238 struct amixer *amixer = NULL; 239 unsigned long flags; 240 241 *ramixer = NULL; 242 243 /* Allocate mem for amixer resource */ 244 amixer = kzalloc(sizeof(*amixer), GFP_KERNEL); 245 if (NULL == amixer) { 246 err = -ENOMEM; 247 return err; 248 } 249 250 /* Check whether there are sufficient 251 * amixer resources to meet request. */ 252 spin_lock_irqsave(&mgr->mgr_lock, flags); 253 for (i = 0; i < desc->msr; i++) { 254 err = mgr_get_resource(&mgr->mgr, 1, &idx); 255 if (err) 256 break; 257 258 amixer->idx[i] = idx; 259 } 260 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 261 if (err) { 262 printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n"); 263 goto error; 264 } 265 266 err = amixer_rsc_init(amixer, desc, mgr); 267 if (err) 268 goto error; 269 270 *ramixer = amixer; 271 272 return 0; 273 274 error: 275 spin_lock_irqsave(&mgr->mgr_lock, flags); 276 for (i--; i >= 0; i--) 277 mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); 278 279 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 280 kfree(amixer); 281 return err; 282 } 283 284 static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) 285 { 286 unsigned long flags; 287 int i = 0; 288 289 spin_lock_irqsave(&mgr->mgr_lock, flags); 290 for (i = 0; i < amixer->rsc.msr; i++) 291 mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); 292 293 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 294 amixer_rsc_uninit(amixer); 295 kfree(amixer); 296 297 return 0; 298 } 299 300 int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr) 301 { 302 int err = 0; 303 struct amixer_mgr *amixer_mgr; 304 305 *ramixer_mgr = NULL; 306 amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); 307 if (NULL == amixer_mgr) 308 return -ENOMEM; 309 310 err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw); 311 if (err) 312 goto error; 313 314 spin_lock_init(&amixer_mgr->mgr_lock); 315 316 amixer_mgr->get_amixer = get_amixer_rsc; 317 amixer_mgr->put_amixer = put_amixer_rsc; 318 319 *ramixer_mgr = amixer_mgr; 320 321 return 0; 322 323 error: 324 kfree(amixer_mgr); 325 return err; 326 } 327 328 int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) 329 { 330 rsc_mgr_uninit(&amixer_mgr->mgr); 331 kfree(amixer_mgr); 332 return 0; 333 } 334 335 /* SUM resource management */ 336 337 static int sum_master(struct rsc *rsc) 338 { 339 rsc->conj = 0; 340 return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; 341 } 342 343 static int sum_next_conj(struct rsc *rsc) 344 { 345 rsc->conj++; 346 return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 347 } 348 349 static int sum_index(const struct rsc *rsc) 350 { 351 return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 352 } 353 354 static int sum_output_slot(const struct rsc *rsc) 355 { 356 return (sum_index(rsc) << 4) + 0xc; 357 } 358 359 static struct rsc_ops sum_basic_rsc_ops = { 360 .master = sum_master, 361 .next_conj = sum_next_conj, 362 .index = sum_index, 363 .output_slot = sum_output_slot, 364 }; 365 366 static int sum_rsc_init(struct sum *sum, 367 const struct sum_desc *desc, 368 struct sum_mgr *mgr) 369 { 370 int err = 0; 371 372 err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); 373 if (err) 374 return err; 375 376 sum->rsc.ops = &sum_basic_rsc_ops; 377 378 return 0; 379 } 380 381 static int sum_rsc_uninit(struct sum *sum) 382 { 383 rsc_uninit(&sum->rsc); 384 return 0; 385 } 386 387 static int get_sum_rsc(struct sum_mgr *mgr, 388 const struct sum_desc *desc, 389 struct sum **rsum) 390 { 391 int err = 0, i = 0; 392 unsigned int idx = 0; 393 struct sum *sum = NULL; 394 unsigned long flags; 395 396 *rsum = NULL; 397 398 /* Allocate mem for sum resource */ 399 sum = kzalloc(sizeof(*sum), GFP_KERNEL); 400 if (NULL == sum) { 401 err = -ENOMEM; 402 return err; 403 } 404 405 /* Check whether there are sufficient sum resources to meet request. */ 406 spin_lock_irqsave(&mgr->mgr_lock, flags); 407 for (i = 0; i < desc->msr; i++) { 408 err = mgr_get_resource(&mgr->mgr, 1, &idx); 409 if (err) 410 break; 411 412 sum->idx[i] = idx; 413 } 414 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 415 if (err) { 416 printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n"); 417 goto error; 418 } 419 420 err = sum_rsc_init(sum, desc, mgr); 421 if (err) 422 goto error; 423 424 *rsum = sum; 425 426 return 0; 427 428 error: 429 spin_lock_irqsave(&mgr->mgr_lock, flags); 430 for (i--; i >= 0; i--) 431 mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 432 433 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 434 kfree(sum); 435 return err; 436 } 437 438 static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) 439 { 440 unsigned long flags; 441 int i = 0; 442 443 spin_lock_irqsave(&mgr->mgr_lock, flags); 444 for (i = 0; i < sum->rsc.msr; i++) 445 mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 446 447 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 448 sum_rsc_uninit(sum); 449 kfree(sum); 450 451 return 0; 452 } 453 454 int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr) 455 { 456 int err = 0; 457 struct sum_mgr *sum_mgr; 458 459 *rsum_mgr = NULL; 460 sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); 461 if (NULL == sum_mgr) 462 return -ENOMEM; 463 464 err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); 465 if (err) 466 goto error; 467 468 spin_lock_init(&sum_mgr->mgr_lock); 469 470 sum_mgr->get_sum = get_sum_rsc; 471 sum_mgr->put_sum = put_sum_rsc; 472 473 *rsum_mgr = sum_mgr; 474 475 return 0; 476 477 error: 478 kfree(sum_mgr); 479 return err; 480 } 481 482 int sum_mgr_destroy(struct sum_mgr *sum_mgr) 483 { 484 rsc_mgr_uninit(&sum_mgr->mgr); 485 kfree(sum_mgr); 486 return 0; 487 } 488 489