1058 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Apple Onboard Audio driver for Onyx codec4 *5 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>6 *7 * This is a driver for the pcm3052 codec chip (codenamed Onyx)8 * that is present in newer Apple hardware (with digital output).9 *10 * The Onyx codec has the following connections (listed by the bit11 * to be used in aoa_codec.connected):12 * 0: analog output13 * 1: digital output14 * 2: line input15 * 3: microphone input16 * Note that even though I know of no machine that has for example17 * the digital output connected but not the analog, I have handled18 * all the different cases in the code so that this driver may serve19 * as a good example of what to do.20 *21 * NOTE: This driver assumes that there's at most one chip to be22 * used with one alsa card, in form of creating all kinds23 * of mixer elements without regard for their existence.24 * But snd-aoa assumes that there's at most one card, so25 * this means you can only have one onyx on a system. This26 * should probably be fixed by changing the assumption of27 * having just a single card on a system, and making the28 * 'card' pointer accessible to anyone who needs it instead29 * of hiding it in the aoa_snd_* functions...30 */31#include <linux/delay.h>32#include <linux/module.h>33#include <linux/of.h>34#include <linux/slab.h>35MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");36MODULE_LICENSE("GPL");37MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");38 39#include "onyx.h"40#include "../aoa.h"41#include "../soundbus/soundbus.h"42 43 44#define PFX "snd-aoa-codec-onyx: "45 46struct onyx {47 /* cache registers 65 to 80, they are write-only! */48 u8 cache[16];49 struct i2c_client *i2c;50 struct aoa_codec codec;51 u32 initialised:1,52 spdif_locked:1,53 analog_locked:1,54 original_mute:2;55 int open_count;56 struct codec_info *codec_info;57 58 /* mutex serializes concurrent access to the device59 * and this structure.60 */61 struct mutex mutex;62};63#define codec_to_onyx(c) container_of(c, struct onyx, codec)64 65/* both return 0 if all ok, else on error */66static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value)67{68 s32 v;69 70 if (reg != ONYX_REG_CONTROL) {71 *value = onyx->cache[reg-FIRSTREGISTER];72 return 0;73 }74 v = i2c_smbus_read_byte_data(onyx->i2c, reg);75 if (v < 0) {76 *value = 0;77 return -1;78 }79 *value = (u8)v;80 onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value;81 return 0;82}83 84static int onyx_write_register(struct onyx *onyx, u8 reg, u8 value)85{86 int result;87 88 result = i2c_smbus_write_byte_data(onyx->i2c, reg, value);89 if (!result)90 onyx->cache[reg-FIRSTREGISTER] = value;91 return result;92}93 94/* alsa stuff */95 96static int onyx_dev_register(struct snd_device *dev)97{98 return 0;99}100 101static const struct snd_device_ops ops = {102 .dev_register = onyx_dev_register,103};104 105/* this is necessary because most alsa mixer programs106 * can't properly handle the negative range */107#define VOLUME_RANGE_SHIFT 128108 109static int onyx_snd_vol_info(struct snd_kcontrol *kcontrol,110 struct snd_ctl_elem_info *uinfo)111{112 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;113 uinfo->count = 2;114 uinfo->value.integer.min = -128 + VOLUME_RANGE_SHIFT;115 uinfo->value.integer.max = -1 + VOLUME_RANGE_SHIFT;116 return 0;117}118 119static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol,120 struct snd_ctl_elem_value *ucontrol)121{122 struct onyx *onyx = snd_kcontrol_chip(kcontrol);123 s8 l, r;124 125 mutex_lock(&onyx->mutex);126 onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);127 onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);128 mutex_unlock(&onyx->mutex);129 130 ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;131 ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;132 133 return 0;134}135 136static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,137 struct snd_ctl_elem_value *ucontrol)138{139 struct onyx *onyx = snd_kcontrol_chip(kcontrol);140 s8 l, r;141 142 if (ucontrol->value.integer.value[0] < -128 + VOLUME_RANGE_SHIFT ||143 ucontrol->value.integer.value[0] > -1 + VOLUME_RANGE_SHIFT)144 return -EINVAL;145 if (ucontrol->value.integer.value[1] < -128 + VOLUME_RANGE_SHIFT ||146 ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT)147 return -EINVAL;148 149 mutex_lock(&onyx->mutex);150 onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);151 onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);152 153 if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&154 r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {155 mutex_unlock(&onyx->mutex);156 return 0;157 }158 159 onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,160 ucontrol->value.integer.value[0]161 - VOLUME_RANGE_SHIFT);162 onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,163 ucontrol->value.integer.value[1]164 - VOLUME_RANGE_SHIFT);165 mutex_unlock(&onyx->mutex);166 167 return 1;168}169 170static const struct snd_kcontrol_new volume_control = {171 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,172 .name = "Master Playback Volume",173 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,174 .info = onyx_snd_vol_info,175 .get = onyx_snd_vol_get,176 .put = onyx_snd_vol_put,177};178 179/* like above, this is necessary because a lot180 * of alsa mixer programs don't handle ranges181 * that don't start at 0 properly.182 * even alsamixer is one of them... */183#define INPUTGAIN_RANGE_SHIFT (-3)184 185static int onyx_snd_inputgain_info(struct snd_kcontrol *kcontrol,186 struct snd_ctl_elem_info *uinfo)187{188 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;189 uinfo->count = 1;190 uinfo->value.integer.min = 3 + INPUTGAIN_RANGE_SHIFT;191 uinfo->value.integer.max = 28 + INPUTGAIN_RANGE_SHIFT;192 return 0;193}194 195static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol,196 struct snd_ctl_elem_value *ucontrol)197{198 struct onyx *onyx = snd_kcontrol_chip(kcontrol);199 u8 ig;200 201 mutex_lock(&onyx->mutex);202 onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);203 mutex_unlock(&onyx->mutex);204 205 ucontrol->value.integer.value[0] =206 (ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;207 208 return 0;209}210 211static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol,212 struct snd_ctl_elem_value *ucontrol)213{214 struct onyx *onyx = snd_kcontrol_chip(kcontrol);215 u8 v, n;216 217 if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT ||218 ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT)219 return -EINVAL;220 mutex_lock(&onyx->mutex);221 onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);222 n = v;223 n &= ~ONYX_ADC_PGA_GAIN_MASK;224 n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)225 & ONYX_ADC_PGA_GAIN_MASK;226 onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);227 mutex_unlock(&onyx->mutex);228 229 return n != v;230}231 232static const struct snd_kcontrol_new inputgain_control = {233 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,234 .name = "Master Capture Volume",235 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,236 .info = onyx_snd_inputgain_info,237 .get = onyx_snd_inputgain_get,238 .put = onyx_snd_inputgain_put,239};240 241static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol,242 struct snd_ctl_elem_info *uinfo)243{244 static const char * const texts[] = { "Line-In", "Microphone" };245 246 return snd_ctl_enum_info(uinfo, 1, 2, texts);247}248 249static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,250 struct snd_ctl_elem_value *ucontrol)251{252 struct onyx *onyx = snd_kcontrol_chip(kcontrol);253 s8 v;254 255 mutex_lock(&onyx->mutex);256 onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);257 mutex_unlock(&onyx->mutex);258 259 ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);260 261 return 0;262}263 264static void onyx_set_capture_source(struct onyx *onyx, int mic)265{266 s8 v;267 268 mutex_lock(&onyx->mutex);269 onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);270 v &= ~ONYX_ADC_INPUT_MIC;271 if (mic)272 v |= ONYX_ADC_INPUT_MIC;273 onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);274 mutex_unlock(&onyx->mutex);275}276 277static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,278 struct snd_ctl_elem_value *ucontrol)279{280 if (ucontrol->value.enumerated.item[0] > 1)281 return -EINVAL;282 onyx_set_capture_source(snd_kcontrol_chip(kcontrol),283 ucontrol->value.enumerated.item[0]);284 return 1;285}286 287static const struct snd_kcontrol_new capture_source_control = {288 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,289 /* If we name this 'Input Source', it properly shows up in290 * alsamixer as a selection, * but it's shown under the291 * 'Playback' category.292 * If I name it 'Capture Source', it shows up in strange293 * ways (two bools of which one can be selected at a294 * time) but at least it's shown in the 'Capture'295 * category.296 * I was told that this was due to backward compatibility,297 * but I don't understand then why the mangling is *not*298 * done when I name it "Input Source".....299 */300 .name = "Capture Source",301 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,302 .info = onyx_snd_capture_source_info,303 .get = onyx_snd_capture_source_get,304 .put = onyx_snd_capture_source_put,305};306 307#define onyx_snd_mute_info snd_ctl_boolean_stereo_info308 309static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol,310 struct snd_ctl_elem_value *ucontrol)311{312 struct onyx *onyx = snd_kcontrol_chip(kcontrol);313 u8 c;314 315 mutex_lock(&onyx->mutex);316 onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);317 mutex_unlock(&onyx->mutex);318 319 ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);320 ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);321 322 return 0;323}324 325static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,326 struct snd_ctl_elem_value *ucontrol)327{328 struct onyx *onyx = snd_kcontrol_chip(kcontrol);329 u8 v = 0, c = 0;330 int err = -EBUSY;331 332 mutex_lock(&onyx->mutex);333 if (onyx->analog_locked)334 goto out_unlock;335 336 onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);337 c = v;338 c &= ~(ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT);339 if (!ucontrol->value.integer.value[0])340 c |= ONYX_MUTE_LEFT;341 if (!ucontrol->value.integer.value[1])342 c |= ONYX_MUTE_RIGHT;343 err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);344 345 out_unlock:346 mutex_unlock(&onyx->mutex);347 348 return !err ? (v != c) : err;349}350 351static const struct snd_kcontrol_new mute_control = {352 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,353 .name = "Master Playback Switch",354 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,355 .info = onyx_snd_mute_info,356 .get = onyx_snd_mute_get,357 .put = onyx_snd_mute_put,358};359 360 361#define onyx_snd_single_bit_info snd_ctl_boolean_mono_info362 363#define FLAG_POLARITY_INVERT 1364#define FLAG_SPDIFLOCK 2365 366static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol,367 struct snd_ctl_elem_value *ucontrol)368{369 struct onyx *onyx = snd_kcontrol_chip(kcontrol);370 u8 c;371 long int pv = kcontrol->private_value;372 u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT;373 u8 address = (pv >> 8) & 0xff;374 u8 mask = pv & 0xff;375 376 mutex_lock(&onyx->mutex);377 onyx_read_register(onyx, address, &c);378 mutex_unlock(&onyx->mutex);379 380 ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;381 382 return 0;383}384 385static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,386 struct snd_ctl_elem_value *ucontrol)387{388 struct onyx *onyx = snd_kcontrol_chip(kcontrol);389 u8 v = 0, c = 0;390 int err;391 long int pv = kcontrol->private_value;392 u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT;393 u8 spdiflock = (pv >> 16) & FLAG_SPDIFLOCK;394 u8 address = (pv >> 8) & 0xff;395 u8 mask = pv & 0xff;396 397 mutex_lock(&onyx->mutex);398 if (spdiflock && onyx->spdif_locked) {399 /* even if alsamixer doesn't care.. */400 err = -EBUSY;401 goto out_unlock;402 }403 onyx_read_register(onyx, address, &v);404 c = v;405 c &= ~(mask);406 if (!!ucontrol->value.integer.value[0] ^ polarity)407 c |= mask;408 err = onyx_write_register(onyx, address, c);409 410 out_unlock:411 mutex_unlock(&onyx->mutex);412 413 return !err ? (v != c) : err;414}415 416#define SINGLE_BIT(n, type, description, address, mask, flags) \417static const struct snd_kcontrol_new n##_control = { \418 .iface = SNDRV_CTL_ELEM_IFACE_##type, \419 .name = description, \420 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \421 .info = onyx_snd_single_bit_info, \422 .get = onyx_snd_single_bit_get, \423 .put = onyx_snd_single_bit_put, \424 .private_value = (flags << 16) | (address << 8) | mask \425}426 427SINGLE_BIT(spdif,428 MIXER,429 SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),430 ONYX_REG_DIG_INFO4,431 ONYX_SPDIF_ENABLE,432 FLAG_SPDIFLOCK);433SINGLE_BIT(ovr1,434 MIXER,435 "Oversampling Rate",436 ONYX_REG_DAC_CONTROL,437 ONYX_OVR1,438 0);439SINGLE_BIT(flt0,440 MIXER,441 "Fast Digital Filter Rolloff",442 ONYX_REG_DAC_FILTER,443 ONYX_ROLLOFF_FAST,444 FLAG_POLARITY_INVERT);445SINGLE_BIT(hpf,446 MIXER,447 "Highpass Filter",448 ONYX_REG_ADC_HPF_BYPASS,449 ONYX_HPF_DISABLE,450 FLAG_POLARITY_INVERT);451SINGLE_BIT(dm12,452 MIXER,453 "Digital De-Emphasis",454 ONYX_REG_DAC_DEEMPH,455 ONYX_DIGDEEMPH_CTRL,456 0);457 458static int onyx_spdif_info(struct snd_kcontrol *kcontrol,459 struct snd_ctl_elem_info *uinfo)460{461 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;462 uinfo->count = 1;463 return 0;464}465 466static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol,467 struct snd_ctl_elem_value *ucontrol)468{469 /* datasheet page 30, all others are 0 */470 ucontrol->value.iec958.status[0] = 0x3e;471 ucontrol->value.iec958.status[1] = 0xff;472 473 ucontrol->value.iec958.status[3] = 0x3f;474 ucontrol->value.iec958.status[4] = 0x0f;475 476 return 0;477}478 479static const struct snd_kcontrol_new onyx_spdif_mask = {480 .access = SNDRV_CTL_ELEM_ACCESS_READ,481 .iface = SNDRV_CTL_ELEM_IFACE_PCM,482 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),483 .info = onyx_spdif_info,484 .get = onyx_spdif_mask_get,485};486 487static int onyx_spdif_get(struct snd_kcontrol *kcontrol,488 struct snd_ctl_elem_value *ucontrol)489{490 struct onyx *onyx = snd_kcontrol_chip(kcontrol);491 u8 v;492 493 mutex_lock(&onyx->mutex);494 onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);495 ucontrol->value.iec958.status[0] = v & 0x3e;496 497 onyx_read_register(onyx, ONYX_REG_DIG_INFO2, &v);498 ucontrol->value.iec958.status[1] = v;499 500 onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v);501 ucontrol->value.iec958.status[3] = v & 0x3f;502 503 onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);504 ucontrol->value.iec958.status[4] = v & 0x0f;505 mutex_unlock(&onyx->mutex);506 507 return 0;508}509 510static int onyx_spdif_put(struct snd_kcontrol *kcontrol,511 struct snd_ctl_elem_value *ucontrol)512{513 struct onyx *onyx = snd_kcontrol_chip(kcontrol);514 u8 v;515 516 mutex_lock(&onyx->mutex);517 onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);518 v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);519 onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);520 521 v = ucontrol->value.iec958.status[1];522 onyx_write_register(onyx, ONYX_REG_DIG_INFO2, v);523 524 onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v);525 v = (v & ~0x3f) | (ucontrol->value.iec958.status[3] & 0x3f);526 onyx_write_register(onyx, ONYX_REG_DIG_INFO3, v);527 528 onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);529 v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);530 onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);531 mutex_unlock(&onyx->mutex);532 533 return 1;534}535 536static const struct snd_kcontrol_new onyx_spdif_ctrl = {537 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,538 .iface = SNDRV_CTL_ELEM_IFACE_PCM,539 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),540 .info = onyx_spdif_info,541 .get = onyx_spdif_get,542 .put = onyx_spdif_put,543};544 545/* our registers */546 547static const u8 register_map[] = {548 ONYX_REG_DAC_ATTEN_LEFT,549 ONYX_REG_DAC_ATTEN_RIGHT,550 ONYX_REG_CONTROL,551 ONYX_REG_DAC_CONTROL,552 ONYX_REG_DAC_DEEMPH,553 ONYX_REG_DAC_FILTER,554 ONYX_REG_DAC_OUTPHASE,555 ONYX_REG_ADC_CONTROL,556 ONYX_REG_ADC_HPF_BYPASS,557 ONYX_REG_DIG_INFO1,558 ONYX_REG_DIG_INFO2,559 ONYX_REG_DIG_INFO3,560 ONYX_REG_DIG_INFO4561};562 563static const u8 initial_values[ARRAY_SIZE(register_map)] = {564 0x80, 0x80, /* muted */565 ONYX_MRST | ONYX_SRST, /* but handled specially! */566 ONYX_MUTE_LEFT | ONYX_MUTE_RIGHT,567 0, /* no deemphasis */568 ONYX_DAC_FILTER_ALWAYS,569 ONYX_OUTPHASE_INVERTED,570 (-1 /*dB*/ + 8) & 0xF, /* line in selected, -1 dB gain*/571 ONYX_ADC_HPF_ALWAYS,572 (1<<2), /* pcm audio */573 2, /* category: pcm coder */574 0, /* sampling frequency 44.1 kHz, clock accuracy level II */575 1 /* 24 bit depth */576};577 578/* reset registers of chip, either to initial or to previous values */579static int onyx_register_init(struct onyx *onyx)580{581 int i;582 u8 val;583 u8 regs[sizeof(initial_values)];584 585 if (!onyx->initialised) {586 memcpy(regs, initial_values, sizeof(initial_values));587 if (onyx_read_register(onyx, ONYX_REG_CONTROL, &val))588 return -1;589 val &= ~ONYX_SILICONVERSION;590 val |= initial_values[3];591 regs[3] = val;592 } else {593 for (i=0; i<sizeof(register_map); i++)594 regs[i] = onyx->cache[register_map[i]-FIRSTREGISTER];595 }596 597 for (i=0; i<sizeof(register_map); i++) {598 if (onyx_write_register(onyx, register_map[i], regs[i]))599 return -1;600 }601 onyx->initialised = 1;602 return 0;603}604 605static struct transfer_info onyx_transfers[] = {606 /* this is first so we can skip it if no input is present...607 * No hardware exists with that, but it's here as an example608 * of what to do :) */609 {610 /* analog input */611 .formats = SNDRV_PCM_FMTBIT_S8 |612 SNDRV_PCM_FMTBIT_S16_BE |613 SNDRV_PCM_FMTBIT_S24_BE,614 .rates = SNDRV_PCM_RATE_8000_96000,615 .transfer_in = 1,616 .must_be_clock_source = 0,617 .tag = 0,618 },619 {620 /* if analog and digital are currently off, anything should go,621 * so this entry describes everything we can do... */622 .formats = SNDRV_PCM_FMTBIT_S8 |623 SNDRV_PCM_FMTBIT_S16_BE |624 SNDRV_PCM_FMTBIT_S24_BE625#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE626 | SNDRV_PCM_FMTBIT_COMPRESSED_16BE627#endif628 ,629 .rates = SNDRV_PCM_RATE_8000_96000,630 .tag = 0,631 },632 {633 /* analog output */634 .formats = SNDRV_PCM_FMTBIT_S8 |635 SNDRV_PCM_FMTBIT_S16_BE |636 SNDRV_PCM_FMTBIT_S24_BE,637 .rates = SNDRV_PCM_RATE_8000_96000,638 .transfer_in = 0,639 .must_be_clock_source = 0,640 .tag = 1,641 },642 {643 /* digital pcm output, also possible for analog out */644 .formats = SNDRV_PCM_FMTBIT_S8 |645 SNDRV_PCM_FMTBIT_S16_BE |646 SNDRV_PCM_FMTBIT_S24_BE,647 .rates = SNDRV_PCM_RATE_32000 |648 SNDRV_PCM_RATE_44100 |649 SNDRV_PCM_RATE_48000,650 .transfer_in = 0,651 .must_be_clock_source = 0,652 .tag = 2,653 },654#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE655 /* Once alsa gets supports for this kind of thing we can add it... */656 {657 /* digital compressed output */658 .formats = SNDRV_PCM_FMTBIT_COMPRESSED_16BE,659 .rates = SNDRV_PCM_RATE_32000 |660 SNDRV_PCM_RATE_44100 |661 SNDRV_PCM_RATE_48000,662 .tag = 2,663 },664#endif665 {}666};667 668static int onyx_usable(struct codec_info_item *cii,669 struct transfer_info *ti,670 struct transfer_info *out)671{672 u8 v;673 struct onyx *onyx = cii->codec_data;674 int spdif_enabled, analog_enabled;675 676 mutex_lock(&onyx->mutex);677 onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);678 spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);679 onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);680 analog_enabled =681 (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))682 != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);683 mutex_unlock(&onyx->mutex);684 685 switch (ti->tag) {686 case 0: return 1;687 case 1: return analog_enabled;688 case 2: return spdif_enabled;689 }690 return 1;691}692 693static int onyx_prepare(struct codec_info_item *cii,694 struct bus_info *bi,695 struct snd_pcm_substream *substream)696{697 u8 v;698 struct onyx *onyx = cii->codec_data;699 int err = -EBUSY;700 701 mutex_lock(&onyx->mutex);702 703#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE704 if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {705 /* mute and lock analog output */706 onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);707 if (onyx_write_register(onyx,708 ONYX_REG_DAC_CONTROL,709 v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))710 goto out_unlock;711 onyx->analog_locked = 1;712 err = 0;713 goto out_unlock;714 }715#endif716 switch (substream->runtime->rate) {717 case 32000:718 case 44100:719 case 48000:720 /* these rates are ok for all outputs */721 /* FIXME: program spdif channel control bits here so that722 * userspace doesn't have to if it only plays pcm! */723 err = 0;724 goto out_unlock;725 default:726 /* got some rate that the digital output can't do,727 * so disable and lock it */728 onyx_read_register(cii->codec_data, ONYX_REG_DIG_INFO4, &v);729 if (onyx_write_register(onyx,730 ONYX_REG_DIG_INFO4,731 v & ~ONYX_SPDIF_ENABLE))732 goto out_unlock;733 onyx->spdif_locked = 1;734 err = 0;735 goto out_unlock;736 }737 738 out_unlock:739 mutex_unlock(&onyx->mutex);740 741 return err;742}743 744static int onyx_open(struct codec_info_item *cii,745 struct snd_pcm_substream *substream)746{747 struct onyx *onyx = cii->codec_data;748 749 mutex_lock(&onyx->mutex);750 onyx->open_count++;751 mutex_unlock(&onyx->mutex);752 753 return 0;754}755 756static int onyx_close(struct codec_info_item *cii,757 struct snd_pcm_substream *substream)758{759 struct onyx *onyx = cii->codec_data;760 761 mutex_lock(&onyx->mutex);762 onyx->open_count--;763 if (!onyx->open_count)764 onyx->spdif_locked = onyx->analog_locked = 0;765 mutex_unlock(&onyx->mutex);766 767 return 0;768}769 770static int onyx_switch_clock(struct codec_info_item *cii,771 enum clock_switch what)772{773 struct onyx *onyx = cii->codec_data;774 775 mutex_lock(&onyx->mutex);776 /* this *MUST* be more elaborate later... */777 switch (what) {778 case CLOCK_SWITCH_PREPARE_SLAVE:779 onyx->codec.gpio->methods->all_amps_off(onyx->codec.gpio);780 break;781 case CLOCK_SWITCH_SLAVE:782 onyx->codec.gpio->methods->all_amps_restore(onyx->codec.gpio);783 break;784 default: /* silence warning */785 break;786 }787 mutex_unlock(&onyx->mutex);788 789 return 0;790}791 792#ifdef CONFIG_PM793 794static int onyx_suspend(struct codec_info_item *cii, pm_message_t state)795{796 struct onyx *onyx = cii->codec_data;797 u8 v;798 int err = -ENXIO;799 800 mutex_lock(&onyx->mutex);801 if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))802 goto out_unlock;803 onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);804 /* Apple does a sleep here but the datasheet says to do it on resume */805 err = 0;806 out_unlock:807 mutex_unlock(&onyx->mutex);808 809 return err;810}811 812static int onyx_resume(struct codec_info_item *cii)813{814 struct onyx *onyx = cii->codec_data;815 u8 v;816 int err = -ENXIO;817 818 mutex_lock(&onyx->mutex);819 820 /* reset codec */821 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);822 msleep(1);823 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);824 msleep(1);825 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);826 msleep(1);827 828 /* take codec out of suspend (if it still is after reset) */829 if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))830 goto out_unlock;831 onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));832 /* FIXME: should divide by sample rate, but 8k is the lowest we go */833 msleep(2205000/8000);834 /* reset all values */835 onyx_register_init(onyx);836 err = 0;837 out_unlock:838 mutex_unlock(&onyx->mutex);839 840 return err;841}842 843#endif /* CONFIG_PM */844 845static struct codec_info onyx_codec_info = {846 .transfers = onyx_transfers,847 .sysclock_factor = 256,848 .bus_factor = 64,849 .owner = THIS_MODULE,850 .usable = onyx_usable,851 .prepare = onyx_prepare,852 .open = onyx_open,853 .close = onyx_close,854 .switch_clock = onyx_switch_clock,855#ifdef CONFIG_PM856 .suspend = onyx_suspend,857 .resume = onyx_resume,858#endif859};860 861static int onyx_init_codec(struct aoa_codec *codec)862{863 struct onyx *onyx = codec_to_onyx(codec);864 struct snd_kcontrol *ctl;865 struct codec_info *ci = &onyx_codec_info;866 u8 v;867 int err;868 869 if (!onyx->codec.gpio || !onyx->codec.gpio->methods) {870 printk(KERN_ERR PFX "gpios not assigned!!\n");871 return -EINVAL;872 }873 874 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);875 msleep(1);876 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);877 msleep(1);878 onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);879 msleep(1);880 881 if (onyx_register_init(onyx)) {882 printk(KERN_ERR PFX "failed to initialise onyx registers\n");883 return -ENODEV;884 }885 886 if (aoa_snd_device_new(SNDRV_DEV_CODEC, onyx, &ops)) {887 printk(KERN_ERR PFX "failed to create onyx snd device!\n");888 return -ENODEV;889 }890 891 /* nothing connected? what a joke! */892 if ((onyx->codec.connected & 0xF) == 0)893 return -ENOTCONN;894 895 /* if no inputs are present... */896 if ((onyx->codec.connected & 0xC) == 0) {897 if (!onyx->codec_info)898 onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL);899 if (!onyx->codec_info)900 return -ENOMEM;901 ci = onyx->codec_info;902 *ci = onyx_codec_info;903 ci->transfers++;904 }905 906 /* if no outputs are present... */907 if ((onyx->codec.connected & 3) == 0) {908 if (!onyx->codec_info)909 onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL);910 if (!onyx->codec_info)911 return -ENOMEM;912 ci = onyx->codec_info;913 /* this is fine as there have to be inputs914 * if we end up in this part of the code */915 *ci = onyx_codec_info;916 ci->transfers[1].formats = 0;917 }918 919 if (onyx->codec.soundbus_dev->attach_codec(onyx->codec.soundbus_dev,920 aoa_get_card(),921 ci, onyx)) {922 printk(KERN_ERR PFX "error creating onyx pcm\n");923 return -ENODEV;924 }925#define ADDCTL(n) \926 do { \927 ctl = snd_ctl_new1(&n, onyx); \928 if (ctl) { \929 ctl->id.device = \930 onyx->codec.soundbus_dev->pcm->device; \931 err = aoa_snd_ctl_add(ctl); \932 if (err) \933 goto error; \934 } \935 } while (0)936 937 if (onyx->codec.soundbus_dev->pcm) {938 /* give the user appropriate controls939 * depending on what inputs are connected */940 if ((onyx->codec.connected & 0xC) == 0xC)941 ADDCTL(capture_source_control);942 else if (onyx->codec.connected & 4)943 onyx_set_capture_source(onyx, 0);944 else945 onyx_set_capture_source(onyx, 1);946 if (onyx->codec.connected & 0xC)947 ADDCTL(inputgain_control);948 949 /* depending on what output is connected,950 * give the user appropriate controls */951 if (onyx->codec.connected & 1) {952 ADDCTL(volume_control);953 ADDCTL(mute_control);954 ADDCTL(ovr1_control);955 ADDCTL(flt0_control);956 ADDCTL(hpf_control);957 ADDCTL(dm12_control);958 /* spdif control defaults to off */959 }960 if (onyx->codec.connected & 2) {961 ADDCTL(onyx_spdif_mask);962 ADDCTL(onyx_spdif_ctrl);963 }964 if ((onyx->codec.connected & 3) == 3)965 ADDCTL(spdif_control);966 /* if only S/PDIF is connected, enable it unconditionally */967 if ((onyx->codec.connected & 3) == 2) {968 onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);969 v |= ONYX_SPDIF_ENABLE;970 onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);971 }972 }973#undef ADDCTL974 printk(KERN_INFO PFX "attached to onyx codec via i2c\n");975 976 return 0;977 error:978 onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);979 snd_device_free(aoa_get_card(), onyx);980 return err;981}982 983static void onyx_exit_codec(struct aoa_codec *codec)984{985 struct onyx *onyx = codec_to_onyx(codec);986 987 if (!onyx->codec.soundbus_dev) {988 printk(KERN_ERR PFX "onyx_exit_codec called without soundbus_dev!\n");989 return;990 }991 onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);992}993 994static int onyx_i2c_probe(struct i2c_client *client)995{996 struct device_node *node = client->dev.of_node;997 struct onyx *onyx;998 u8 dummy;999 1000 onyx = kzalloc(sizeof(struct onyx), GFP_KERNEL);1001 1002 if (!onyx)1003 return -ENOMEM;1004 1005 mutex_init(&onyx->mutex);1006 onyx->i2c = client;1007 i2c_set_clientdata(client, onyx);1008 1009 /* we try to read from register ONYX_REG_CONTROL1010 * to check if the codec is present */1011 if (onyx_read_register(onyx, ONYX_REG_CONTROL, &dummy) != 0) {1012 printk(KERN_ERR PFX "failed to read control register\n");1013 goto fail;1014 }1015 1016 strscpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN);1017 onyx->codec.owner = THIS_MODULE;1018 onyx->codec.init = onyx_init_codec;1019 onyx->codec.exit = onyx_exit_codec;1020 onyx->codec.node = of_node_get(node);1021 1022 if (aoa_codec_register(&onyx->codec)) {1023 goto fail;1024 }1025 printk(KERN_DEBUG PFX "created and attached onyx instance\n");1026 return 0;1027 fail:1028 kfree(onyx);1029 return -ENODEV;1030}1031 1032static void onyx_i2c_remove(struct i2c_client *client)1033{1034 struct onyx *onyx = i2c_get_clientdata(client);1035 1036 aoa_codec_unregister(&onyx->codec);1037 of_node_put(onyx->codec.node);1038 kfree(onyx->codec_info);1039 kfree(onyx);1040}1041 1042static const struct i2c_device_id onyx_i2c_id[] = {1043 { "MAC,pcm3052" },1044 { }1045};1046MODULE_DEVICE_TABLE(i2c,onyx_i2c_id);1047 1048static struct i2c_driver onyx_driver = {1049 .driver = {1050 .name = "aoa_codec_onyx",1051 },1052 .probe = onyx_i2c_probe,1053 .remove = onyx_i2c_remove,1054 .id_table = onyx_i2c_id,1055};1056 1057module_i2c_driver(onyx_driver);1058