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