root/drivers/media/i2c/cx25840/cx25840-audio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cx25840_set_audclk_freq
  2. cx25836_set_audclk_freq
  3. cx23885_set_audclk_freq
  4. cx231xx_set_audclk_freq
  5. set_audclk_freq
  6. cx25840_audio_set_path
  7. set_volume
  8. set_balance
  9. cx25840_s_clock_freq
  10. cx25840_audio_s_ctrl

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* cx25840 audio functions
   3  */
   4 
   5 
   6 #include <linux/videodev2.h>
   7 #include <linux/i2c.h>
   8 #include <media/v4l2-common.h>
   9 #include <media/drv-intf/cx25840.h>
  10 
  11 #include "cx25840-core.h"
  12 
  13 /*
  14  * Note: The PLL and SRC parameters are based on a reference frequency that
  15  * would ideally be:
  16  *
  17  * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
  18  *
  19  * However, it's not the exact reference frequency that matters, only that the
  20  * firmware and modules that comprise the driver for a particular board all
  21  * use the same value (close to the ideal value).
  22  *
  23  * Comments below will note which reference frequency is assumed for various
  24  * parameters.  They will usually be one of
  25  *
  26  *      ref_freq = 28.636360 MHz
  27  *              or
  28  *      ref_freq = 28.636363 MHz
  29  */
  30 
  31 static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq)
  32 {
  33         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
  34 
  35         if (state->aud_input != CX25840_AUDIO_SERIAL) {
  36                 switch (freq) {
  37                 case 32000:
  38                         /*
  39                          * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
  40                          * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
  41                          */
  42                         cx25840_write4(client, 0x108, 0x1006040f);
  43 
  44                         /*
  45                          * VID_PLL Fraction (register 0x10c) = 0x2be2fe
  46                          * 28636360 * 0xf.15f17f0/4 = 108 MHz
  47                          * 432 MHz pre-postdivide
  48                          */
  49 
  50                         /*
  51                          * AUX_PLL Fraction = 0x1bb39ee
  52                          * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384
  53                          * 196.6 MHz pre-postdivide
  54                          * FIXME < 200 MHz is out of specified valid range
  55                          * FIXME 28636363 ref_freq doesn't match VID PLL ref
  56                          */
  57                         cx25840_write4(client, 0x110, 0x01bb39ee);
  58 
  59                         /*
  60                          * SA_MCLK_SEL = 1
  61                          * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
  62                          */
  63                         cx25840_write(client, 0x127, 0x50);
  64 
  65                         if (is_cx2583x(state))
  66                                 break;
  67 
  68                         /* src3/4/6_ctl */
  69                         /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
  70                         cx25840_write4(client, 0x900, 0x0801f77f);
  71                         cx25840_write4(client, 0x904, 0x0801f77f);
  72                         cx25840_write4(client, 0x90c, 0x0801f77f);
  73                         break;
  74 
  75                 case 44100:
  76                         /*
  77                          * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
  78                          * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
  79                          */
  80                         cx25840_write4(client, 0x108, 0x1009040f);
  81 
  82                         /*
  83                          * VID_PLL Fraction (register 0x10c) = 0x2be2fe
  84                          * 28636360 * 0xf.15f17f0/4 = 108 MHz
  85                          * 432 MHz pre-postdivide
  86                          */
  87 
  88                         /*
  89                          * AUX_PLL Fraction = 0x0ec6bd6
  90                          * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384
  91                          * 271 MHz pre-postdivide
  92                          * FIXME 28636363 ref_freq doesn't match VID PLL ref
  93                          */
  94                         cx25840_write4(client, 0x110, 0x00ec6bd6);
  95 
  96                         /*
  97                          * SA_MCLK_SEL = 1
  98                          * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
  99                          */
 100                         cx25840_write(client, 0x127, 0x50);
 101 
 102                         if (is_cx2583x(state))
 103                                 break;
 104 
 105                         /* src3/4/6_ctl */
 106                         /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
 107                         cx25840_write4(client, 0x900, 0x08016d59);
 108                         cx25840_write4(client, 0x904, 0x08016d59);
 109                         cx25840_write4(client, 0x90c, 0x08016d59);
 110                         break;
 111 
 112                 case 48000:
 113                         /*
 114                          * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
 115                          * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
 116                          */
 117                         cx25840_write4(client, 0x108, 0x100a040f);
 118 
 119                         /*
 120                          * VID_PLL Fraction (register 0x10c) = 0x2be2fe
 121                          * 28636360 * 0xf.15f17f0/4 = 108 MHz
 122                          * 432 MHz pre-postdivide
 123                          */
 124 
 125                         /*
 126                          * AUX_PLL Fraction = 0x098d6e5
 127                          * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384
 128                          * 295 MHz pre-postdivide
 129                          * FIXME 28636363 ref_freq doesn't match VID PLL ref
 130                          */
 131                         cx25840_write4(client, 0x110, 0x0098d6e5);
 132 
 133                         /*
 134                          * SA_MCLK_SEL = 1
 135                          * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
 136                          */
 137                         cx25840_write(client, 0x127, 0x50);
 138 
 139                         if (is_cx2583x(state))
 140                                 break;
 141 
 142                         /* src3/4/6_ctl */
 143                         /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
 144                         cx25840_write4(client, 0x900, 0x08014faa);
 145                         cx25840_write4(client, 0x904, 0x08014faa);
 146                         cx25840_write4(client, 0x90c, 0x08014faa);
 147                         break;
 148                 }
 149         } else {
 150                 switch (freq) {
 151                 case 32000:
 152                         /*
 153                          * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
 154                          * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
 155                          */
 156                         cx25840_write4(client, 0x108, 0x1e08040f);
 157 
 158                         /*
 159                          * VID_PLL Fraction (register 0x10c) = 0x2be2fe
 160                          * 28636360 * 0xf.15f17f0/4 = 108 MHz
 161                          * 432 MHz pre-postdivide
 162                          */
 163 
 164                         /*
 165                          * AUX_PLL Fraction = 0x12a0869
 166                          * 28636363 * 0x8.9504348/0x1e = 32000 * 256
 167                          * 246 MHz pre-postdivide
 168                          * FIXME 28636363 ref_freq doesn't match VID PLL ref
 169                          */
 170                         cx25840_write4(client, 0x110, 0x012a0869);
 171 
 172                         /*
 173                          * SA_MCLK_SEL = 1
 174                          * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
 175                          */
 176                         cx25840_write(client, 0x127, 0x54);
 177 
 178                         if (is_cx2583x(state))
 179                                 break;
 180 
 181                         /* src1_ctl */
 182                         /* 0x1.0000 = 32000/32000 */
 183                         cx25840_write4(client, 0x8f8, 0x08010000);
 184 
 185                         /* src3/4/6_ctl */
 186                         /* 0x2.0000 = 2 * (32000/32000) */
 187                         cx25840_write4(client, 0x900, 0x08020000);
 188                         cx25840_write4(client, 0x904, 0x08020000);
 189                         cx25840_write4(client, 0x90c, 0x08020000);
 190                         break;
 191 
 192                 case 44100:
 193                         /*
 194                          * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
 195                          * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
 196                          */
 197                         cx25840_write4(client, 0x108, 0x1809040f);
 198 
 199                         /*
 200                          * VID_PLL Fraction (register 0x10c) = 0x2be2fe
 201                          * 28636360 * 0xf.15f17f0/4 = 108 MHz
 202                          * 432 MHz pre-postdivide
 203                          */
 204 
 205                         /*
 206                          * AUX_PLL Fraction = 0x0ec6bd6
 207                          * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256
 208                          * 271 MHz pre-postdivide
 209                          * FIXME 28636363 ref_freq doesn't match VID PLL ref
 210                          */
 211                         cx25840_write4(client, 0x110, 0x00ec6bd6);
 212 
 213                         /*
 214                          * SA_MCLK_SEL = 1
 215                          * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
 216                          */
 217                         cx25840_write(client, 0x127, 0x50);
 218 
 219                         if (is_cx2583x(state))
 220                                 break;
 221 
 222                         /* src1_ctl */
 223                         /* 0x1.60cd = 44100/32000 */
 224                         cx25840_write4(client, 0x8f8, 0x080160cd);
 225 
 226                         /* src3/4/6_ctl */
 227                         /* 0x1.7385 = 2 * (32000/44100) */
 228                         cx25840_write4(client, 0x900, 0x08017385);
 229                         cx25840_write4(client, 0x904, 0x08017385);
 230                         cx25840_write4(client, 0x90c, 0x08017385);
 231                         break;
 232 
 233                 case 48000:
 234                         /*
 235                          * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
 236                          * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
 237                          */
 238                         cx25840_write4(client, 0x108, 0x180a040f);
 239 
 240                         /*
 241                          * VID_PLL Fraction (register 0x10c) = 0x2be2fe
 242                          * 28636360 * 0xf.15f17f0/4 = 108 MHz
 243                          * 432 MHz pre-postdivide
 244                          */
 245 
 246                         /*
 247                          * AUX_PLL Fraction = 0x098d6e5
 248                          * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256
 249                          * 295 MHz pre-postdivide
 250                          * FIXME 28636363 ref_freq doesn't match VID PLL ref
 251                          */
 252                         cx25840_write4(client, 0x110, 0x0098d6e5);
 253 
 254                         /*
 255                          * SA_MCLK_SEL = 1
 256                          * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
 257                          */
 258                         cx25840_write(client, 0x127, 0x50);
 259 
 260                         if (is_cx2583x(state))
 261                                 break;
 262 
 263                         /* src1_ctl */
 264                         /* 0x1.8000 = 48000/32000 */
 265                         cx25840_write4(client, 0x8f8, 0x08018000);
 266 
 267                         /* src3/4/6_ctl */
 268                         /* 0x1.5555 = 2 * (32000/48000) */
 269                         cx25840_write4(client, 0x900, 0x08015555);
 270                         cx25840_write4(client, 0x904, 0x08015555);
 271                         cx25840_write4(client, 0x90c, 0x08015555);
 272                         break;
 273                 }
 274         }
 275 
 276         state->audclk_freq = freq;
 277 
 278         return 0;
 279 }
 280 
 281 static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq)
 282 {
 283         return cx25840_set_audclk_freq(client, freq);
 284 }
 285 
 286 static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq)
 287 {
 288         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 289 
 290         if (state->aud_input != CX25840_AUDIO_SERIAL) {
 291                 switch (freq) {
 292                 case 32000:
 293                 case 44100:
 294                 case 48000:
 295                         /* We don't have register values
 296                          * so avoid destroying registers. */
 297                         /* FIXME return -EINVAL; */
 298                         break;
 299                 }
 300         } else {
 301                 switch (freq) {
 302                 case 32000:
 303                 case 44100:
 304                         /* We don't have register values
 305                          * so avoid destroying registers. */
 306                         /* FIXME return -EINVAL; */
 307                         break;
 308 
 309                 case 48000:
 310                         /* src1_ctl */
 311                         /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
 312                         cx25840_write4(client, 0x8f8, 0x0801867c);
 313 
 314                         /* src3/4/6_ctl */
 315                         /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
 316                         cx25840_write4(client, 0x900, 0x08014faa);
 317                         cx25840_write4(client, 0x904, 0x08014faa);
 318                         cx25840_write4(client, 0x90c, 0x08014faa);
 319                         break;
 320                 }
 321         }
 322 
 323         state->audclk_freq = freq;
 324 
 325         return 0;
 326 }
 327 
 328 static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq)
 329 {
 330         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 331 
 332         if (state->aud_input != CX25840_AUDIO_SERIAL) {
 333                 switch (freq) {
 334                 case 32000:
 335                         /* src3/4/6_ctl */
 336                         /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
 337                         cx25840_write4(client, 0x900, 0x0801f77f);
 338                         cx25840_write4(client, 0x904, 0x0801f77f);
 339                         cx25840_write4(client, 0x90c, 0x0801f77f);
 340                         break;
 341 
 342                 case 44100:
 343                         /* src3/4/6_ctl */
 344                         /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
 345                         cx25840_write4(client, 0x900, 0x08016d59);
 346                         cx25840_write4(client, 0x904, 0x08016d59);
 347                         cx25840_write4(client, 0x90c, 0x08016d59);
 348                         break;
 349 
 350                 case 48000:
 351                         /* src3/4/6_ctl */
 352                         /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
 353                         cx25840_write4(client, 0x900, 0x08014faa);
 354                         cx25840_write4(client, 0x904, 0x08014faa);
 355                         cx25840_write4(client, 0x90c, 0x08014faa);
 356                         break;
 357                 }
 358         } else {
 359                 switch (freq) {
 360                 /* FIXME These cases make different assumptions about audclk */
 361                 case 32000:
 362                         /* src1_ctl */
 363                         /* 0x1.0000 = 32000/32000 */
 364                         cx25840_write4(client, 0x8f8, 0x08010000);
 365 
 366                         /* src3/4/6_ctl */
 367                         /* 0x2.0000 = 2 * (32000/32000) */
 368                         cx25840_write4(client, 0x900, 0x08020000);
 369                         cx25840_write4(client, 0x904, 0x08020000);
 370                         cx25840_write4(client, 0x90c, 0x08020000);
 371                         break;
 372 
 373                 case 44100:
 374                         /* src1_ctl */
 375                         /* 0x1.60cd = 44100/32000 */
 376                         cx25840_write4(client, 0x8f8, 0x080160cd);
 377 
 378                         /* src3/4/6_ctl */
 379                         /* 0x1.7385 = 2 * (32000/44100) */
 380                         cx25840_write4(client, 0x900, 0x08017385);
 381                         cx25840_write4(client, 0x904, 0x08017385);
 382                         cx25840_write4(client, 0x90c, 0x08017385);
 383                         break;
 384 
 385                 case 48000:
 386                         /* src1_ctl */
 387                         /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
 388                         cx25840_write4(client, 0x8f8, 0x0801867c);
 389 
 390                         /* src3/4/6_ctl */
 391                         /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
 392                         cx25840_write4(client, 0x900, 0x08014faa);
 393                         cx25840_write4(client, 0x904, 0x08014faa);
 394                         cx25840_write4(client, 0x90c, 0x08014faa);
 395                         break;
 396                 }
 397         }
 398 
 399         state->audclk_freq = freq;
 400 
 401         return 0;
 402 }
 403 
 404 static int set_audclk_freq(struct i2c_client *client, u32 freq)
 405 {
 406         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 407 
 408         if (freq != 32000 && freq != 44100 && freq != 48000)
 409                 return -EINVAL;
 410 
 411         if (is_cx231xx(state))
 412                 return cx231xx_set_audclk_freq(client, freq);
 413 
 414         if (is_cx2388x(state))
 415                 return cx23885_set_audclk_freq(client, freq);
 416 
 417         if (is_cx2583x(state))
 418                 return cx25836_set_audclk_freq(client, freq);
 419 
 420         return cx25840_set_audclk_freq(client, freq);
 421 }
 422 
 423 void cx25840_audio_set_path(struct i2c_client *client)
 424 {
 425         struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 426 
 427         if (!is_cx2583x(state)) {
 428                 /* assert soft reset */
 429                 cx25840_and_or(client, 0x810, ~0x1, 0x01);
 430 
 431                 /* stop microcontroller */
 432                 cx25840_and_or(client, 0x803, ~0x10, 0);
 433 
 434                 /* Mute everything to prevent the PFFT! */
 435                 cx25840_write(client, 0x8d3, 0x1f);
 436 
 437                 if (state->aud_input == CX25840_AUDIO_SERIAL) {
 438                         /* Set Path1 to Serial Audio Input */
 439                         cx25840_write4(client, 0x8d0, 0x01011012);
 440 
 441                         /* The microcontroller should not be started for the
 442                          * non-tuner inputs: autodetection is specific for
 443                          * TV audio. */
 444                 } else {
 445                         /* Set Path1 to Analog Demod Main Channel */
 446                         cx25840_write4(client, 0x8d0, 0x1f063870);
 447                 }
 448         }
 449 
 450         set_audclk_freq(client, state->audclk_freq);
 451 
 452         if (!is_cx2583x(state)) {
 453                 if (state->aud_input != CX25840_AUDIO_SERIAL) {
 454                         /* When the microcontroller detects the
 455                          * audio format, it will unmute the lines */
 456                         cx25840_and_or(client, 0x803, ~0x10, 0x10);
 457                 }
 458 
 459                 /* deassert soft reset */
 460                 cx25840_and_or(client, 0x810, ~0x1, 0x00);
 461 
 462                 /* Ensure the controller is running when we exit */
 463                 if (is_cx2388x(state) || is_cx231xx(state))
 464                         cx25840_and_or(client, 0x803, ~0x10, 0x10);
 465         }
 466 }
 467 
 468 static void set_volume(struct i2c_client *client, int volume)
 469 {
 470         int vol;
 471 
 472         /* Convert the volume to msp3400 values (0-127) */
 473         vol = volume >> 9;
 474 
 475         /* now scale it up to cx25840 values
 476          * -114dB to -96dB maps to 0
 477          * this should be 19, but in my testing that was 4dB too loud */
 478         if (vol <= 23) {
 479                 vol = 0;
 480         } else {
 481                 vol -= 23;
 482         }
 483 
 484         /* PATH1_VOLUME */
 485         cx25840_write(client, 0x8d4, 228 - (vol * 2));
 486 }
 487 
 488 static void set_balance(struct i2c_client *client, int balance)
 489 {
 490         int bal = balance >> 8;
 491         if (bal > 0x80) {
 492                 /* PATH1_BAL_LEFT */
 493                 cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
 494                 /* PATH1_BAL_LEVEL */
 495                 cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
 496         } else {
 497                 /* PATH1_BAL_LEFT */
 498                 cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
 499                 /* PATH1_BAL_LEVEL */
 500                 cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
 501         }
 502 }
 503 
 504 int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 505 {
 506         struct i2c_client *client = v4l2_get_subdevdata(sd);
 507         struct cx25840_state *state = to_state(sd);
 508         int retval;
 509 
 510         if (!is_cx2583x(state))
 511                 cx25840_and_or(client, 0x810, ~0x1, 1);
 512         if (state->aud_input != CX25840_AUDIO_SERIAL) {
 513                 cx25840_and_or(client, 0x803, ~0x10, 0);
 514                 cx25840_write(client, 0x8d3, 0x1f);
 515         }
 516         retval = set_audclk_freq(client, freq);
 517         if (state->aud_input != CX25840_AUDIO_SERIAL)
 518                 cx25840_and_or(client, 0x803, ~0x10, 0x10);
 519         if (!is_cx2583x(state))
 520                 cx25840_and_or(client, 0x810, ~0x1, 0);
 521         return retval;
 522 }
 523 
 524 static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl)
 525 {
 526         struct v4l2_subdev *sd = to_sd(ctrl);
 527         struct cx25840_state *state = to_state(sd);
 528         struct i2c_client *client = v4l2_get_subdevdata(sd);
 529 
 530         switch (ctrl->id) {
 531         case V4L2_CID_AUDIO_VOLUME:
 532                 if (state->mute->val)
 533                         set_volume(client, 0);
 534                 else
 535                         set_volume(client, state->volume->val);
 536                 break;
 537         case V4L2_CID_AUDIO_BASS:
 538                 /* PATH1_EQ_BASS_VOL */
 539                 cx25840_and_or(client, 0x8d9, ~0x3f,
 540                                         48 - (ctrl->val * 48 / 0xffff));
 541                 break;
 542         case V4L2_CID_AUDIO_TREBLE:
 543                 /* PATH1_EQ_TREBLE_VOL */
 544                 cx25840_and_or(client, 0x8db, ~0x3f,
 545                                         48 - (ctrl->val * 48 / 0xffff));
 546                 break;
 547         case V4L2_CID_AUDIO_BALANCE:
 548                 set_balance(client, ctrl->val);
 549                 break;
 550         default:
 551                 return -EINVAL;
 552         }
 553         return 0;
 554 }
 555 
 556 const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = {
 557         .s_ctrl = cx25840_audio_s_ctrl,
 558 };

/* [<][>][^][v][top][bottom][index][help] */