linux/sound/pci/hda/patch_ca0110.c
<<
>>
Prefs
   1/*
   2 * HD audio interface patch for Creative X-Fi CA0110-IBG chip
   3 *
   4 * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
   5 *
   6 *  This driver is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This driver is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  19 */
  20
  21#include <linux/init.h>
  22#include <linux/delay.h>
  23#include <linux/slab.h>
  24#include <linux/pci.h>
  25#include <sound/core.h>
  26#include "hda_codec.h"
  27#include "hda_local.h"
  28
  29/*
  30 */
  31
  32struct ca0110_spec {
  33        struct auto_pin_cfg autocfg;
  34        struct hda_multi_out multiout;
  35        hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
  36        hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
  37        hda_nid_t hp_dac;
  38        hda_nid_t input_pins[AUTO_PIN_LAST];
  39        hda_nid_t adcs[AUTO_PIN_LAST];
  40        hda_nid_t dig_out;
  41        hda_nid_t dig_in;
  42        unsigned int num_inputs;
  43        const char *input_labels[AUTO_PIN_LAST];
  44        struct hda_pcm pcm_rec[2];      /* PCM information */
  45};
  46
  47/*
  48 * PCM callbacks
  49 */
  50static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo,
  51                                    struct hda_codec *codec,
  52                                    struct snd_pcm_substream *substream)
  53{
  54        struct ca0110_spec *spec = codec->spec;
  55        return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
  56                                             hinfo);
  57}
  58
  59static int ca0110_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
  60                                       struct hda_codec *codec,
  61                                       unsigned int stream_tag,
  62                                       unsigned int format,
  63                                       struct snd_pcm_substream *substream)
  64{
  65        struct ca0110_spec *spec = codec->spec;
  66        return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
  67                                                stream_tag, format, substream);
  68}
  69
  70static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
  71                                       struct hda_codec *codec,
  72                                       struct snd_pcm_substream *substream)
  73{
  74        struct ca0110_spec *spec = codec->spec;
  75        return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
  76}
  77
  78/*
  79 * Digital out
  80 */
  81static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
  82                                        struct hda_codec *codec,
  83                                        struct snd_pcm_substream *substream)
  84{
  85        struct ca0110_spec *spec = codec->spec;
  86        return snd_hda_multi_out_dig_open(codec, &spec->multiout);
  87}
  88
  89static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
  90                                         struct hda_codec *codec,
  91                                         struct snd_pcm_substream *substream)
  92{
  93        struct ca0110_spec *spec = codec->spec;
  94        return snd_hda_multi_out_dig_close(codec, &spec->multiout);
  95}
  96
  97static int ca0110_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
  98                                           struct hda_codec *codec,
  99                                           unsigned int stream_tag,
 100                                           unsigned int format,
 101                                           struct snd_pcm_substream *substream)
 102{
 103        struct ca0110_spec *spec = codec->spec;
 104        return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
 105                                             format, substream);
 106}
 107
 108/*
 109 * Analog capture
 110 */
 111static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
 112                                      struct hda_codec *codec,
 113                                      unsigned int stream_tag,
 114                                      unsigned int format,
 115                                      struct snd_pcm_substream *substream)
 116{
 117        struct ca0110_spec *spec = codec->spec;
 118
 119        snd_hda_codec_setup_stream(codec, spec->adcs[substream->number],
 120                                   stream_tag, 0, format);
 121        return 0;
 122}
 123
 124static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 125                                      struct hda_codec *codec,
 126                                      struct snd_pcm_substream *substream)
 127{
 128        struct ca0110_spec *spec = codec->spec;
 129
 130        snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]);
 131        return 0;
 132}
 133
 134/*
 135 */
 136
 137static char *dirstr[2] = { "Playback", "Capture" };
 138
 139static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
 140                       int chan, int dir)
 141{
 142        char namestr[44];
 143        int type = dir ? HDA_INPUT : HDA_OUTPUT;
 144        struct snd_kcontrol_new knew =
 145                HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type);
 146        sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
 147        return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
 148}
 149
 150static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
 151                       int chan, int dir)
 152{
 153        char namestr[44];
 154        int type = dir ? HDA_INPUT : HDA_OUTPUT;
 155        struct snd_kcontrol_new knew =
 156                HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type);
 157        sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]);
 158        return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
 159}
 160
 161#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0)
 162#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0)
 163#define add_in_switch(codec, nid, pfx)  _add_switch(codec, nid, pfx, 3, 1)
 164#define add_in_volume(codec, nid, pfx)  _add_volume(codec, nid, pfx, 3, 1)
 165#define add_mono_switch(codec, nid, pfx, chan) \
 166        _add_switch(codec, nid, pfx, chan, 0)
 167#define add_mono_volume(codec, nid, pfx, chan) \
 168        _add_volume(codec, nid, pfx, chan, 0)
 169
 170static int ca0110_build_controls(struct hda_codec *codec)
 171{
 172        struct ca0110_spec *spec = codec->spec;
 173        struct auto_pin_cfg *cfg = &spec->autocfg;
 174        static char *prefix[AUTO_CFG_MAX_OUTS] = {
 175                "Front", "Surround", NULL, "Side", "Multi"
 176        };
 177        hda_nid_t mutenid;
 178        int i, err;
 179
 180        for (i = 0; i < spec->multiout.num_dacs; i++) {
 181                if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP)
 182                        mutenid = spec->out_pins[i];
 183                else
 184                        mutenid = spec->multiout.dac_nids[i];
 185                if (!prefix[i]) {
 186                        err = add_mono_switch(codec, mutenid,
 187                                              "Center", 1);
 188                        if (err < 0)
 189                                return err;
 190                        err = add_mono_switch(codec, mutenid,
 191                                              "LFE", 1);
 192                        if (err < 0)
 193                                return err;
 194                        err = add_mono_volume(codec, spec->multiout.dac_nids[i],
 195                                              "Center", 1);
 196                        if (err < 0)
 197                                return err;
 198                        err = add_mono_volume(codec, spec->multiout.dac_nids[i],
 199                                              "LFE", 1);
 200                        if (err < 0)
 201                                return err;
 202                } else {
 203                        err = add_out_switch(codec, mutenid,
 204                                             prefix[i]);
 205                        if (err < 0)
 206                                return err;
 207                        err = add_out_volume(codec, spec->multiout.dac_nids[i],
 208                                         prefix[i]);
 209                        if (err < 0)
 210                                return err;
 211                }
 212        }
 213        if (cfg->hp_outs) {
 214                if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP)
 215                        mutenid = cfg->hp_pins[0];
 216                else
 217                        mutenid = spec->multiout.dac_nids[i];
 218
 219                err = add_out_switch(codec, mutenid, "Headphone");
 220                if (err < 0)
 221                        return err;
 222                if (spec->hp_dac) {
 223                        err = add_out_volume(codec, spec->hp_dac, "Headphone");
 224                        if (err < 0)
 225                                return err;
 226                }
 227        }
 228        for (i = 0; i < spec->num_inputs; i++) {
 229                const char *label = spec->input_labels[i];
 230                if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP)
 231                        mutenid = spec->input_pins[i];
 232                else
 233                        mutenid = spec->adcs[i];
 234                err = add_in_switch(codec, mutenid, label);
 235                if (err < 0)
 236                        return err;
 237                err = add_in_volume(codec, spec->adcs[i], label);
 238                if (err < 0)
 239                        return err;
 240        }
 241
 242        if (spec->dig_out) {
 243                err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out);
 244                if (err < 0)
 245                        return err;
 246                err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
 247                if (err < 0)
 248                        return err;
 249                spec->multiout.share_spdif = 1;
 250        }
 251        if (spec->dig_in) {
 252                err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
 253                if (err < 0)
 254                        return err;
 255                err = add_in_volume(codec, spec->dig_in, "IEC958");
 256        }
 257        return 0;
 258}
 259
 260/*
 261 */
 262static struct hda_pcm_stream ca0110_pcm_analog_playback = {
 263        .substreams = 1,
 264        .channels_min = 2,
 265        .channels_max = 8,
 266        .ops = {
 267                .open = ca0110_playback_pcm_open,
 268                .prepare = ca0110_playback_pcm_prepare,
 269                .cleanup = ca0110_playback_pcm_cleanup
 270        },
 271};
 272
 273static struct hda_pcm_stream ca0110_pcm_analog_capture = {
 274        .substreams = 1,
 275        .channels_min = 2,
 276        .channels_max = 2,
 277        .ops = {
 278                .prepare = ca0110_capture_pcm_prepare,
 279                .cleanup = ca0110_capture_pcm_cleanup
 280        },
 281};
 282
 283static struct hda_pcm_stream ca0110_pcm_digital_playback = {
 284        .substreams = 1,
 285        .channels_min = 2,
 286        .channels_max = 2,
 287        .ops = {
 288                .open = ca0110_dig_playback_pcm_open,
 289                .close = ca0110_dig_playback_pcm_close,
 290                .prepare = ca0110_dig_playback_pcm_prepare
 291        },
 292};
 293
 294static struct hda_pcm_stream ca0110_pcm_digital_capture = {
 295        .substreams = 1,
 296        .channels_min = 2,
 297        .channels_max = 2,
 298};
 299
 300static int ca0110_build_pcms(struct hda_codec *codec)
 301{
 302        struct ca0110_spec *spec = codec->spec;
 303        struct hda_pcm *info = spec->pcm_rec;
 304
 305        codec->pcm_info = info;
 306        codec->num_pcms = 0;
 307
 308        info->name = "CA0110 Analog";
 309        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback;
 310        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
 311        info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
 312                spec->multiout.max_channels;
 313        info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture;
 314        info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs;
 315        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
 316        codec->num_pcms++;
 317
 318        if (!spec->dig_out && !spec->dig_in)
 319                return 0;
 320
 321        info++;
 322        info->name = "CA0110 Digital";
 323        info->pcm_type = HDA_PCM_TYPE_SPDIF;
 324        if (spec->dig_out) {
 325                info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
 326                        ca0110_pcm_digital_playback;
 327                info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
 328        }
 329        if (spec->dig_in) {
 330                info->stream[SNDRV_PCM_STREAM_CAPTURE] =
 331                        ca0110_pcm_digital_capture;
 332                info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
 333        }
 334        codec->num_pcms++;
 335
 336        return 0;
 337}
 338
 339static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 340{
 341        if (pin) {
 342                snd_hda_codec_write(codec, pin, 0,
 343                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
 344                if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
 345                        snd_hda_codec_write(codec, pin, 0,
 346                                            AC_VERB_SET_AMP_GAIN_MUTE,
 347                                            AMP_OUT_UNMUTE);
 348        }
 349        if (dac)
 350                snd_hda_codec_write(codec, dac, 0,
 351                                    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
 352}
 353
 354static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
 355{
 356        if (pin) {
 357                snd_hda_codec_write(codec, pin, 0,
 358                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
 359                if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
 360                        snd_hda_codec_write(codec, pin, 0,
 361                                            AC_VERB_SET_AMP_GAIN_MUTE,
 362                                            AMP_IN_UNMUTE(0));
 363        }
 364        if (adc)
 365                snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 366                                    AMP_IN_UNMUTE(0));
 367}
 368
 369static int ca0110_init(struct hda_codec *codec)
 370{
 371        struct ca0110_spec *spec = codec->spec;
 372        struct auto_pin_cfg *cfg = &spec->autocfg;
 373        int i;
 374
 375        for (i = 0; i < spec->multiout.num_dacs; i++)
 376                init_output(codec, spec->out_pins[i],
 377                            spec->multiout.dac_nids[i]);
 378        init_output(codec, cfg->hp_pins[0], spec->hp_dac);
 379        init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
 380
 381        for (i = 0; i < spec->num_inputs; i++)
 382                init_input(codec, spec->input_pins[i], spec->adcs[i]);
 383        init_input(codec, cfg->dig_in_pin, spec->dig_in);
 384        return 0;
 385}
 386
 387static void ca0110_free(struct hda_codec *codec)
 388{
 389        kfree(codec->spec);
 390}
 391
 392static struct hda_codec_ops ca0110_patch_ops = {
 393        .build_controls = ca0110_build_controls,
 394        .build_pcms = ca0110_build_pcms,
 395        .init = ca0110_init,
 396        .free = ca0110_free,
 397};
 398
 399
 400static void parse_line_outs(struct hda_codec *codec)
 401{
 402        struct ca0110_spec *spec = codec->spec;
 403        struct auto_pin_cfg *cfg = &spec->autocfg;
 404        int i, n;
 405        unsigned int def_conf;
 406        hda_nid_t nid;
 407
 408        n = 0;
 409        for (i = 0; i < cfg->line_outs; i++) {
 410                nid = cfg->line_out_pins[i];
 411                def_conf = snd_hda_codec_get_pincfg(codec, nid);
 412                if (!def_conf)
 413                        continue; /* invalid pin */
 414                if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1)
 415                        continue;
 416                spec->out_pins[n++] = nid;
 417        }
 418        spec->multiout.dac_nids = spec->dacs;
 419        spec->multiout.num_dacs = n;
 420        spec->multiout.max_channels = n * 2;
 421}
 422
 423static void parse_hp_out(struct hda_codec *codec)
 424{
 425        struct ca0110_spec *spec = codec->spec;
 426        struct auto_pin_cfg *cfg = &spec->autocfg;
 427        int i;
 428        unsigned int def_conf;
 429        hda_nid_t nid, dac;
 430
 431        if (!cfg->hp_outs)
 432                return;
 433        nid = cfg->hp_pins[0];
 434        def_conf = snd_hda_codec_get_pincfg(codec, nid);
 435        if (!def_conf) {
 436                cfg->hp_outs = 0;
 437                return;
 438        }
 439        if (snd_hda_get_connections(codec, nid, &dac, 1) != 1)
 440                return;
 441
 442        for (i = 0; i < cfg->line_outs; i++)
 443                if (dac == spec->dacs[i])
 444                        break;
 445        if (i >= cfg->line_outs) {
 446                spec->hp_dac = dac;
 447                spec->multiout.hp_nid = dac;
 448        }
 449}
 450
 451static void parse_input(struct hda_codec *codec)
 452{
 453        struct ca0110_spec *spec = codec->spec;
 454        struct auto_pin_cfg *cfg = &spec->autocfg;
 455        hda_nid_t nid, pin;
 456        int n, i, j;
 457
 458        n = 0;
 459        nid = codec->start_nid;
 460        for (i = 0; i < codec->num_nodes; i++, nid++) {
 461                unsigned int wcaps = get_wcaps(codec, nid);
 462                unsigned int type = get_wcaps_type(wcaps);
 463                if (type != AC_WID_AUD_IN)
 464                        continue;
 465                if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
 466                        continue;
 467                if (pin == cfg->dig_in_pin) {
 468                        spec->dig_in = nid;
 469                        continue;
 470                }
 471                for (j = 0; j < AUTO_PIN_LAST; j++)
 472                        if (cfg->input_pins[j] == pin)
 473                                break;
 474                if (j >= AUTO_PIN_LAST)
 475                        continue;
 476                spec->input_pins[n] = pin;
 477                spec->input_labels[n] = auto_pin_cfg_labels[j];
 478                spec->adcs[n] = nid;
 479                n++;
 480        }
 481        spec->num_inputs = n;
 482}
 483
 484static void parse_digital(struct hda_codec *codec)
 485{
 486        struct ca0110_spec *spec = codec->spec;
 487        struct auto_pin_cfg *cfg = &spec->autocfg;
 488
 489        if (cfg->dig_outs &&
 490            snd_hda_get_connections(codec, cfg->dig_out_pins[0],
 491                                    &spec->dig_out, 1) == 1)
 492                spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
 493}
 494
 495static int ca0110_parse_auto_config(struct hda_codec *codec)
 496{
 497        struct ca0110_spec *spec = codec->spec;
 498        int err;
 499
 500        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
 501        if (err < 0)
 502                return err;
 503
 504        parse_line_outs(codec);
 505        parse_hp_out(codec);
 506        parse_digital(codec);
 507        parse_input(codec);
 508        return 0;
 509}
 510
 511
 512static int patch_ca0110(struct hda_codec *codec)
 513{
 514        struct ca0110_spec *spec;
 515        int err;
 516
 517        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 518        if (!spec)
 519                return -ENOMEM;
 520        codec->spec = spec;
 521
 522        codec->bus->needs_damn_long_delay = 1;
 523
 524        err = ca0110_parse_auto_config(codec);
 525        if (err < 0)
 526                goto error;
 527
 528        codec->patch_ops = ca0110_patch_ops;
 529
 530        return 0;
 531
 532 error:
 533        kfree(codec->spec);
 534        codec->spec = NULL;
 535        return err;
 536}
 537
 538
 539/*
 540 * patch entries
 541 */
 542static struct hda_codec_preset snd_hda_preset_ca0110[] = {
 543        { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 },
 544        { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 },
 545        { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 },
 546        {} /* terminator */
 547};
 548
 549MODULE_ALIAS("snd-hda-codec-id:1102000a");
 550MODULE_ALIAS("snd-hda-codec-id:1102000b");
 551MODULE_ALIAS("snd-hda-codec-id:1102000d");
 552
 553MODULE_LICENSE("GPL");
 554MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
 555
 556static struct hda_codec_preset_list ca0110_list = {
 557        .preset = snd_hda_preset_ca0110,
 558        .owner = THIS_MODULE,
 559};
 560
 561static int __init patch_ca0110_init(void)
 562{
 563        return snd_hda_add_codec_preset(&ca0110_list);
 564}
 565
 566static void __exit patch_ca0110_exit(void)
 567{
 568        snd_hda_delete_codec_preset(&ca0110_list);
 569}
 570
 571module_init(patch_ca0110_init)
 572module_exit(patch_ca0110_exit)
 573