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, struct amixer_mgr **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(struct amixer_mgr *amixer_mgr) 325 { 326 rsc_mgr_uninit(&amixer_mgr->mgr); 327 kfree(amixer_mgr); 328 return 0; 329 } 330 331 /* SUM resource management */ 332 333 static void sum_master(struct rsc *rsc) 334 { 335 rsc->conj = 0; 336 rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; 337 } 338 339 static void sum_next_conj(struct rsc *rsc) 340 { 341 rsc->conj++; 342 } 343 344 static int sum_index(const struct rsc *rsc) 345 { 346 return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 347 } 348 349 static int sum_output_slot(const struct rsc *rsc) 350 { 351 return (sum_index(rsc) << 4) + 0xc; 352 } 353 354 static const struct rsc_ops sum_basic_rsc_ops = { 355 .master = sum_master, 356 .next_conj = sum_next_conj, 357 .index = sum_index, 358 .output_slot = sum_output_slot, 359 }; 360 361 static int sum_rsc_init(struct sum *sum, 362 const struct sum_desc *desc, 363 struct sum_mgr *mgr) 364 { 365 int err; 366 367 err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); 368 if (err) 369 return err; 370 371 sum->rsc.ops = &sum_basic_rsc_ops; 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 unsigned long flags; 390 391 *rsum = NULL; 392 393 /* Allocate mem for sum resource */ 394 sum = kzalloc(sizeof(*sum), GFP_KERNEL); 395 if (!sum) 396 return -ENOMEM; 397 398 /* Check whether there are sufficient sum resources to meet request. */ 399 err = 0; 400 spin_lock_irqsave(&mgr->mgr_lock, flags); 401 for (i = 0; i < desc->msr; i++) { 402 err = mgr_get_resource(&mgr->mgr, 1, &idx); 403 if (err) 404 break; 405 406 sum->idx[i] = idx; 407 } 408 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 409 if (err) { 410 dev_err(mgr->card->dev, 411 "Can't meet SUM resource request!\n"); 412 goto error; 413 } 414 415 err = sum_rsc_init(sum, desc, mgr); 416 if (err) 417 goto error; 418 419 *rsum = sum; 420 421 return 0; 422 423 error: 424 spin_lock_irqsave(&mgr->mgr_lock, flags); 425 for (i--; i >= 0; i--) 426 mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 427 428 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 429 kfree(sum); 430 return err; 431 } 432 433 static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) 434 { 435 unsigned long flags; 436 int i; 437 438 spin_lock_irqsave(&mgr->mgr_lock, flags); 439 for (i = 0; i < sum->rsc.msr; i++) 440 mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 441 442 spin_unlock_irqrestore(&mgr->mgr_lock, flags); 443 sum_rsc_uninit(sum); 444 kfree(sum); 445 446 return 0; 447 } 448 449 int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr) 450 { 451 int err; 452 struct sum_mgr *sum_mgr; 453 454 *rsum_mgr = NULL; 455 sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); 456 if (!sum_mgr) 457 return -ENOMEM; 458 459 err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); 460 if (err) 461 goto error; 462 463 spin_lock_init(&sum_mgr->mgr_lock); 464 465 sum_mgr->get_sum = get_sum_rsc; 466 sum_mgr->put_sum = put_sum_rsc; 467 sum_mgr->card = hw->card; 468 469 *rsum_mgr = sum_mgr; 470 471 return 0; 472 473 error: 474 kfree(sum_mgr); 475 return err; 476 } 477 478 int sum_mgr_destroy(struct sum_mgr *sum_mgr) 479 { 480 rsc_mgr_uninit(&sum_mgr->mgr); 481 kfree(sum_mgr); 482 return 0; 483 } 484 485