wm_hubs.c 41.0 KB
Newer Older
1 2 3
/*
 * wm_hubs.c  --  WM8993/4 common code
 *
4
 * Copyright 2009-12 Wolfson Microelectronics plc
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
20
#include <linux/mfd/wm8994/registers.h>
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>

#include "wm8993.h"
#include "wm_hubs.h"

const DECLARE_TLV_DB_SCALE(wm_hubs_spkmix_tlv, -300, 300, 0);
EXPORT_SYMBOL_GPL(wm_hubs_spkmix_tlv);

static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0);
static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0);
static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1);
static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
static const unsigned int spkboost_tlv[] = {
C
Clemens Ladisch 已提交
42
	TLV_DB_RANGE_HEAD(2),
43 44 45 46 47 48 49 50 51 52
	0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
	7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
};
static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);

static const char *speaker_ref_text[] = {
	"SPKVDD/2",
	"VMID",
};

53 54
static SOC_ENUM_SINGLE_DECL(speaker_ref,
			    WM8993_SPEAKER_MIXER, 8, speaker_ref_text);
55 56 57 58 59 60

static const char *speaker_mode_text[] = {
	"Class D",
	"Class AB",
};

61 62
static SOC_ENUM_SINGLE_DECL(speaker_mode,
			    WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);
63

64
static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
65
{
66
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
67 68
	unsigned int reg;
	int count = 0;
69
	int timeout;
70 71 72 73 74 75
	unsigned int val;

	val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;

	/* Trigger the command */
	snd_soc_write(codec, WM8993_DC_SERVO_0, val);
76 77

	dev_dbg(codec->dev, "Waiting for DC servo...\n");
78

79 80 81 82
	if (hubs->dcs_done_irq)
		timeout = 4;
	else
		timeout = 400;
83

84 85 86 87 88 89 90
	do {
		count++;

		if (hubs->dcs_done_irq)
			wait_for_completion_timeout(&hubs->dcs_done,
						    msecs_to_jiffies(250));
		else
91
			msleep(1);
92 93 94 95

		reg = snd_soc_read(codec, WM8993_DC_SERVO_0);
		dev_dbg(codec->dev, "DC servo: %x\n", reg);
	} while (reg & op && count < timeout);
96

97
	if (reg & op)
98 99
		dev_err(codec->dev, "Timed out waiting for DC Servo %x\n",
			op);
100 101
}

102 103 104 105 106 107 108 109 110 111
irqreturn_t wm_hubs_dcs_done(int irq, void *data)
{
	struct wm_hubs_data *hubs = data;

	complete(&hubs->dcs_done);

	return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
static bool wm_hubs_dac_hp_direct(struct snd_soc_codec *codec)
{
	int reg;

	/* If we're going via the mixer we'll need to do additional checks */
	reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER1);
	if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
		if (reg & ~WM8993_DACL_TO_MIXOUTL) {
			dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
				 reg & ~WM8993_DACL_TO_HPOUT1L);
			return false;
		} else {
			dev_vdbg(codec->dev, "HPL connected to mixer\n");
		}
	} else {
		dev_vdbg(codec->dev, "HPL connected to DAC\n");
	}

	reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER2);
	if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
		if (reg & ~WM8993_DACR_TO_MIXOUTR) {
			dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
				 reg & ~WM8993_DACR_TO_HPOUT1R);
			return false;
		} else {
			dev_vdbg(codec->dev, "HPR connected to mixer\n");
		}
	} else {
		dev_vdbg(codec->dev, "HPR connected to DAC\n");
	}

	return true;
}

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
struct wm_hubs_dcs_cache {
	struct list_head list;
	unsigned int left;
	unsigned int right;
	u16 dcs_cfg;
};

static bool wm_hubs_dcs_cache_get(struct snd_soc_codec *codec,
				  struct wm_hubs_dcs_cache **entry)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
	struct wm_hubs_dcs_cache *cache;
	unsigned int left, right;

	left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
	left &= WM8993_HPOUT1L_VOL_MASK;

	right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
	right &= WM8993_HPOUT1R_VOL_MASK;

	list_for_each_entry(cache, &hubs->dcs_cache, list) {
		if (cache->left != left || cache->right != right)
			continue;

		*entry = cache;
		return true;
	}

	return false;
}

static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
	struct wm_hubs_dcs_cache *cache;

	if (hubs->no_cache_dac_hp_direct)
		return;

	cache = devm_kzalloc(codec->dev, sizeof(*cache), GFP_KERNEL);
186
	if (!cache)
187 188 189 190 191 192 193 194 195 196 197 198 199
		return;

	cache->left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
	cache->left &= WM8993_HPOUT1L_VOL_MASK;

	cache->right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
	cache->right &= WM8993_HPOUT1R_VOL_MASK;

	cache->dcs_cfg = dcs_cfg;

	list_add_tail(&cache->list, &hubs->dcs_cache);
}

200
static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
201 202 203 204
				  u16 *reg_l, u16 *reg_r)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
	u16 dcs_reg, reg;
205
	int ret = 0;
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237

	switch (hubs->dcs_readback_mode) {
	case 2:
		dcs_reg = WM8994_DC_SERVO_4E;
		break;
	case 1:
		dcs_reg = WM8994_DC_SERVO_READBACK;
		break;
	default:
		dcs_reg = WM8993_DC_SERVO_3;
		break;
	}

	/* Different chips in the family support different readback
	 * methods.
	 */
	switch (hubs->dcs_readback_mode) {
	case 0:
		*reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
			& WM8993_DCS_INTEG_CHAN_0_MASK;
		*reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
			& WM8993_DCS_INTEG_CHAN_1_MASK;
		break;
	case 2:
	case 1:
		reg = snd_soc_read(codec, dcs_reg);
		*reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
		*reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
		break;
	default:
		WARN(1, "Unknown DCS readback method\n");
238
		ret = -1;
239
	}
240
	return ret;
241 242
}

243 244 245
/*
 * Startup calibration of the DC servo
 */
246
static void enable_dc_servo(struct snd_soc_codec *codec)
247
{
248
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
249
	struct wm_hubs_dcs_cache *cache;
250
	s8 offset;
251
	u16 reg_l, reg_r, dcs_cfg, dcs_reg;
252 253 254 255 256 257 258 259 260

	switch (hubs->dcs_readback_mode) {
	case 2:
		dcs_reg = WM8994_DC_SERVO_4E;
		break;
	default:
		dcs_reg = WM8993_DC_SERVO_3;
		break;
	}
261

262 263
	/* If we're using a digital only path and have a previously
	 * callibrated DC servo offset stored then use that. */
264 265 266 267 268
	if (wm_hubs_dac_hp_direct(codec) &&
	    wm_hubs_dcs_cache_get(codec, &cache)) {
		dev_dbg(codec->dev, "Using cached DCS offset %x for %d,%d\n",
			cache->dcs_cfg, cache->left, cache->right);
		snd_soc_write(codec, dcs_reg, cache->dcs_cfg);
269 270 271 272 273 274
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_DAC_WR_0 |
				  WM8993_DCS_TRIG_DAC_WR_1);
		return;
	}

275
	if (hubs->series_startup) {
276 277 278 279 280 281 282 283 284 285 286 287
		/* Set for 32 series updates */
		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
				    WM8993_DCS_SERIES_NO_01_MASK,
				    32 << WM8993_DCS_SERIES_NO_01_SHIFT);
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_SERIES_0 |
				  WM8993_DCS_TRIG_SERIES_1);
	} else {
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_STARTUP_0 |
				  WM8993_DCS_TRIG_STARTUP_1);
	}
288

289 290
	if (wm_hubs_read_dc_servo(codec, &reg_l, &reg_r) < 0)
		return;
291 292 293

	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);

294
	/* Apply correction to DC servo result */
295 296 297 298
	if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
		dev_dbg(codec->dev,
			"Applying %d/%d code DC servo correction\n",
			hubs->dcs_codes_l, hubs->dcs_codes_r);
299

300
		/* HPOUT1R */
301
		offset = (s8)reg_r;
302 303
		dev_dbg(codec->dev, "DCS right %d->%d\n", offset,
			offset + hubs->dcs_codes_r);
304
		offset += hubs->dcs_codes_r;
305
		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
306

307
		/* HPOUT1L */
308
		offset = (s8)reg_l;
309 310
		dev_dbg(codec->dev, "DCS left %d->%d\n", offset,
			offset + hubs->dcs_codes_l);
311
		offset += hubs->dcs_codes_l;
312
		dcs_cfg |= (u8)offset;
313

314 315
		dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);

316
		/* Do it */
317
		snd_soc_write(codec, dcs_reg, dcs_cfg);
318 319 320
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_DAC_WR_0 |
				  WM8993_DCS_TRIG_DAC_WR_1);
321
	} else {
322 323
		dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
		dcs_cfg |= reg_l;
324
	}
325 326 327

	/* Save the callibrated offset if we're in class W mode and
	 * therefore don't have any analogue signal mixed in. */
328 329
	if (wm_hubs_dac_hp_direct(codec))
		wm_hubs_dcs_cache_set(codec, dcs_cfg);
330 331
}

332 333 334 335
/*
 * Update the DC servo calibration on gain changes
 */
static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
336
			       struct snd_ctl_elem_value *ucontrol)
337
{
338
	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
339
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
340 341
	int ret;

342
	ret = snd_soc_put_volsw(kcontrol, ucontrol);
343

344 345
	/* If we're applying an offset correction then updating the
	 * callibration would be likely to introduce further offsets. */
346
	if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
347 348
		return ret;

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	/* Only need to do this if the outputs are active */
	if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1)
	    & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
		snd_soc_update_bits(codec,
				    WM8993_DC_SERVO_0,
				    WM8993_DCS_TRIG_SINGLE_0 |
				    WM8993_DCS_TRIG_SINGLE_1,
				    WM8993_DCS_TRIG_SINGLE_0 |
				    WM8993_DCS_TRIG_SINGLE_1);

	return ret;
}

static const struct snd_kcontrol_new analogue_snd_controls[] = {
SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
	       inpga_tlv),
SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
M
Mark Brown 已提交
366
SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
367 368 369 370

SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
	       inpga_tlv),
SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
M
Mark Brown 已提交
371
SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
372 373 374 375 376


SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
	       inpga_tlv),
SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
M
Mark Brown 已提交
377
SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
378 379 380 381

SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
	       inpga_tlv),
SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
M
Mark Brown 已提交
382
SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473

SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
	       inmix_sw_tlv),
SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0,
	       inmix_sw_tlv),
SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0,
	       inmix_tlv),
SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv),
SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0,
	       inmix_tlv),

SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0,
	       inmix_sw_tlv),
SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0,
	       inmix_sw_tlv),
SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0,
	       inmix_tlv),
SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv),
SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0,
	       inmix_tlv),

SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1,
	       outmix_tlv),
SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1,
	       outmix_tlv),
SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1,
	       outmix_tlv),
SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1,
	       outmix_tlv),
SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1,
	       outmix_tlv),
SOC_SINGLE_TLV("Left Output Mixer Right Input Volume",
	       WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Left Output Mixer Left Input Volume",
	       WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1,
	       outmix_tlv),

SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume",
	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume",
	       WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Right Output Mixer IN1L Volume",
	       WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Right Output Mixer IN1R Volume",
	       WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume",
	       WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Right Output Mixer Left Input Volume",
	       WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Right Output Mixer Right Input Volume",
	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
SOC_SINGLE_TLV("Right Output Mixer DAC Volume",
	       WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv),

SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME,
		 WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv),
SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME,
	     WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0),
SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME,
	     WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0),

SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1),
SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv),

SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION,
	       5, 1, 1, wm_hubs_spkmix_tlv),
SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION,
	       4, 1, 1, wm_hubs_spkmix_tlv),
SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION,
	       3, 1, 1, wm_hubs_spkmix_tlv),

SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION,
	       5, 1, 1, wm_hubs_spkmix_tlv),
SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION,
	       4, 1, 1, wm_hubs_spkmix_tlv),
SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION,
	       3, 1, 1, wm_hubs_spkmix_tlv),

SOC_DOUBLE_R_TLV("Speaker Mixer Volume",
		 WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION,
		 0, 3, 1, spkmixout_tlv),
SOC_DOUBLE_R_TLV("Speaker Volume",
		 WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
		 0, 63, 0, outpga_tlv),
SOC_DOUBLE_R("Speaker Switch",
	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
	     6, 1, 0),
SOC_DOUBLE_R("Speaker ZC Switch",
	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
	     7, 1, 0),
474
SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
475 476 477 478
	       spkboost_tlv),
SOC_ENUM("Speaker Reference", speaker_ref),
SOC_ENUM("Speaker Mode", speaker_mode),

479 480
SOC_DOUBLE_R_EXT_TLV("Headphone Volume",
		     WM8993_LEFT_OUTPUT_VOLUME, WM8993_RIGHT_OUTPUT_VOLUME,
481
		     0, 63, 0, snd_soc_get_volsw, wm8993_put_dc_servo,
482 483
		     outpga_tlv),

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
	     WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
	     WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0),

SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1),
SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1),
SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1,
	       line_tlv),

SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1),
SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1),
SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
	       line_tlv),
};

500 501 502
static int hp_supply_event(struct snd_soc_dapm_widget *w,
			   struct snd_kcontrol *kcontrol, int event)
{
503
	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
504
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		switch (hubs->hp_startup_mode) {
		case 0:
			break;
		case 1:
			/* Enable the headphone amp */
			snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
					    WM8993_HPOUT1L_ENA |
					    WM8993_HPOUT1R_ENA,
					    WM8993_HPOUT1L_ENA |
					    WM8993_HPOUT1R_ENA);

			/* Enable the second stage */
			snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
					    WM8993_HPOUT1L_DLY |
					    WM8993_HPOUT1R_DLY,
					    WM8993_HPOUT1L_DLY |
					    WM8993_HPOUT1R_DLY);
			break;
		default:
			dev_err(codec->dev, "Unknown HP startup mode %d\n",
				hubs->hp_startup_mode);
			break;
		}
531
		break;
532 533 534 535 536 537 538 539 540 541

	case SND_SOC_DAPM_PRE_PMD:
		snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
				    WM8993_CP_ENA, 0);
		break;
	}

	return 0;
}

542 543 544
static int hp_event(struct snd_soc_dapm_widget *w,
		    struct snd_kcontrol *kcontrol, int event)
{
545
	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
	unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0);

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
				    WM8993_CP_ENA, WM8993_CP_ENA);

		msleep(5);

		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);

		reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
		snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);

562
		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
563
				    WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
564

565
		enable_dc_servo(codec);
566 567 568 569 570 571 572

		reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
			WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
		snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
		break;

	case SND_SOC_DAPM_PRE_PMD:
573
		snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
574 575
				    WM8993_HPOUT1L_OUTP |
				    WM8993_HPOUT1R_OUTP |
576 577
				    WM8993_HPOUT1L_RMV_SHORT |
				    WM8993_HPOUT1R_RMV_SHORT, 0);
578

579
		snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
580 581
				    WM8993_HPOUT1L_DLY |
				    WM8993_HPOUT1R_DLY, 0);
582

583 584
		snd_soc_write(codec, WM8993_DC_SERVO_0, 0);

585 586 587 588 589 590 591 592 593 594 595 596
		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
				    0);
		break;
	}

	return 0;
}

static int earpiece_event(struct snd_soc_dapm_widget *w,
			  struct snd_kcontrol *control, int event)
{
597
	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
598 599 600 601 602 603 604 605 606 607 608 609 610 611
	u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		reg |= WM8993_HPOUT2_IN_ENA;
		snd_soc_write(codec, WM8993_ANTIPOP1, reg);
		udelay(50);
		break;

	case SND_SOC_DAPM_POST_PMD:
		snd_soc_write(codec, WM8993_ANTIPOP1, reg);
		break;

	default:
612
		WARN(1, "Invalid event %d\n", event);
613 614 615 616 617 618
		break;
	}

	return 0;
}

619 620 621
static int lineout_event(struct snd_soc_dapm_widget *w,
			 struct snd_kcontrol *control, int event)
{
622
	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
	bool *flag;

	switch (w->shift) {
	case WM8993_LINEOUT1N_ENA_SHIFT:
		flag = &hubs->lineout1n_ena;
		break;
	case WM8993_LINEOUT1P_ENA_SHIFT:
		flag = &hubs->lineout1p_ena;
		break;
	case WM8993_LINEOUT2N_ENA_SHIFT:
		flag = &hubs->lineout2n_ena;
		break;
	case WM8993_LINEOUT2P_ENA_SHIFT:
		flag = &hubs->lineout2p_ena;
		break;
	default:
		WARN(1, "Unknown line output");
		return -EINVAL;
	}

	*flag = SND_SOC_DAPM_EVENT_ON(event);

	return 0;
}

649 650 651
static int micbias_event(struct snd_soc_dapm_widget *w,
			 struct snd_kcontrol *kcontrol, int event)
{
652
	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);

	switch (w->shift) {
	case WM8993_MICB1_ENA_SHIFT:
		if (hubs->micb1_delay)
			msleep(hubs->micb1_delay);
		break;
	case WM8993_MICB2_ENA_SHIFT:
		if (hubs->micb2_delay)
			msleep(hubs->micb2_delay);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
void wm_hubs_update_class_w(struct snd_soc_codec *codec)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
	int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;

	if (!wm_hubs_dac_hp_direct(codec))
		enable = false;

	if (hubs->check_class_w_digital && !hubs->check_class_w_digital(codec))
		enable = false;

	dev_vdbg(codec->dev, "Class W %s\n", enable ? "enabled" : "disabled");

	snd_soc_update_bits(codec, WM8993_CLASS_W_0,
			    WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
686 687 688 689 690

	snd_soc_write(codec, WM8993_LEFT_OUTPUT_VOLUME,
		      snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME));
	snd_soc_write(codec, WM8993_RIGHT_OUTPUT_VOLUME,
		      snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME));
691 692 693
}
EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);

694
#define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
695 696
	SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
		snd_soc_dapm_get_volsw, class_w_put_volsw)
697 698 699 700

static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_value *ucontrol)
{
701
	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
702 703 704 705 706 707 708 709 710
	int ret;

	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);

	wm_hubs_update_class_w(codec);

	return ret;
}

711 712 713 714
#define WM_HUBS_ENUM_W(xname, xenum) \
{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
	.info = snd_soc_info_enum_double, \
	.get = snd_soc_dapm_get_enum_double, \
715
	.put = class_w_put_double, \
716 717
	.private_value = (unsigned long)&xenum }

718 719
static int class_w_put_double(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_value *ucontrol)
720
{
721
	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
722 723 724 725 726 727 728 729 730 731 732 733 734 735
	int ret;

	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);

	wm_hubs_update_class_w(codec);

	return ret;
}

static const char *hp_mux_text[] = {
	"Mixer",
	"DAC",
};

736 737
static SOC_ENUM_SINGLE_DECL(hpl_enum,
			    WM8993_OUTPUT_MIXER1, 8, hp_mux_text);
738 739 740 741 742

const struct snd_kcontrol_new wm_hubs_hpl_mux =
	WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);

743 744
static SOC_ENUM_SINGLE_DECL(hpr_enum,
			    WM8993_OUTPUT_MIXER2, 8, hp_mux_text);
745 746 747 748 749

const struct snd_kcontrol_new wm_hubs_hpr_mux =
	WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
EXPORT_SYMBOL_GPL(wm_hubs_hpr_mux);

750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
static const struct snd_kcontrol_new in1l_pga[] = {
SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
};

static const struct snd_kcontrol_new in1r_pga[] = {
SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0),
SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0),
};

static const struct snd_kcontrol_new in2l_pga[] = {
SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0),
SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0),
};

static const struct snd_kcontrol_new in2r_pga[] = {
SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0),
SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0),
};

static const struct snd_kcontrol_new mixinl[] = {
SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0),
SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0),
};

static const struct snd_kcontrol_new mixinr[] = {
SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0),
SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
};

static const struct snd_kcontrol_new left_output_mixer[] = {
781 782 783 784 785 786 787 788
WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
WM_HUBS_SINGLE_W("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
789 790 791
};

static const struct snd_kcontrol_new right_output_mixer[] = {
792 793 794 795 796 797 798 799
WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
WM_HUBS_SINGLE_W("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
};

static const struct snd_kcontrol_new earpiece_mixer[] = {
SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0),
SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0),
SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0),
};

static const struct snd_kcontrol_new left_speaker_boost[] = {
SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0),
SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0),
SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0),
};

static const struct snd_kcontrol_new right_speaker_boost[] = {
SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0),
SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0),
SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0),
};

static const struct snd_kcontrol_new line1_mix[] = {
SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0),
SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0),
SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
};

static const struct snd_kcontrol_new line1n_mix[] = {
SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0),
SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0),
};

static const struct snd_kcontrol_new line1p_mix[] = {
SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
};

static const struct snd_kcontrol_new line2_mix[] = {
836 837
SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0),
SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0),
838 839 840 841
SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
};

static const struct snd_kcontrol_new line2n_mix[] = {
842 843
SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
844 845 846 847 848 849 850 851 852 853
};

static const struct snd_kcontrol_new line2p_mix[] = {
SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
};

static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("IN1LN"),
SND_SOC_DAPM_INPUT("IN1LP"),
SND_SOC_DAPM_INPUT("IN2LN"),
854
SND_SOC_DAPM_INPUT("IN2LP:VXRN"),
855 856 857
SND_SOC_DAPM_INPUT("IN1RN"),
SND_SOC_DAPM_INPUT("IN1RP"),
SND_SOC_DAPM_INPUT("IN2RN"),
858
SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
859

860 861 862 863
SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0,
		    micbias_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0,
		    micbias_event, SND_SOC_DAPM_POST_PMU),
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887

SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
		   in1l_pga, ARRAY_SIZE(in1l_pga)),
SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
		   in1r_pga, ARRAY_SIZE(in1r_pga)),

SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
		   in2l_pga, ARRAY_SIZE(in2l_pga)),
SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
		   in2r_pga, ARRAY_SIZE(in2r_pga)),

SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
		   mixinl, ARRAY_SIZE(mixinl)),
SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
		   mixinr, ARRAY_SIZE(mixinr)),

SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0,
		   left_output_mixer, ARRAY_SIZE(left_output_mixer)),
SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
		   right_output_mixer, ARRAY_SIZE(right_output_mixer)),

SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),

888 889
SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, 
		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
890 891
SND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
		       hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
892 893 894 895 896 897 898 899 900 901 902 903

SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
		   earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0,
		   NULL, 0, earpiece_event,
		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),

SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
		   left_speaker_boost, ARRAY_SIZE(left_speaker_boost)),
SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
		   right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),

904
SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
905 906 907 908
SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
		     NULL, 0),
SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
		     NULL, 0),
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923

SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
		   line1_mix, ARRAY_SIZE(line1_mix)),
SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
		   line2_mix, ARRAY_SIZE(line2_mix)),

SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0,
		   line1n_mix, ARRAY_SIZE(line1n_mix)),
SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0,
		   line1p_mix, ARRAY_SIZE(line1p_mix)),
SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
		   line2n_mix, ARRAY_SIZE(line2n_mix)),
SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
		   line2p_mix, ARRAY_SIZE(line2p_mix)),

924 925 926 927 928 929 930 931 932 933 934 935
SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
		       NULL, 0, lineout_event,
		     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
		       NULL, 0, lineout_event,
		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
		       NULL, 0, lineout_event,
		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
		       NULL, 0, lineout_event,
		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951

SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
SND_SOC_DAPM_OUTPUT("HPOUT2P"),
SND_SOC_DAPM_OUTPUT("HPOUT2N"),
SND_SOC_DAPM_OUTPUT("LINEOUT1P"),
SND_SOC_DAPM_OUTPUT("LINEOUT1N"),
SND_SOC_DAPM_OUTPUT("LINEOUT2P"),
SND_SOC_DAPM_OUTPUT("LINEOUT2N"),
};

static const struct snd_soc_dapm_route analogue_routes[] = {
952 953 954
	{ "MICBIAS1", NULL, "CLK_SYS" },
	{ "MICBIAS2", NULL, "CLK_SYS" },

955 956 957
	{ "IN1L PGA", "IN1LP Switch", "IN1LP" },
	{ "IN1L PGA", "IN1LN Switch", "IN1LN" },

958 959 960 961 962
	{ "IN1L PGA", NULL, "VMID" },
	{ "IN1R PGA", NULL, "VMID" },
	{ "IN2L PGA", NULL, "VMID" },
	{ "IN2R PGA", NULL, "VMID" },

963 964 965
	{ "IN1R PGA", "IN1RP Switch", "IN1RP" },
	{ "IN1R PGA", "IN1RN Switch", "IN1RN" },

966
	{ "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" },
967 968
	{ "IN2L PGA", "IN2LN Switch", "IN2LN" },

969
	{ "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" },
970 971
	{ "IN2R PGA", "IN2RN Switch", "IN2RN" },

972 973
	{ "Direct Voice", NULL, "IN2LP:VXRN" },
	{ "Direct Voice", NULL, "IN2RP:VXRP" },
974 975 976 977 978 979

	{ "MIXINL", "IN1L Switch", "IN1L PGA" },
	{ "MIXINL", "IN2L Switch", "IN2L PGA" },
	{ "MIXINL", NULL, "Direct Voice" },
	{ "MIXINL", NULL, "IN1LP" },
	{ "MIXINL", NULL, "Left Output Mixer" },
980
	{ "MIXINL", NULL, "VMID" },
981 982 983 984 985 986

	{ "MIXINR", "IN1R Switch", "IN1R PGA" },
	{ "MIXINR", "IN2R Switch", "IN2R PGA" },
	{ "MIXINR", NULL, "Direct Voice" },
	{ "MIXINR", NULL, "IN1RP" },
	{ "MIXINR", NULL, "Right Output Mixer" },
987
	{ "MIXINR", NULL, "VMID" },
988 989 990 991 992 993 994 995

	{ "ADCL", NULL, "MIXINL" },
	{ "ADCR", NULL, "MIXINR" },

	{ "Left Output Mixer", "Left Input Switch", "MIXINL" },
	{ "Left Output Mixer", "Right Input Switch", "MIXINR" },
	{ "Left Output Mixer", "IN2RN Switch", "IN2RN" },
	{ "Left Output Mixer", "IN2LN Switch", "IN2LN" },
996
	{ "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" },
997 998 999 1000 1001 1002 1003
	{ "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
	{ "Left Output Mixer", "IN1R Switch", "IN1R PGA" },

	{ "Right Output Mixer", "Left Input Switch", "MIXINL" },
	{ "Right Output Mixer", "Right Input Switch", "MIXINR" },
	{ "Right Output Mixer", "IN2LN Switch", "IN2LN" },
	{ "Right Output Mixer", "IN2RN Switch", "IN2RN" },
1004
	{ "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" },
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
	{ "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
	{ "Right Output Mixer", "IN1R Switch", "IN1R PGA" },

	{ "Left Output PGA", NULL, "Left Output Mixer" },
	{ "Left Output PGA", NULL, "TOCLK" },

	{ "Right Output PGA", NULL, "Right Output Mixer" },
	{ "Right Output PGA", NULL, "TOCLK" },

	{ "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" },
	{ "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
	{ "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },

1018
	{ "Earpiece Driver", NULL, "VMID" },
1019 1020 1021 1022 1023 1024
	{ "Earpiece Driver", NULL, "Earpiece Mixer" },
	{ "HPOUT2N", NULL, "Earpiece Driver" },
	{ "HPOUT2P", NULL, "Earpiece Driver" },

	{ "SPKL", "Input Switch", "MIXINL" },
	{ "SPKL", "IN1LP Switch", "IN1LP" },
1025
	{ "SPKL", "Output Switch", "Left Output PGA" },
1026 1027 1028 1029
	{ "SPKL", NULL, "TOCLK" },

	{ "SPKR", "Input Switch", "MIXINR" },
	{ "SPKR", "IN1RP Switch", "IN1RP" },
1030
	{ "SPKR", "Output Switch", "Right Output PGA" },
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
	{ "SPKR", NULL, "TOCLK" },

	{ "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
	{ "SPKL Boost", "SPKL Switch", "SPKL" },
	{ "SPKL Boost", "SPKR Switch", "SPKR" },

	{ "SPKR Boost", "Direct Voice Switch", "Direct Voice" },
	{ "SPKR Boost", "SPKR Switch", "SPKR" },
	{ "SPKR Boost", "SPKL Switch", "SPKL" },

1041
	{ "SPKL Driver", NULL, "VMID" },
1042 1043
	{ "SPKL Driver", NULL, "SPKL Boost" },
	{ "SPKL Driver", NULL, "CLK_SYS" },
1044
	{ "SPKL Driver", NULL, "TSHUT" },
1045

1046
	{ "SPKR Driver", NULL, "VMID" },
1047 1048
	{ "SPKR Driver", NULL, "SPKR Boost" },
	{ "SPKR Driver", NULL, "CLK_SYS" },
1049
	{ "SPKR Driver", NULL, "TSHUT" },
1050 1051 1052 1053 1054 1055

	{ "SPKOUTLP", NULL, "SPKL Driver" },
	{ "SPKOUTLN", NULL, "SPKL Driver" },
	{ "SPKOUTRP", NULL, "SPKR Driver" },
	{ "SPKOUTRN", NULL, "SPKR Driver" },

1056 1057
	{ "Left Headphone Mux", "Mixer", "Left Output PGA" },
	{ "Right Headphone Mux", "Mixer", "Right Output PGA" },
1058 1059 1060

	{ "Headphone PGA", NULL, "Left Headphone Mux" },
	{ "Headphone PGA", NULL, "Right Headphone Mux" },
1061
	{ "Headphone PGA", NULL, "VMID" },
1062
	{ "Headphone PGA", NULL, "CLK_SYS" },
1063
	{ "Headphone PGA", NULL, "Headphone Supply" },
1064 1065 1066 1067

	{ "HPOUT1L", NULL, "Headphone PGA" },
	{ "HPOUT1R", NULL, "Headphone PGA" },

1068 1069 1070 1071 1072
	{ "LINEOUT1N Driver", NULL, "VMID" },
	{ "LINEOUT1P Driver", NULL, "VMID" },
	{ "LINEOUT2N Driver", NULL, "VMID" },
	{ "LINEOUT2P Driver", NULL, "VMID" },

1073 1074 1075 1076 1077 1078 1079 1080 1081
	{ "LINEOUT1N", NULL, "LINEOUT1N Driver" },
	{ "LINEOUT1P", NULL, "LINEOUT1P Driver" },
	{ "LINEOUT2N", NULL, "LINEOUT2N Driver" },
	{ "LINEOUT2P", NULL, "LINEOUT2P Driver" },
};

static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
	{ "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
	{ "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
1082
	{ "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" },
1083 1084 1085 1086 1087 1088

	{ "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
	{ "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
};

static const struct snd_soc_dapm_route lineout1_se_routes[] = {
1089 1090
	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
1091

1092
	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
1093 1094 1095 1096 1097 1098

	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
	{ "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
};

static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
1099 1100
	{ "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" },
	{ "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" },
1101
	{ "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
1102 1103 1104 1105 1106 1107

	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
	{ "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
};

static const struct snd_soc_dapm_route lineout2_se_routes[] = {
1108 1109
	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
1110

1111
	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
1112 1113 1114 1115 1116 1117 1118

	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
};

int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
{
L
Liam Girdwood 已提交
1119 1120
	struct snd_soc_dapm_context *dapm = &codec->dapm;

1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
	/* Latch volume update bits & default ZC on */
	snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
			    WM8993_IN1_VU, WM8993_IN1_VU);
	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
			    WM8993_IN1_VU, WM8993_IN1_VU);
	snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
			    WM8993_IN2_VU, WM8993_IN2_VU);
	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
			    WM8993_IN2_VU, WM8993_IN2_VU);

1131 1132
	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_LEFT,
			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
1133 1134 1135 1136
	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);

	snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
1137 1138
			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
1139 1140 1141 1142 1143
	snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);

	snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
1144 1145
			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
1146 1147 1148 1149
	snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);

1150
	snd_soc_add_codec_controls(codec, analogue_snd_controls,
1151 1152
			     ARRAY_SIZE(analogue_snd_controls));

L
Liam Girdwood 已提交
1153
	snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
1154 1155 1156 1157 1158 1159 1160 1161
				  ARRAY_SIZE(analogue_dapm_widgets));
	return 0;
}
EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);

int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
				int lineout1_diff, int lineout2_diff)
{
1162
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
L
Liam Girdwood 已提交
1163 1164
	struct snd_soc_dapm_context *dapm = &codec->dapm;

1165 1166
	hubs->codec = codec;

1167
	INIT_LIST_HEAD(&hubs->dcs_cache);
1168 1169
	init_completion(&hubs->dcs_done);

L
Liam Girdwood 已提交
1170
	snd_soc_dapm_add_routes(dapm, analogue_routes,
1171 1172 1173
				ARRAY_SIZE(analogue_routes));

	if (lineout1_diff)
L
Liam Girdwood 已提交
1174
		snd_soc_dapm_add_routes(dapm,
1175 1176 1177
					lineout1_diff_routes,
					ARRAY_SIZE(lineout1_diff_routes));
	else
L
Liam Girdwood 已提交
1178
		snd_soc_dapm_add_routes(dapm,
1179 1180 1181 1182
					lineout1_se_routes,
					ARRAY_SIZE(lineout1_se_routes));

	if (lineout2_diff)
L
Liam Girdwood 已提交
1183
		snd_soc_dapm_add_routes(dapm,
1184 1185 1186
					lineout2_diff_routes,
					ARRAY_SIZE(lineout2_diff_routes));
	else
L
Liam Girdwood 已提交
1187
		snd_soc_dapm_add_routes(dapm,
1188 1189 1190 1191 1192 1193 1194
					lineout2_se_routes,
					ARRAY_SIZE(lineout2_se_routes));

	return 0;
}
EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);

1195 1196 1197
int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
				  int lineout1_diff, int lineout2_diff,
				  int lineout1fb, int lineout2fb,
1198 1199 1200
				  int jd_scthr, int jd_thr,
				  int micbias1_delay, int micbias2_delay,
				  int micbias1_lvl, int micbias2_lvl)
1201
{
1202 1203 1204 1205
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);

	hubs->lineout1_se = !lineout1_diff;
	hubs->lineout2_se = !lineout2_diff;
1206 1207
	hubs->micb1_delay = micbias1_delay;
	hubs->micb2_delay = micbias2_delay;
1208

1209 1210 1211 1212 1213 1214 1215 1216 1217
	if (!lineout1_diff)
		snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
				    WM8993_LINEOUT1_MODE,
				    WM8993_LINEOUT1_MODE);
	if (!lineout2_diff)
		snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
				    WM8993_LINEOUT2_MODE,
				    WM8993_LINEOUT2_MODE);

1218 1219 1220 1221 1222
	if (!lineout1_diff && !lineout2_diff)
		snd_soc_update_bits(codec, WM8993_ANTIPOP1,
				    WM8993_LINEOUT_VMID_BUF_ENA,
				    WM8993_LINEOUT_VMID_BUF_ENA);

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
	if (lineout1fb)
		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
				    WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);

	if (lineout2fb)
		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
				    WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);

	snd_soc_update_bits(codec, WM8993_MICBIAS,
			    WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
			    WM8993_MICB1_LVL | WM8993_MICB2_LVL,
			    jd_scthr << WM8993_JD_SCTHR_SHIFT |
			    jd_thr << WM8993_JD_THR_SHIFT |
			    micbias1_lvl |
			    micbias2_lvl << WM8993_MICB2_LVL_SHIFT);

	return 0;
}
EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);

1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
void wm_hubs_vmid_ena(struct snd_soc_codec *codec)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
	int val = 0;

	if (hubs->lineout1_se)
		val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;

	if (hubs->lineout2_se)
		val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;

	/* Enable the line outputs while we power up */
	snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, val, val);
}
EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);

void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
			    enum snd_soc_bias_level level)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
1263
	int mask, val;
1264 1265

	switch (level) {
1266 1267 1268 1269 1270 1271
	case SND_SOC_BIAS_STANDBY:
		/* Clamp the inputs to VMID while we ramp to charge caps */
		snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
				    WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP);
		break;

1272 1273 1274
	case SND_SOC_BIAS_ON:
		/* Turn off any unneded single ended outputs */
		val = 0;
1275 1276 1277 1278 1279 1280 1281
		mask = 0;

		if (hubs->lineout1_se)
			mask |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;

		if (hubs->lineout2_se)
			mask |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295

		if (hubs->lineout1_se && hubs->lineout1n_ena)
			val |= WM8993_LINEOUT1N_ENA;

		if (hubs->lineout1_se && hubs->lineout1p_ena)
			val |= WM8993_LINEOUT1P_ENA;

		if (hubs->lineout2_se && hubs->lineout2n_ena)
			val |= WM8993_LINEOUT2N_ENA;

		if (hubs->lineout2_se && hubs->lineout2p_ena)
			val |= WM8993_LINEOUT2P_ENA;

		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3,
1296
				    mask, val);
1297

1298 1299 1300
		/* Remove the input clamps */
		snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
				    WM8993_INPUTS_CLAMP, 0);
1301 1302 1303 1304 1305 1306 1307 1308
		break;

	default:
		break;
	}
}
EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level);

1309 1310 1311
MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");