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