brintos

brintos / linux-shallow public Read only

0
0
Text · 13.7 KiB · 0818e42 Raw
448 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *   ALSA driver for ICEnsemble VT1724 (Envy24HT)4 *5 *   Lowlevel functions for Philips PSC724 Ultimate Edge6 *7 *	Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org>8 */9 10#include <linux/delay.h>11#include <linux/init.h>12#include <linux/slab.h>13#include <sound/core.h>14 15#include "ice1712.h"16#include "envy24ht.h"17#include "psc724.h"18#include "wm8766.h"19#include "wm8776.h"20 21struct psc724_spec {22	struct snd_wm8766 wm8766;23	struct snd_wm8776 wm8776;24	bool mute_all, jack_detect;25	struct snd_ice1712 *ice;26	struct delayed_work hp_work;27	bool hp_connected;28};29 30/****************************************************************************/31/*  PHILIPS PSC724 ULTIMATE EDGE                                            */32/****************************************************************************/33/*34 *  VT1722 (Envy24GT) - 6 outputs, 4 inputs (only 2 used), 24-bit/96kHz35 *36 *  system configuration ICE_EEP2_SYSCONF=0x4237 *    XIN1 49.152MHz38 *    no MPU40139 *    one stereo ADC, no S/PDIF receiver40 *    three stereo DACs (FRONT, REAR, CENTER+LFE)41 *42 *  AC-Link configuration ICE_EEP2_ACLINK=0x8043 *    use I2S, not AC9744 *45 *  I2S converters feature ICE_EEP2_I2S=0x3046 *    I2S codec has no volume/mute control feature (bug!)47 *    I2S codec does not support 96KHz or 192KHz (bug!)48 *    I2S codec 24bits49 *50 *  S/PDIF configuration ICE_EEP2_SPDIF=0xc151 *    Enable integrated S/PDIF transmitter52 *    internal S/PDIF out implemented53 *    No S/PDIF input54 *    External S/PDIF out implemented55 *56 *57 * ** connected chips **58 *59 *  WM877660 *     2-channel DAC used for main output and stereo ADC (with 10-channel MUX)61 *     AIN1: LINE IN, AIN2: CD/VIDEO, AIN3: AUX, AIN4: Front MIC, AIN5: Rear MIC62 *     Controlled by I2C using VT1722 I2C interface:63 *          MODE (pin16) -- GND64 *          CE   (pin17) -- GND  I2C mode (address=0x34)65 *          DI   (pin18) -- SDA  (VT1722 pin70)66 *          CL   (pin19) -- SCLK (VT1722 pin71)67 *68 *  WM876669 *      6-channel DAC used for rear & center/LFE outputs (only 4 channels used)70 *      Controlled by SPI using VT1722 GPIO pins:71 *          MODE   (pin 1) -- GPIO19 (VT1722 pin99)72 *          ML/I2S (pin11) -- GPIO18 (VT1722 pin98)73 *          MC/IWL (pin12) -- GPIO17 (VT1722 pin97)74 *          MD/DM  (pin13) -- GPIO16 (VT1722 pin96)75 *          MUTE   (pin14) -- GPIO20 (VT1722 pin101)76 *77 *  GPIO14 is used as input for headphone jack detection (1 = connected)78 *  GPIO22 is used as MUTE ALL output, grounding all 6 channels79 *80 * ** output pins and device names **81 *82 *   5.1ch name -- output connector color -- device (-D option)83 *84 *      FRONT 2ch                  -- green  -- plughw:0,085 *      CENTER(Lch) SUBWOOFER(Rch) -- orange -- plughw:0,2,086 *      REAR 2ch                   -- black  -- plughw:0,2,187 */88 89/* codec access low-level functions */90 91#define GPIO_HP_JACK	(1 << 14)92#define GPIO_MUTE_SUR	(1 << 20)93#define GPIO_MUTE_ALL	(1 << 22)94 95#define JACK_INTERVAL	100096 97#define PSC724_SPI_DELAY 198 99#define PSC724_SPI_DATA	(1 << 16)100#define PSC724_SPI_CLK	(1 << 17)101#define PSC724_SPI_LOAD	(1 << 18)102#define PSC724_SPI_MASK	(PSC724_SPI_DATA | PSC724_SPI_CLK | PSC724_SPI_LOAD)103 104static void psc724_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data)105{106	struct psc724_spec *spec = container_of(wm, struct psc724_spec, wm8766);107	struct snd_ice1712 *ice = spec->ice;108	u32 st, bits;109	int i;110 111	snd_ice1712_save_gpio_status(ice);112 113	st = ((addr & 0x7f) << 9) | (data & 0x1ff);114	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | PSC724_SPI_MASK);115	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~PSC724_SPI_MASK);116	bits = snd_ice1712_gpio_read(ice) & ~PSC724_SPI_MASK;117	snd_ice1712_gpio_write(ice, bits);118 119	for (i = 0; i < 16; i++) {120		udelay(PSC724_SPI_DELAY);121		bits &= ~PSC724_SPI_CLK;122		/* MSB first */123		st <<= 1;124		if (st & 0x10000)125			bits |= PSC724_SPI_DATA;126		else127			bits &= ~PSC724_SPI_DATA;128		snd_ice1712_gpio_write(ice, bits);129		/* CLOCK high */130		udelay(PSC724_SPI_DELAY);131		bits |= PSC724_SPI_CLK;132		snd_ice1712_gpio_write(ice, bits);133	}134	/* LOAD high */135	udelay(PSC724_SPI_DELAY);136	bits |= PSC724_SPI_LOAD;137	snd_ice1712_gpio_write(ice, bits);138	/* LOAD low, DATA and CLOCK high */139	udelay(PSC724_SPI_DELAY);140	bits |= (PSC724_SPI_DATA | PSC724_SPI_CLK);141	snd_ice1712_gpio_write(ice, bits);142 143	snd_ice1712_restore_gpio_status(ice);144}145 146static void psc724_wm8776_write(struct snd_wm8776 *wm, u8 addr, u8 data)147{148	struct psc724_spec *spec = container_of(wm, struct psc724_spec, wm8776);149 150	snd_vt1724_write_i2c(spec->ice, 0x34, addr, data);151}152 153/* mute all */154 155static void psc724_set_master_switch(struct snd_ice1712 *ice, bool on)156{157	unsigned int bits = snd_ice1712_gpio_read(ice);158	struct psc724_spec *spec = ice->spec;159 160	spec->mute_all = !on;161	if (on)162		bits &= ~(GPIO_MUTE_ALL | GPIO_MUTE_SUR);163	else164		bits |= GPIO_MUTE_ALL | GPIO_MUTE_SUR;165	snd_ice1712_gpio_write(ice, bits);166}167 168static bool psc724_get_master_switch(struct snd_ice1712 *ice)169{170	struct psc724_spec *spec = ice->spec;171 172	return !spec->mute_all;173}174 175/* jack detection */176 177static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected)178{179	struct psc724_spec *spec = ice->spec;180	struct snd_kcontrol *kctl;181	u16 power = spec->wm8776.regs[WM8776_REG_PWRDOWN] & ~WM8776_PWR_HPPD;182 183	psc724_set_master_switch(ice, !hp_connected);184	if (!hp_connected)185		power |= WM8776_PWR_HPPD;186	snd_wm8776_set_power(&spec->wm8776, power);187	spec->hp_connected = hp_connected;188	/* notify about master speaker mute change */189	kctl = snd_ctl_find_id_mixer(ice->card,190				     "Master Speakers Playback Switch");191	if (kctl)192		snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);193	/* and headphone mute change */194	kctl = snd_ctl_find_id_mixer(ice->card,195				     spec->wm8776.ctl[WM8776_CTL_HP_SW].name);196	if (kctl)197		snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);198}199 200static void psc724_update_hp_jack_state(struct work_struct *work)201{202	struct psc724_spec *spec = container_of(work, struct psc724_spec,203						hp_work.work);204	struct snd_ice1712 *ice = spec->ice;205	bool hp_connected = snd_ice1712_gpio_read(ice) & GPIO_HP_JACK;206 207	schedule_delayed_work(&spec->hp_work, msecs_to_jiffies(JACK_INTERVAL));208	if (hp_connected == spec->hp_connected)209		return;210	psc724_set_jack_state(ice, hp_connected);211}212 213static void psc724_set_jack_detection(struct snd_ice1712 *ice, bool on)214{215	struct psc724_spec *spec = ice->spec;216 217	if (spec->jack_detect == on)218		return;219 220	spec->jack_detect = on;221	if (on) {222		bool hp_connected = snd_ice1712_gpio_read(ice) & GPIO_HP_JACK;223		psc724_set_jack_state(ice, hp_connected);224		schedule_delayed_work(&spec->hp_work,225					msecs_to_jiffies(JACK_INTERVAL));226	} else227		cancel_delayed_work_sync(&spec->hp_work);228}229 230static bool psc724_get_jack_detection(struct snd_ice1712 *ice)231{232	struct psc724_spec *spec = ice->spec;233 234	return spec->jack_detect;235}236 237/* mixer controls */238 239struct psc724_control {240	const char *name;241	void (*set)(struct snd_ice1712 *ice, bool on);242	bool (*get)(struct snd_ice1712 *ice);243};244 245static const struct psc724_control psc724_cont[] = {246	{247		.name = "Master Speakers Playback Switch",248		.set = psc724_set_master_switch,249		.get = psc724_get_master_switch,250	},251	{252		.name = "Headphone Jack Detection Playback Switch",253		.set = psc724_set_jack_detection,254		.get = psc724_get_jack_detection,255	},256};257 258static int psc724_ctl_get(struct snd_kcontrol *kcontrol,259				  struct snd_ctl_elem_value *ucontrol)260{261	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);262	int n = kcontrol->private_value;263 264	ucontrol->value.integer.value[0] = psc724_cont[n].get(ice);265 266	return 0;267}268 269static int psc724_ctl_put(struct snd_kcontrol *kcontrol,270				  struct snd_ctl_elem_value *ucontrol)271{272	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);273	int n = kcontrol->private_value;274 275	psc724_cont[n].set(ice, ucontrol->value.integer.value[0]);276 277	return 0;278}279 280static const char *front_volume	= "Front Playback Volume";281static const char *front_switch	= "Front Playback Switch";282static const char *front_zc	= "Front Zero Cross Detect Playback Switch";283static const char *front_izd	= "Front Infinite Zero Detect Playback Switch";284static const char *front_phase	= "Front Phase Invert Playback Switch";285static const char *front_deemph	= "Front Deemphasis Playback Switch";286static const char *ain1_switch	= "Line Capture Switch";287static const char *ain2_switch	= "CD Capture Switch";288static const char *ain3_switch	= "AUX Capture Switch";289static const char *ain4_switch	= "Front Mic Capture Switch";290static const char *ain5_switch	= "Rear Mic Capture Switch";291static const char *rear_volume	= "Surround Playback Volume";292static const char *clfe_volume	= "CLFE Playback Volume";293static const char *rear_switch	= "Surround Playback Switch";294static const char *clfe_switch	= "CLFE Playback Switch";295static const char *rear_phase	= "Surround Phase Invert Playback Switch";296static const char *clfe_phase	= "CLFE Phase Invert Playback Switch";297static const char *rear_deemph	= "Surround Deemphasis Playback Switch";298static const char *clfe_deemph	= "CLFE Deemphasis Playback Switch";299static const char *rear_clfe_izd = "Rear Infinite Zero Detect Playback Switch";300static const char *rear_clfe_zc	= "Rear Zero Cross Detect Playback Switch";301 302static int psc724_add_controls(struct snd_ice1712 *ice)303{304	struct snd_kcontrol_new cont;305	struct snd_kcontrol *ctl;306	int err, i;307	struct psc724_spec *spec = ice->spec;308 309	spec->wm8776.ctl[WM8776_CTL_DAC_VOL].name = front_volume;310	spec->wm8776.ctl[WM8776_CTL_DAC_SW].name = front_switch;311	spec->wm8776.ctl[WM8776_CTL_DAC_ZC_SW].name = front_zc;312	spec->wm8776.ctl[WM8776_CTL_AUX_SW].name = NULL;313	spec->wm8776.ctl[WM8776_CTL_DAC_IZD_SW].name = front_izd;314	spec->wm8776.ctl[WM8776_CTL_PHASE_SW].name = front_phase;315	spec->wm8776.ctl[WM8776_CTL_DEEMPH_SW].name = front_deemph;316	spec->wm8776.ctl[WM8776_CTL_INPUT1_SW].name = ain1_switch;317	spec->wm8776.ctl[WM8776_CTL_INPUT2_SW].name = ain2_switch;318	spec->wm8776.ctl[WM8776_CTL_INPUT3_SW].name = ain3_switch;319	spec->wm8776.ctl[WM8776_CTL_INPUT4_SW].name = ain4_switch;320	spec->wm8776.ctl[WM8776_CTL_INPUT5_SW].name = ain5_switch;321	snd_wm8776_build_controls(&spec->wm8776);322	spec->wm8766.ctl[WM8766_CTL_CH1_VOL].name = rear_volume;323	spec->wm8766.ctl[WM8766_CTL_CH2_VOL].name = clfe_volume;324	spec->wm8766.ctl[WM8766_CTL_CH3_VOL].name = NULL;325	spec->wm8766.ctl[WM8766_CTL_CH1_SW].name = rear_switch;326	spec->wm8766.ctl[WM8766_CTL_CH2_SW].name = clfe_switch;327	spec->wm8766.ctl[WM8766_CTL_CH3_SW].name = NULL;328	spec->wm8766.ctl[WM8766_CTL_PHASE1_SW].name = rear_phase;329	spec->wm8766.ctl[WM8766_CTL_PHASE2_SW].name = clfe_phase;330	spec->wm8766.ctl[WM8766_CTL_PHASE3_SW].name = NULL;331	spec->wm8766.ctl[WM8766_CTL_DEEMPH1_SW].name = rear_deemph;332	spec->wm8766.ctl[WM8766_CTL_DEEMPH2_SW].name = clfe_deemph;333	spec->wm8766.ctl[WM8766_CTL_DEEMPH3_SW].name = NULL;334	spec->wm8766.ctl[WM8766_CTL_IZD_SW].name = rear_clfe_izd;335	spec->wm8766.ctl[WM8766_CTL_ZC_SW].name = rear_clfe_zc;336	snd_wm8766_build_controls(&spec->wm8766);337 338	memset(&cont, 0, sizeof(cont));339	cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER;340	for (i = 0; i < ARRAY_SIZE(psc724_cont); i++) {341		cont.private_value = i;342		cont.name = psc724_cont[i].name;343		cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;344		cont.info = snd_ctl_boolean_mono_info;345		cont.get = psc724_ctl_get;346		cont.put = psc724_ctl_put;347		ctl = snd_ctl_new1(&cont, ice);348		if (!ctl)349			return -ENOMEM;350		err = snd_ctl_add(ice->card, ctl);351		if (err < 0)352			return err;353	}354 355	return 0;356}357 358static void psc724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate)359{360	struct psc724_spec *spec = ice->spec;361	/* restore codec volume settings after rate change (PMCLK stop) */362	snd_wm8776_volume_restore(&spec->wm8776);363	snd_wm8766_volume_restore(&spec->wm8766);364}365 366/* power management */367 368#ifdef CONFIG_PM_SLEEP369static int psc724_resume(struct snd_ice1712 *ice)370{371	struct psc724_spec *spec = ice->spec;372 373	snd_wm8776_resume(&spec->wm8776);374	snd_wm8766_resume(&spec->wm8766);375 376	return 0;377}378#endif379 380/* init */381 382static int psc724_init(struct snd_ice1712 *ice)383{384	struct psc724_spec *spec;385 386	spec = kzalloc(sizeof(*spec), GFP_KERNEL);387	if (!spec)388		return -ENOMEM;389	ice->spec = spec;390	spec->ice = ice;391 392	ice->num_total_dacs = 6;393	ice->num_total_adcs = 2;394	spec->wm8776.ops.write = psc724_wm8776_write;395	spec->wm8776.card = ice->card;396	snd_wm8776_init(&spec->wm8776);397	spec->wm8766.ops.write = psc724_wm8766_write;398	spec->wm8766.card = ice->card;399#ifdef CONFIG_PM_SLEEP400	ice->pm_resume = psc724_resume;401	ice->pm_suspend_enabled = 1;402#endif403	snd_wm8766_init(&spec->wm8766);404	snd_wm8766_set_if(&spec->wm8766,405			WM8766_IF_FMT_I2S | WM8766_IF_IWL_24BIT);406	ice->gpio.set_pro_rate = psc724_set_pro_rate;407	INIT_DELAYED_WORK(&spec->hp_work, psc724_update_hp_jack_state);408	psc724_set_jack_detection(ice, true);409	return 0;410}411 412static void psc724_exit(struct snd_ice1712 *ice)413{414	struct psc724_spec *spec = ice->spec;415 416	cancel_delayed_work_sync(&spec->hp_work);417}418 419/* PSC724 has buggy EEPROM (no 96&192kHz, all FFh GPIOs), so override it here */420static const unsigned char psc724_eeprom[] = {421	[ICE_EEP2_SYSCONF]	= 0x42,	/* 49.152MHz, 1 ADC, 3 DACs */422	[ICE_EEP2_ACLINK]	= 0x80,	/* I2S */423	[ICE_EEP2_I2S]		= 0xf0,	/* I2S volume, 96kHz, 24bit */424	[ICE_EEP2_SPDIF]	= 0xc1,	/* spdif out-en, out-int, no input */425	/* GPIO outputs */426	[ICE_EEP2_GPIO_DIR2]	= 0x5f, /* MUTE_ALL,WM8766 MUTE/MODE/ML/MC/MD */427	/* GPIO write enable */428	[ICE_EEP2_GPIO_MASK]	= 0xff, /* read-only */429	[ICE_EEP2_GPIO_MASK1]	= 0xff, /* read-only */430	[ICE_EEP2_GPIO_MASK2]	= 0xa0, /* MUTE_ALL,WM8766 MUTE/MODE/ML/MC/MD */431	/* GPIO initial state */432	[ICE_EEP2_GPIO_STATE2]	= 0x20,	/* unmuted, all WM8766 pins low */433};434 435struct snd_ice1712_card_info snd_vt1724_psc724_cards[] = {436	{437		.subvendor = VT1724_SUBDEVICE_PSC724,438		.name = "Philips PSC724 Ultimate Edge",439		.model = "psc724",440		.chip_init = psc724_init,441		.chip_exit = psc724_exit,442		.build_controls = psc724_add_controls,443		.eeprom_size = sizeof(psc724_eeprom),444		.eeprom_data = psc724_eeprom,445	},446	{} /*terminator*/447};448