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; 62 63 hw = amixer->rsc.hw; 64 hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE); 65 amixer->input = rsc; 66 if (!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; 79 80 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; 89 90 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; 99 100 hw = amixer->rsc.hw; 101 amixer->sum = sum; 102 if (!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; 116 unsigned int index; 117 int i; 118 struct rsc *input; 119 struct sum *sum; 120 121 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 (input) 128 input->ops->master(input); 129 130 if (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 (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 (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 (input) 151 input->ops->master(input); 152 153 if (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; 162 unsigned int index; 163 164 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; 174 175 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; 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, i; 237 unsigned int idx; 238 struct amixer *amixer; 239 unsigned long flags; 240 241 *ramixer = NULL; 242 243 /* Allocate mem for amixer resource */ 244 amixer = kzalloc(sizeof(*amixer), GFP_KERNEL); 245 if (!amixer) 246 return -ENOMEM; 247 248 /* Check whether there are sufficient 249 * amixer resources to meet request. */ 250 err = 0; 251 spin_lock_irqsave(&mgr->mgr_lock, flags); 252 for (i = 0; i < desc->msr; i++) { 253 err = mgr_get_resource(&mgr->mgr, 1, &idx); 254 if (err) 255 break; 256 257 amixer->idx[i] = idx; 258 } 259 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 260 if (err) { 261 dev_err(mgr->card->dev, 262 "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; 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(struct hw *hw, struct amixer_mgr **ramixer_mgr) 301 { 302 int err; 303 struct amixer_mgr *amixer_mgr; 304 305 *ramixer_mgr = NULL; 306 amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); 307 if (!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 amixer_mgr->card = hw->card; 319 320 *ramixer_mgr = amixer_mgr; 321 322 return 0; 323 324 error: 325 kfree(amixer_mgr); 326 return err; 327 } 328 329 int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) 330 { 331 rsc_mgr_uninit(&amixer_mgr->mgr); 332 kfree(amixer_mgr); 333 return 0; 334 } 335 336 /* SUM resource management */ 337 338 static int sum_master(struct rsc *rsc) 339 { 340 rsc->conj = 0; 341 return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; 342 } 343 344 static int sum_next_conj(struct rsc *rsc) 345 { 346 rsc->conj++; 347 return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 348 } 349 350 static int sum_index(const struct rsc *rsc) 351 { 352 return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 353 } 354 355 static int sum_output_slot(const struct rsc *rsc) 356 { 357 return (sum_index(rsc) << 4) + 0xc; 358 } 359 360 static struct rsc_ops sum_basic_rsc_ops = { 361 .master = sum_master, 362 .next_conj = sum_next_conj, 363 .index = sum_index, 364 .output_slot = sum_output_slot, 365 }; 366 367 static int sum_rsc_init(struct sum *sum, 368 const struct sum_desc *desc, 369 struct sum_mgr *mgr) 370 { 371 int err; 372 373 err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); 374 if (err) 375 return err; 376 377 sum->rsc.ops = &sum_basic_rsc_ops; 378 379 return 0; 380 } 381 382 static int sum_rsc_uninit(struct sum *sum) 383 { 384 rsc_uninit(&sum->rsc); 385 return 0; 386 } 387 388 static int get_sum_rsc(struct sum_mgr *mgr, 389 const struct sum_desc *desc, 390 struct sum **rsum) 391 { 392 int err, i; 393 unsigned int idx; 394 struct sum *sum; 395 unsigned long flags; 396 397 *rsum = NULL; 398 399 /* Allocate mem for sum resource */ 400 sum = kzalloc(sizeof(*sum), GFP_KERNEL); 401 if (!sum) 402 return -ENOMEM; 403 404 /* Check whether there are sufficient sum resources to meet request. */ 405 err = 0; 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 dev_err(mgr->card->dev, 417 "Can't meet SUM resource request!\n"); 418 goto error; 419 } 420 421 err = sum_rsc_init(sum, desc, mgr); 422 if (err) 423 goto error; 424 425 *rsum = sum; 426 427 return 0; 428 429 error: 430 spin_lock_irqsave(&mgr->mgr_lock, flags); 431 for (i--; i >= 0; i--) 432 mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 433 434 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 435 kfree(sum); 436 return err; 437 } 438 439 static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) 440 { 441 unsigned long flags; 442 int i; 443 444 spin_lock_irqsave(&mgr->mgr_lock, flags); 445 for (i = 0; i < sum->rsc.msr; i++) 446 mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 447 448 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 449 sum_rsc_uninit(sum); 450 kfree(sum); 451 452 return 0; 453 } 454 455 int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr) 456 { 457 int err; 458 struct sum_mgr *sum_mgr; 459 460 *rsum_mgr = NULL; 461 sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); 462 if (!sum_mgr) 463 return -ENOMEM; 464 465 err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); 466 if (err) 467 goto error; 468 469 spin_lock_init(&sum_mgr->mgr_lock); 470 471 sum_mgr->get_sum = get_sum_rsc; 472 sum_mgr->put_sum = put_sum_rsc; 473 sum_mgr->card = hw->card; 474 475 *rsum_mgr = sum_mgr; 476 477 return 0; 478 479 error: 480 kfree(sum_mgr); 481 return err; 482 } 483 484 int sum_mgr_destroy(struct sum_mgr *sum_mgr) 485 { 486 rsc_mgr_uninit(&sum_mgr->mgr); 487 kfree(sum_mgr); 488 return 0; 489 } 490 491