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->rsc.conj = 0; 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 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 scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { 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 } 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 scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { 271 for (i--; i >= 0; i--) 272 mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); 273 } 274 275 kfree(amixer); 276 return err; 277 } 278 279 static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) 280 { 281 int i; 282 283 scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { 284 for (i = 0; i < amixer->rsc.msr; i++) 285 mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); 286 } 287 amixer_rsc_uninit(amixer); 288 kfree(amixer); 289 290 return 0; 291 } 292 293 int amixer_mgr_create(struct hw *hw, void **ramixer_mgr) 294 { 295 int err; 296 struct amixer_mgr *amixer_mgr; 297 298 *ramixer_mgr = NULL; 299 amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); 300 if (!amixer_mgr) 301 return -ENOMEM; 302 303 err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw); 304 if (err) 305 goto error; 306 307 spin_lock_init(&amixer_mgr->mgr_lock); 308 309 amixer_mgr->get_amixer = get_amixer_rsc; 310 amixer_mgr->put_amixer = put_amixer_rsc; 311 amixer_mgr->card = hw->card; 312 313 *ramixer_mgr = amixer_mgr; 314 315 return 0; 316 317 error: 318 kfree(amixer_mgr); 319 return err; 320 } 321 322 int amixer_mgr_destroy(void *ptr) 323 { 324 struct amixer_mgr *amixer_mgr = ptr; 325 rsc_mgr_uninit(&amixer_mgr->mgr); 326 kfree(amixer_mgr); 327 return 0; 328 } 329 330 /* SUM resource management */ 331 332 static void sum_master(struct rsc *rsc) 333 { 334 rsc->conj = 0; 335 rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; 336 } 337 338 static void sum_next_conj(struct rsc *rsc) 339 { 340 rsc->conj++; 341 } 342 343 static int sum_index(const struct rsc *rsc) 344 { 345 return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 346 } 347 348 static int sum_output_slot(const struct rsc *rsc) 349 { 350 return (sum_index(rsc) << 4) + 0xc; 351 } 352 353 static const struct rsc_ops sum_basic_rsc_ops = { 354 .master = sum_master, 355 .next_conj = sum_next_conj, 356 .index = sum_index, 357 .output_slot = sum_output_slot, 358 }; 359 360 static int sum_rsc_init(struct sum *sum, 361 const struct sum_desc *desc, 362 struct sum_mgr *mgr) 363 { 364 int err; 365 366 err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); 367 if (err) 368 return err; 369 370 sum->rsc.ops = &sum_basic_rsc_ops; 371 sum->rsc.conj = 0; 372 373 return 0; 374 } 375 376 static int sum_rsc_uninit(struct sum *sum) 377 { 378 rsc_uninit(&sum->rsc); 379 return 0; 380 } 381 382 static int get_sum_rsc(struct sum_mgr *mgr, 383 const struct sum_desc *desc, 384 struct sum **rsum) 385 { 386 int err, i; 387 unsigned int idx; 388 struct sum *sum; 389 390 *rsum = NULL; 391 392 /* Allocate mem for sum resource */ 393 sum = kzalloc(sizeof(*sum), GFP_KERNEL); 394 if (!sum) 395 return -ENOMEM; 396 397 /* Check whether there are sufficient sum resources to meet request. */ 398 err = 0; 399 scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { 400 for (i = 0; i < desc->msr; i++) { 401 err = mgr_get_resource(&mgr->mgr, 1, &idx); 402 if (err) 403 break; 404 405 sum->idx[i] = idx; 406 } 407 } 408 if (err) { 409 dev_err(mgr->card->dev, 410 "Can't meet SUM resource request!\n"); 411 goto error; 412 } 413 414 err = sum_rsc_init(sum, desc, mgr); 415 if (err) 416 goto error; 417 418 *rsum = sum; 419 420 return 0; 421 422 error: 423 scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { 424 for (i--; i >= 0; i--) 425 mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 426 } 427 kfree(sum); 428 return err; 429 } 430 431 static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) 432 { 433 int i; 434 435 scoped_guard(spinlock_irqsave, &mgr->mgr_lock) { 436 for (i = 0; i < sum->rsc.msr; i++) 437 mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 438 } 439 sum_rsc_uninit(sum); 440 kfree(sum); 441 442 return 0; 443 } 444 445 int sum_mgr_create(struct hw *hw, void **rsum_mgr) 446 { 447 int err; 448 struct sum_mgr *sum_mgr; 449 450 *rsum_mgr = NULL; 451 sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); 452 if (!sum_mgr) 453 return -ENOMEM; 454 455 err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); 456 if (err) 457 goto error; 458 459 spin_lock_init(&sum_mgr->mgr_lock); 460 461 sum_mgr->get_sum = get_sum_rsc; 462 sum_mgr->put_sum = put_sum_rsc; 463 sum_mgr->card = hw->card; 464 465 *rsum_mgr = sum_mgr; 466 467 return 0; 468 469 error: 470 kfree(sum_mgr); 471 return err; 472 } 473 474 int sum_mgr_destroy(void *ptr) 475 { 476 struct sum_mgr *sum_mgr = ptr; 477 rsc_mgr_uninit(&sum_mgr->mgr); 478 kfree(sum_mgr); 479 return 0; 480 } 481 482