brintos

brintos / linux-shallow public Read only

0
0
Text · 27.2 KiB · ac347a1 Raw
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