cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wm_hubs.c (43160B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * wm_hubs.c  --  WM8993/4 common code
      4 *
      5 * Copyright 2009-12 Wolfson Microelectronics plc
      6 *
      7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/moduleparam.h>
     12#include <linux/init.h>
     13#include <linux/delay.h>
     14#include <linux/pm.h>
     15#include <linux/i2c.h>
     16#include <linux/mfd/wm8994/registers.h>
     17#include <sound/core.h>
     18#include <sound/pcm.h>
     19#include <sound/pcm_params.h>
     20#include <sound/soc.h>
     21#include <sound/initval.h>
     22#include <sound/tlv.h>
     23
     24#include "wm8993.h"
     25#include "wm_hubs.h"
     26
     27const DECLARE_TLV_DB_SCALE(wm_hubs_spkmix_tlv, -300, 300, 0);
     28EXPORT_SYMBOL_GPL(wm_hubs_spkmix_tlv);
     29
     30static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0);
     31static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0);
     32static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1);
     33static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
     34static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
     35static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
     36static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
     37static const DECLARE_TLV_DB_RANGE(spkboost_tlv,
     38	0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
     39	7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
     40);
     41static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);
     42
     43static const char *speaker_ref_text[] = {
     44	"SPKVDD/2",
     45	"VMID",
     46};
     47
     48static SOC_ENUM_SINGLE_DECL(speaker_ref,
     49			    WM8993_SPEAKER_MIXER, 8, speaker_ref_text);
     50
     51static const char *speaker_mode_text[] = {
     52	"Class D",
     53	"Class AB",
     54};
     55
     56static SOC_ENUM_SINGLE_DECL(speaker_mode,
     57			    WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);
     58
     59static void wait_for_dc_servo(struct snd_soc_component *component, unsigned int op)
     60{
     61	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
     62	unsigned int reg;
     63	int count = 0;
     64	int timeout;
     65	unsigned int val;
     66
     67	val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;
     68
     69	/* Trigger the command */
     70	snd_soc_component_write(component, WM8993_DC_SERVO_0, val);
     71
     72	dev_dbg(component->dev, "Waiting for DC servo...\n");
     73
     74	if (hubs->dcs_done_irq)
     75		timeout = 4;
     76	else
     77		timeout = 400;
     78
     79	do {
     80		count++;
     81
     82		if (hubs->dcs_done_irq)
     83			wait_for_completion_timeout(&hubs->dcs_done,
     84						    msecs_to_jiffies(250));
     85		else
     86			msleep(1);
     87
     88		reg = snd_soc_component_read(component, WM8993_DC_SERVO_0);
     89		dev_dbg(component->dev, "DC servo: %x\n", reg);
     90	} while (reg & op && count < timeout);
     91
     92	if (reg & op)
     93		dev_err(component->dev, "Timed out waiting for DC Servo %x\n",
     94			op);
     95}
     96
     97irqreturn_t wm_hubs_dcs_done(int irq, void *data)
     98{
     99	struct wm_hubs_data *hubs = data;
    100
    101	complete(&hubs->dcs_done);
    102
    103	return IRQ_HANDLED;
    104}
    105EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
    106
    107static bool wm_hubs_dac_hp_direct(struct snd_soc_component *component)
    108{
    109	int reg;
    110
    111	/* If we're going via the mixer we'll need to do additional checks */
    112	reg = snd_soc_component_read(component, WM8993_OUTPUT_MIXER1);
    113	if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
    114		if (reg & ~WM8993_DACL_TO_MIXOUTL) {
    115			dev_vdbg(component->dev, "Analogue paths connected: %x\n",
    116				 reg & ~WM8993_DACL_TO_HPOUT1L);
    117			return false;
    118		} else {
    119			dev_vdbg(component->dev, "HPL connected to mixer\n");
    120		}
    121	} else {
    122		dev_vdbg(component->dev, "HPL connected to DAC\n");
    123	}
    124
    125	reg = snd_soc_component_read(component, WM8993_OUTPUT_MIXER2);
    126	if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
    127		if (reg & ~WM8993_DACR_TO_MIXOUTR) {
    128			dev_vdbg(component->dev, "Analogue paths connected: %x\n",
    129				 reg & ~WM8993_DACR_TO_HPOUT1R);
    130			return false;
    131		} else {
    132			dev_vdbg(component->dev, "HPR connected to mixer\n");
    133		}
    134	} else {
    135		dev_vdbg(component->dev, "HPR connected to DAC\n");
    136	}
    137
    138	return true;
    139}
    140
    141struct wm_hubs_dcs_cache {
    142	struct list_head list;
    143	unsigned int left;
    144	unsigned int right;
    145	u16 dcs_cfg;
    146};
    147
    148static bool wm_hubs_dcs_cache_get(struct snd_soc_component *component,
    149				  struct wm_hubs_dcs_cache **entry)
    150{
    151	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    152	struct wm_hubs_dcs_cache *cache;
    153	unsigned int left, right;
    154
    155	left = snd_soc_component_read(component, WM8993_LEFT_OUTPUT_VOLUME);
    156	left &= WM8993_HPOUT1L_VOL_MASK;
    157
    158	right = snd_soc_component_read(component, WM8993_RIGHT_OUTPUT_VOLUME);
    159	right &= WM8993_HPOUT1R_VOL_MASK;
    160
    161	list_for_each_entry(cache, &hubs->dcs_cache, list) {
    162		if (cache->left != left || cache->right != right)
    163			continue;
    164
    165		*entry = cache;
    166		return true;
    167	}
    168
    169	return false;
    170}
    171
    172static void wm_hubs_dcs_cache_set(struct snd_soc_component *component, u16 dcs_cfg)
    173{
    174	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    175	struct wm_hubs_dcs_cache *cache;
    176
    177	if (hubs->no_cache_dac_hp_direct)
    178		return;
    179
    180	cache = devm_kzalloc(component->dev, sizeof(*cache), GFP_KERNEL);
    181	if (!cache)
    182		return;
    183
    184	cache->left = snd_soc_component_read(component, WM8993_LEFT_OUTPUT_VOLUME);
    185	cache->left &= WM8993_HPOUT1L_VOL_MASK;
    186
    187	cache->right = snd_soc_component_read(component, WM8993_RIGHT_OUTPUT_VOLUME);
    188	cache->right &= WM8993_HPOUT1R_VOL_MASK;
    189
    190	cache->dcs_cfg = dcs_cfg;
    191
    192	list_add_tail(&cache->list, &hubs->dcs_cache);
    193}
    194
    195static int wm_hubs_read_dc_servo(struct snd_soc_component *component,
    196				  u16 *reg_l, u16 *reg_r)
    197{
    198	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    199	u16 dcs_reg, reg;
    200	int ret = 0;
    201
    202	switch (hubs->dcs_readback_mode) {
    203	case 2:
    204		dcs_reg = WM8994_DC_SERVO_4E;
    205		break;
    206	case 1:
    207		dcs_reg = WM8994_DC_SERVO_READBACK;
    208		break;
    209	default:
    210		dcs_reg = WM8993_DC_SERVO_3;
    211		break;
    212	}
    213
    214	/* Different chips in the family support different readback
    215	 * methods.
    216	 */
    217	switch (hubs->dcs_readback_mode) {
    218	case 0:
    219		*reg_l = snd_soc_component_read(component, WM8993_DC_SERVO_READBACK_1)
    220			& WM8993_DCS_INTEG_CHAN_0_MASK;
    221		*reg_r = snd_soc_component_read(component, WM8993_DC_SERVO_READBACK_2)
    222			& WM8993_DCS_INTEG_CHAN_1_MASK;
    223		break;
    224	case 2:
    225	case 1:
    226		reg = snd_soc_component_read(component, dcs_reg);
    227		*reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
    228			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
    229		*reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
    230		break;
    231	default:
    232		WARN(1, "Unknown DCS readback method\n");
    233		ret = -1;
    234	}
    235	return ret;
    236}
    237
    238/*
    239 * Startup calibration of the DC servo
    240 */
    241static void enable_dc_servo(struct snd_soc_component *component)
    242{
    243	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    244	struct wm_hubs_dcs_cache *cache;
    245	s8 offset;
    246	u16 reg_l, reg_r, dcs_cfg, dcs_reg;
    247
    248	switch (hubs->dcs_readback_mode) {
    249	case 2:
    250		dcs_reg = WM8994_DC_SERVO_4E;
    251		break;
    252	default:
    253		dcs_reg = WM8993_DC_SERVO_3;
    254		break;
    255	}
    256
    257	/* If we're using a digital only path and have a previously
    258	 * callibrated DC servo offset stored then use that. */
    259	if (wm_hubs_dac_hp_direct(component) &&
    260	    wm_hubs_dcs_cache_get(component, &cache)) {
    261		dev_dbg(component->dev, "Using cached DCS offset %x for %d,%d\n",
    262			cache->dcs_cfg, cache->left, cache->right);
    263		snd_soc_component_write(component, dcs_reg, cache->dcs_cfg);
    264		wait_for_dc_servo(component,
    265				  WM8993_DCS_TRIG_DAC_WR_0 |
    266				  WM8993_DCS_TRIG_DAC_WR_1);
    267		return;
    268	}
    269
    270	if (hubs->series_startup) {
    271		/* Set for 32 series updates */
    272		snd_soc_component_update_bits(component, WM8993_DC_SERVO_1,
    273				    WM8993_DCS_SERIES_NO_01_MASK,
    274				    32 << WM8993_DCS_SERIES_NO_01_SHIFT);
    275		wait_for_dc_servo(component,
    276				  WM8993_DCS_TRIG_SERIES_0 |
    277				  WM8993_DCS_TRIG_SERIES_1);
    278	} else {
    279		wait_for_dc_servo(component,
    280				  WM8993_DCS_TRIG_STARTUP_0 |
    281				  WM8993_DCS_TRIG_STARTUP_1);
    282	}
    283
    284	if (wm_hubs_read_dc_servo(component, &reg_l, &reg_r) < 0)
    285		return;
    286
    287	dev_dbg(component->dev, "DCS input: %x %x\n", reg_l, reg_r);
    288
    289	/* Apply correction to DC servo result */
    290	if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
    291		dev_dbg(component->dev,
    292			"Applying %d/%d code DC servo correction\n",
    293			hubs->dcs_codes_l, hubs->dcs_codes_r);
    294
    295		/* HPOUT1R */
    296		offset = (s8)reg_r;
    297		dev_dbg(component->dev, "DCS right %d->%d\n", offset,
    298			offset + hubs->dcs_codes_r);
    299		offset += hubs->dcs_codes_r;
    300		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
    301
    302		/* HPOUT1L */
    303		offset = (s8)reg_l;
    304		dev_dbg(component->dev, "DCS left %d->%d\n", offset,
    305			offset + hubs->dcs_codes_l);
    306		offset += hubs->dcs_codes_l;
    307		dcs_cfg |= (u8)offset;
    308
    309		dev_dbg(component->dev, "DCS result: %x\n", dcs_cfg);
    310
    311		/* Do it */
    312		snd_soc_component_write(component, dcs_reg, dcs_cfg);
    313		wait_for_dc_servo(component,
    314				  WM8993_DCS_TRIG_DAC_WR_0 |
    315				  WM8993_DCS_TRIG_DAC_WR_1);
    316	} else {
    317		dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
    318		dcs_cfg |= reg_l;
    319	}
    320
    321	/* Save the callibrated offset if we're in class W mode and
    322	 * therefore don't have any analogue signal mixed in. */
    323	if (wm_hubs_dac_hp_direct(component))
    324		wm_hubs_dcs_cache_set(component, dcs_cfg);
    325}
    326
    327/*
    328 * Update the DC servo calibration on gain changes
    329 */
    330static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
    331			       struct snd_ctl_elem_value *ucontrol)
    332{
    333	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    334	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    335	int ret;
    336
    337	ret = snd_soc_put_volsw(kcontrol, ucontrol);
    338
    339	/* If we're applying an offset correction then updating the
    340	 * callibration would be likely to introduce further offsets. */
    341	if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
    342		return ret;
    343
    344	/* Only need to do this if the outputs are active */
    345	if (snd_soc_component_read(component, WM8993_POWER_MANAGEMENT_1)
    346	    & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
    347		snd_soc_component_update_bits(component,
    348				    WM8993_DC_SERVO_0,
    349				    WM8993_DCS_TRIG_SINGLE_0 |
    350				    WM8993_DCS_TRIG_SINGLE_1,
    351				    WM8993_DCS_TRIG_SINGLE_0 |
    352				    WM8993_DCS_TRIG_SINGLE_1);
    353
    354	return ret;
    355}
    356
    357static const struct snd_kcontrol_new analogue_snd_controls[] = {
    358SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
    359	       inpga_tlv),
    360SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
    361SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
    362
    363SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
    364	       inpga_tlv),
    365SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
    366SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
    367
    368
    369SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
    370	       inpga_tlv),
    371SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
    372SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
    373
    374SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
    375	       inpga_tlv),
    376SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
    377SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
    378
    379SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
    380	       inmix_sw_tlv),
    381SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0,
    382	       inmix_sw_tlv),
    383SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0,
    384	       inmix_tlv),
    385SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv),
    386SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0,
    387	       inmix_tlv),
    388
    389SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0,
    390	       inmix_sw_tlv),
    391SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0,
    392	       inmix_sw_tlv),
    393SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0,
    394	       inmix_tlv),
    395SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv),
    396SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0,
    397	       inmix_tlv),
    398
    399SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1,
    400	       outmix_tlv),
    401SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1,
    402	       outmix_tlv),
    403SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1,
    404	       outmix_tlv),
    405SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1,
    406	       outmix_tlv),
    407SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1,
    408	       outmix_tlv),
    409SOC_SINGLE_TLV("Left Output Mixer Right Input Volume",
    410	       WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv),
    411SOC_SINGLE_TLV("Left Output Mixer Left Input Volume",
    412	       WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv),
    413SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1,
    414	       outmix_tlv),
    415
    416SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume",
    417	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
    418SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume",
    419	       WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv),
    420SOC_SINGLE_TLV("Right Output Mixer IN1L Volume",
    421	       WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv),
    422SOC_SINGLE_TLV("Right Output Mixer IN1R Volume",
    423	       WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv),
    424SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume",
    425	       WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv),
    426SOC_SINGLE_TLV("Right Output Mixer Left Input Volume",
    427	       WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv),
    428SOC_SINGLE_TLV("Right Output Mixer Right Input Volume",
    429	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
    430SOC_SINGLE_TLV("Right Output Mixer DAC Volume",
    431	       WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv),
    432
    433SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME,
    434		 WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv),
    435SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME,
    436	     WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0),
    437SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME,
    438	     WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0),
    439
    440SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1),
    441SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv),
    442
    443SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION,
    444	       5, 1, 1, wm_hubs_spkmix_tlv),
    445SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION,
    446	       4, 1, 1, wm_hubs_spkmix_tlv),
    447SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION,
    448	       3, 1, 1, wm_hubs_spkmix_tlv),
    449
    450SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION,
    451	       5, 1, 1, wm_hubs_spkmix_tlv),
    452SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION,
    453	       4, 1, 1, wm_hubs_spkmix_tlv),
    454SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION,
    455	       3, 1, 1, wm_hubs_spkmix_tlv),
    456
    457SOC_DOUBLE_R_TLV("Speaker Mixer Volume",
    458		 WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION,
    459		 0, 3, 1, spkmixout_tlv),
    460SOC_DOUBLE_R_TLV("Speaker Volume",
    461		 WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
    462		 0, 63, 0, outpga_tlv),
    463SOC_DOUBLE_R("Speaker Switch",
    464	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
    465	     6, 1, 0),
    466SOC_DOUBLE_R("Speaker ZC Switch",
    467	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
    468	     7, 1, 0),
    469SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
    470	       spkboost_tlv),
    471SOC_ENUM("Speaker Reference", speaker_ref),
    472SOC_ENUM("Speaker Mode", speaker_mode),
    473
    474SOC_DOUBLE_R_EXT_TLV("Headphone Volume",
    475		     WM8993_LEFT_OUTPUT_VOLUME, WM8993_RIGHT_OUTPUT_VOLUME,
    476		     0, 63, 0, snd_soc_get_volsw, wm8993_put_dc_servo,
    477		     outpga_tlv),
    478
    479SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
    480	     WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
    481SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
    482	     WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
    483
    484SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1),
    485SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1),
    486SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1,
    487	       line_tlv),
    488
    489SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1),
    490SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1),
    491SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
    492	       line_tlv),
    493};
    494
    495static int hp_supply_event(struct snd_soc_dapm_widget *w,
    496			   struct snd_kcontrol *kcontrol, int event)
    497{
    498	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    499	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    500
    501	switch (event) {
    502	case SND_SOC_DAPM_PRE_PMU:
    503		switch (hubs->hp_startup_mode) {
    504		case 0:
    505			break;
    506		case 1:
    507			/* Enable the headphone amp */
    508			snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
    509					    WM8993_HPOUT1L_ENA |
    510					    WM8993_HPOUT1R_ENA,
    511					    WM8993_HPOUT1L_ENA |
    512					    WM8993_HPOUT1R_ENA);
    513
    514			/* Enable the second stage */
    515			snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
    516					    WM8993_HPOUT1L_DLY |
    517					    WM8993_HPOUT1R_DLY,
    518					    WM8993_HPOUT1L_DLY |
    519					    WM8993_HPOUT1R_DLY);
    520			break;
    521		default:
    522			dev_err(component->dev, "Unknown HP startup mode %d\n",
    523				hubs->hp_startup_mode);
    524			break;
    525		}
    526		break;
    527
    528	case SND_SOC_DAPM_PRE_PMD:
    529		snd_soc_component_update_bits(component, WM8993_CHARGE_PUMP_1,
    530				    WM8993_CP_ENA, 0);
    531		break;
    532	}
    533
    534	return 0;
    535}
    536
    537static int hp_event(struct snd_soc_dapm_widget *w,
    538		    struct snd_kcontrol *kcontrol, int event)
    539{
    540	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    541	unsigned int reg = snd_soc_component_read(component, WM8993_ANALOGUE_HP_0);
    542
    543	switch (event) {
    544	case SND_SOC_DAPM_POST_PMU:
    545		snd_soc_component_update_bits(component, WM8993_CHARGE_PUMP_1,
    546				    WM8993_CP_ENA, WM8993_CP_ENA);
    547
    548		msleep(5);
    549
    550		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
    551				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
    552				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);
    553
    554		reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
    555		snd_soc_component_write(component, WM8993_ANALOGUE_HP_0, reg);
    556
    557		snd_soc_component_update_bits(component, WM8993_DC_SERVO_1,
    558				    WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
    559
    560		enable_dc_servo(component);
    561
    562		reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
    563			WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
    564		snd_soc_component_write(component, WM8993_ANALOGUE_HP_0, reg);
    565		break;
    566
    567	case SND_SOC_DAPM_PRE_PMD:
    568		snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
    569				    WM8993_HPOUT1L_OUTP |
    570				    WM8993_HPOUT1R_OUTP |
    571				    WM8993_HPOUT1L_RMV_SHORT |
    572				    WM8993_HPOUT1R_RMV_SHORT, 0);
    573
    574		snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
    575				    WM8993_HPOUT1L_DLY |
    576				    WM8993_HPOUT1R_DLY, 0);
    577
    578		snd_soc_component_write(component, WM8993_DC_SERVO_0, 0);
    579
    580		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
    581				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
    582				    0);
    583		break;
    584	}
    585
    586	return 0;
    587}
    588
    589static int earpiece_event(struct snd_soc_dapm_widget *w,
    590			  struct snd_kcontrol *control, int event)
    591{
    592	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    593	u16 reg = snd_soc_component_read(component, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
    594
    595	switch (event) {
    596	case SND_SOC_DAPM_PRE_PMU:
    597		reg |= WM8993_HPOUT2_IN_ENA;
    598		snd_soc_component_write(component, WM8993_ANTIPOP1, reg);
    599		udelay(50);
    600		break;
    601
    602	case SND_SOC_DAPM_POST_PMD:
    603		snd_soc_component_write(component, WM8993_ANTIPOP1, reg);
    604		break;
    605
    606	default:
    607		WARN(1, "Invalid event %d\n", event);
    608		break;
    609	}
    610
    611	return 0;
    612}
    613
    614static int lineout_event(struct snd_soc_dapm_widget *w,
    615			 struct snd_kcontrol *control, int event)
    616{
    617	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    618	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    619	bool *flag;
    620
    621	switch (w->shift) {
    622	case WM8993_LINEOUT1N_ENA_SHIFT:
    623		flag = &hubs->lineout1n_ena;
    624		break;
    625	case WM8993_LINEOUT1P_ENA_SHIFT:
    626		flag = &hubs->lineout1p_ena;
    627		break;
    628	case WM8993_LINEOUT2N_ENA_SHIFT:
    629		flag = &hubs->lineout2n_ena;
    630		break;
    631	case WM8993_LINEOUT2P_ENA_SHIFT:
    632		flag = &hubs->lineout2p_ena;
    633		break;
    634	default:
    635		WARN(1, "Unknown line output");
    636		return -EINVAL;
    637	}
    638
    639	*flag = SND_SOC_DAPM_EVENT_ON(event);
    640
    641	return 0;
    642}
    643
    644static int micbias_event(struct snd_soc_dapm_widget *w,
    645			 struct snd_kcontrol *kcontrol, int event)
    646{
    647	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    648	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    649
    650	switch (w->shift) {
    651	case WM8993_MICB1_ENA_SHIFT:
    652		if (hubs->micb1_delay)
    653			msleep(hubs->micb1_delay);
    654		break;
    655	case WM8993_MICB2_ENA_SHIFT:
    656		if (hubs->micb2_delay)
    657			msleep(hubs->micb2_delay);
    658		break;
    659	default:
    660		return -EINVAL;
    661	}
    662
    663	return 0;
    664}
    665
    666void wm_hubs_update_class_w(struct snd_soc_component *component)
    667{
    668	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
    669	int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;
    670
    671	if (!wm_hubs_dac_hp_direct(component))
    672		enable = false;
    673
    674	if (hubs->check_class_w_digital && !hubs->check_class_w_digital(component))
    675		enable = false;
    676
    677	dev_vdbg(component->dev, "Class W %s\n", enable ? "enabled" : "disabled");
    678
    679	snd_soc_component_update_bits(component, WM8993_CLASS_W_0,
    680			    WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
    681
    682	snd_soc_component_write(component, WM8993_LEFT_OUTPUT_VOLUME,
    683		      snd_soc_component_read(component, WM8993_LEFT_OUTPUT_VOLUME));
    684	snd_soc_component_write(component, WM8993_RIGHT_OUTPUT_VOLUME,
    685		      snd_soc_component_read(component, WM8993_RIGHT_OUTPUT_VOLUME));
    686}
    687EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
    688
    689#define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
    690	SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
    691		snd_soc_dapm_get_volsw, class_w_put_volsw)
    692
    693static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
    694			      struct snd_ctl_elem_value *ucontrol)
    695{
    696	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
    697	int ret;
    698
    699	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
    700
    701	wm_hubs_update_class_w(component);
    702
    703	return ret;
    704}
    705
    706#define WM_HUBS_ENUM_W(xname, xenum) \
    707{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
    708	.info = snd_soc_info_enum_double, \
    709	.get = snd_soc_dapm_get_enum_double, \
    710	.put = class_w_put_double, \
    711	.private_value = (unsigned long)&xenum }
    712
    713static int class_w_put_double(struct snd_kcontrol *kcontrol,
    714			      struct snd_ctl_elem_value *ucontrol)
    715{
    716	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
    717	int ret;
    718
    719	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
    720
    721	wm_hubs_update_class_w(component);
    722
    723	return ret;
    724}
    725
    726static const char *hp_mux_text[] = {
    727	"Mixer",
    728	"DAC",
    729};
    730
    731static SOC_ENUM_SINGLE_DECL(hpl_enum,
    732			    WM8993_OUTPUT_MIXER1, 8, hp_mux_text);
    733
    734const struct snd_kcontrol_new wm_hubs_hpl_mux =
    735	WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
    736EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
    737
    738static SOC_ENUM_SINGLE_DECL(hpr_enum,
    739			    WM8993_OUTPUT_MIXER2, 8, hp_mux_text);
    740
    741const struct snd_kcontrol_new wm_hubs_hpr_mux =
    742	WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
    743EXPORT_SYMBOL_GPL(wm_hubs_hpr_mux);
    744
    745static const struct snd_kcontrol_new in1l_pga[] = {
    746SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
    747SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
    748};
    749
    750static const struct snd_kcontrol_new in1r_pga[] = {
    751SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0),
    752SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0),
    753};
    754
    755static const struct snd_kcontrol_new in2l_pga[] = {
    756SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0),
    757SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0),
    758};
    759
    760static const struct snd_kcontrol_new in2r_pga[] = {
    761SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0),
    762SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0),
    763};
    764
    765static const struct snd_kcontrol_new mixinl[] = {
    766SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0),
    767SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0),
    768};
    769
    770static const struct snd_kcontrol_new mixinr[] = {
    771SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0),
    772SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
    773};
    774
    775static const struct snd_kcontrol_new left_output_mixer[] = {
    776WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
    777WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
    778WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
    779WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
    780WM_HUBS_SINGLE_W("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
    781WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
    782WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
    783WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
    784};
    785
    786static const struct snd_kcontrol_new right_output_mixer[] = {
    787WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
    788WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
    789WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
    790WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
    791WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
    792WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
    793WM_HUBS_SINGLE_W("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
    794WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
    795};
    796
    797static const struct snd_kcontrol_new earpiece_mixer[] = {
    798SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0),
    799SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0),
    800SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0),
    801};
    802
    803static const struct snd_kcontrol_new left_speaker_boost[] = {
    804SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0),
    805SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0),
    806SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0),
    807};
    808
    809static const struct snd_kcontrol_new right_speaker_boost[] = {
    810SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0),
    811SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0),
    812SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0),
    813};
    814
    815static const struct snd_kcontrol_new line1_mix[] = {
    816SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0),
    817SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0),
    818SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
    819};
    820
    821static const struct snd_kcontrol_new line1n_mix[] = {
    822SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0),
    823SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0),
    824};
    825
    826static const struct snd_kcontrol_new line1p_mix[] = {
    827SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
    828};
    829
    830static const struct snd_kcontrol_new line2_mix[] = {
    831SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0),
    832SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0),
    833SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
    834};
    835
    836static const struct snd_kcontrol_new line2n_mix[] = {
    837SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
    838SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
    839};
    840
    841static const struct snd_kcontrol_new line2p_mix[] = {
    842SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
    843};
    844
    845static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = {
    846SND_SOC_DAPM_INPUT("IN1LN"),
    847SND_SOC_DAPM_INPUT("IN1LP"),
    848SND_SOC_DAPM_INPUT("IN2LN"),
    849SND_SOC_DAPM_INPUT("IN2LP:VXRN"),
    850SND_SOC_DAPM_INPUT("IN1RN"),
    851SND_SOC_DAPM_INPUT("IN1RP"),
    852SND_SOC_DAPM_INPUT("IN2RN"),
    853SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
    854
    855SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0,
    856		    micbias_event, SND_SOC_DAPM_POST_PMU),
    857SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0,
    858		    micbias_event, SND_SOC_DAPM_POST_PMU),
    859
    860SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
    861		   in1l_pga, ARRAY_SIZE(in1l_pga)),
    862SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
    863		   in1r_pga, ARRAY_SIZE(in1r_pga)),
    864
    865SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
    866		   in2l_pga, ARRAY_SIZE(in2l_pga)),
    867SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
    868		   in2r_pga, ARRAY_SIZE(in2r_pga)),
    869
    870SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
    871		   mixinl, ARRAY_SIZE(mixinl)),
    872SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
    873		   mixinr, ARRAY_SIZE(mixinr)),
    874
    875SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0,
    876		   left_output_mixer, ARRAY_SIZE(left_output_mixer)),
    877SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
    878		   right_output_mixer, ARRAY_SIZE(right_output_mixer)),
    879
    880SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
    881SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
    882
    883SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event, 
    884		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
    885SND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
    886		       hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    887
    888SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
    889		   earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
    890SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0,
    891		   NULL, 0, earpiece_event,
    892		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
    893
    894SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
    895		   left_speaker_boost, ARRAY_SIZE(left_speaker_boost)),
    896SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
    897		   right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
    898
    899SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
    900SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
    901		     NULL, 0),
    902SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
    903		     NULL, 0),
    904
    905SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
    906		   line1_mix, ARRAY_SIZE(line1_mix)),
    907SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
    908		   line2_mix, ARRAY_SIZE(line2_mix)),
    909
    910SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0,
    911		   line1n_mix, ARRAY_SIZE(line1n_mix)),
    912SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0,
    913		   line1p_mix, ARRAY_SIZE(line1p_mix)),
    914SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
    915		   line2n_mix, ARRAY_SIZE(line2n_mix)),
    916SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
    917		   line2p_mix, ARRAY_SIZE(line2p_mix)),
    918
    919SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
    920		       NULL, 0, lineout_event,
    921		     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    922SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
    923		       NULL, 0, lineout_event,
    924		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    925SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
    926		       NULL, 0, lineout_event,
    927		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    928SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
    929		       NULL, 0, lineout_event,
    930		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    931
    932SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
    933SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
    934SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
    935SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
    936SND_SOC_DAPM_OUTPUT("HPOUT1L"),
    937SND_SOC_DAPM_OUTPUT("HPOUT1R"),
    938SND_SOC_DAPM_OUTPUT("HPOUT2P"),
    939SND_SOC_DAPM_OUTPUT("HPOUT2N"),
    940SND_SOC_DAPM_OUTPUT("LINEOUT1P"),
    941SND_SOC_DAPM_OUTPUT("LINEOUT1N"),
    942SND_SOC_DAPM_OUTPUT("LINEOUT2P"),
    943SND_SOC_DAPM_OUTPUT("LINEOUT2N"),
    944};
    945
    946static const struct snd_soc_dapm_route analogue_routes[] = {
    947	{ "MICBIAS1", NULL, "CLK_SYS" },
    948	{ "MICBIAS2", NULL, "CLK_SYS" },
    949
    950	{ "IN1L PGA", "IN1LP Switch", "IN1LP" },
    951	{ "IN1L PGA", "IN1LN Switch", "IN1LN" },
    952
    953	{ "IN1L PGA", NULL, "VMID" },
    954	{ "IN1R PGA", NULL, "VMID" },
    955	{ "IN2L PGA", NULL, "VMID" },
    956	{ "IN2R PGA", NULL, "VMID" },
    957
    958	{ "IN1R PGA", "IN1RP Switch", "IN1RP" },
    959	{ "IN1R PGA", "IN1RN Switch", "IN1RN" },
    960
    961	{ "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" },
    962	{ "IN2L PGA", "IN2LN Switch", "IN2LN" },
    963
    964	{ "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" },
    965	{ "IN2R PGA", "IN2RN Switch", "IN2RN" },
    966
    967	{ "Direct Voice", NULL, "IN2LP:VXRN" },
    968	{ "Direct Voice", NULL, "IN2RP:VXRP" },
    969
    970	{ "MIXINL", "IN1L Switch", "IN1L PGA" },
    971	{ "MIXINL", "IN2L Switch", "IN2L PGA" },
    972	{ "MIXINL", NULL, "Direct Voice" },
    973	{ "MIXINL", NULL, "IN1LP" },
    974	{ "MIXINL", NULL, "Left Output Mixer" },
    975	{ "MIXINL", NULL, "VMID" },
    976
    977	{ "MIXINR", "IN1R Switch", "IN1R PGA" },
    978	{ "MIXINR", "IN2R Switch", "IN2R PGA" },
    979	{ "MIXINR", NULL, "Direct Voice" },
    980	{ "MIXINR", NULL, "IN1RP" },
    981	{ "MIXINR", NULL, "Right Output Mixer" },
    982	{ "MIXINR", NULL, "VMID" },
    983
    984	{ "ADCL", NULL, "MIXINL" },
    985	{ "ADCR", NULL, "MIXINR" },
    986
    987	{ "Left Output Mixer", "Left Input Switch", "MIXINL" },
    988	{ "Left Output Mixer", "Right Input Switch", "MIXINR" },
    989	{ "Left Output Mixer", "IN2RN Switch", "IN2RN" },
    990	{ "Left Output Mixer", "IN2LN Switch", "IN2LN" },
    991	{ "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" },
    992	{ "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
    993	{ "Left Output Mixer", "IN1R Switch", "IN1R PGA" },
    994
    995	{ "Right Output Mixer", "Left Input Switch", "MIXINL" },
    996	{ "Right Output Mixer", "Right Input Switch", "MIXINR" },
    997	{ "Right Output Mixer", "IN2LN Switch", "IN2LN" },
    998	{ "Right Output Mixer", "IN2RN Switch", "IN2RN" },
    999	{ "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" },
   1000	{ "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
   1001	{ "Right Output Mixer", "IN1R Switch", "IN1R PGA" },
   1002
   1003	{ "Left Output PGA", NULL, "Left Output Mixer" },
   1004	{ "Left Output PGA", NULL, "TOCLK" },
   1005
   1006	{ "Right Output PGA", NULL, "Right Output Mixer" },
   1007	{ "Right Output PGA", NULL, "TOCLK" },
   1008
   1009	{ "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" },
   1010	{ "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
   1011	{ "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },
   1012
   1013	{ "Earpiece Driver", NULL, "VMID" },
   1014	{ "Earpiece Driver", NULL, "Earpiece Mixer" },
   1015	{ "HPOUT2N", NULL, "Earpiece Driver" },
   1016	{ "HPOUT2P", NULL, "Earpiece Driver" },
   1017
   1018	{ "SPKL", "Input Switch", "MIXINL" },
   1019	{ "SPKL", "IN1LP Switch", "IN1LP" },
   1020	{ "SPKL", "Output Switch", "Left Output PGA" },
   1021	{ "SPKL", NULL, "TOCLK" },
   1022
   1023	{ "SPKR", "Input Switch", "MIXINR" },
   1024	{ "SPKR", "IN1RP Switch", "IN1RP" },
   1025	{ "SPKR", "Output Switch", "Right Output PGA" },
   1026	{ "SPKR", NULL, "TOCLK" },
   1027
   1028	{ "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
   1029	{ "SPKL Boost", "SPKL Switch", "SPKL" },
   1030	{ "SPKL Boost", "SPKR Switch", "SPKR" },
   1031
   1032	{ "SPKR Boost", "Direct Voice Switch", "Direct Voice" },
   1033	{ "SPKR Boost", "SPKR Switch", "SPKR" },
   1034	{ "SPKR Boost", "SPKL Switch", "SPKL" },
   1035
   1036	{ "SPKL Driver", NULL, "VMID" },
   1037	{ "SPKL Driver", NULL, "SPKL Boost" },
   1038	{ "SPKL Driver", NULL, "CLK_SYS" },
   1039	{ "SPKL Driver", NULL, "TSHUT" },
   1040
   1041	{ "SPKR Driver", NULL, "VMID" },
   1042	{ "SPKR Driver", NULL, "SPKR Boost" },
   1043	{ "SPKR Driver", NULL, "CLK_SYS" },
   1044	{ "SPKR Driver", NULL, "TSHUT" },
   1045
   1046	{ "SPKOUTLP", NULL, "SPKL Driver" },
   1047	{ "SPKOUTLN", NULL, "SPKL Driver" },
   1048	{ "SPKOUTRP", NULL, "SPKR Driver" },
   1049	{ "SPKOUTRN", NULL, "SPKR Driver" },
   1050
   1051	{ "Left Headphone Mux", "Mixer", "Left Output PGA" },
   1052	{ "Right Headphone Mux", "Mixer", "Right Output PGA" },
   1053
   1054	{ "Headphone PGA", NULL, "Left Headphone Mux" },
   1055	{ "Headphone PGA", NULL, "Right Headphone Mux" },
   1056	{ "Headphone PGA", NULL, "VMID" },
   1057	{ "Headphone PGA", NULL, "CLK_SYS" },
   1058	{ "Headphone PGA", NULL, "Headphone Supply" },
   1059
   1060	{ "HPOUT1L", NULL, "Headphone PGA" },
   1061	{ "HPOUT1R", NULL, "Headphone PGA" },
   1062
   1063	{ "LINEOUT1N Driver", NULL, "VMID" },
   1064	{ "LINEOUT1P Driver", NULL, "VMID" },
   1065	{ "LINEOUT2N Driver", NULL, "VMID" },
   1066	{ "LINEOUT2P Driver", NULL, "VMID" },
   1067
   1068	{ "LINEOUT1N", NULL, "LINEOUT1N Driver" },
   1069	{ "LINEOUT1P", NULL, "LINEOUT1P Driver" },
   1070	{ "LINEOUT2N", NULL, "LINEOUT2N Driver" },
   1071	{ "LINEOUT2P", NULL, "LINEOUT2P Driver" },
   1072};
   1073
   1074static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
   1075	{ "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
   1076	{ "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
   1077	{ "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" },
   1078
   1079	{ "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
   1080	{ "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
   1081};
   1082
   1083static const struct snd_soc_dapm_route lineout1_se_routes[] = {
   1084	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
   1085	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
   1086
   1087	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
   1088
   1089	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
   1090	{ "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
   1091};
   1092
   1093static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
   1094	{ "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" },
   1095	{ "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" },
   1096	{ "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
   1097
   1098	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
   1099	{ "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
   1100};
   1101
   1102static const struct snd_soc_dapm_route lineout2_se_routes[] = {
   1103	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
   1104	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
   1105
   1106	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
   1107
   1108	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
   1109	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
   1110};
   1111
   1112int wm_hubs_add_analogue_controls(struct snd_soc_component *component)
   1113{
   1114	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
   1115
   1116	/* Latch volume update bits & default ZC on */
   1117	snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
   1118			    WM8993_IN1_VU, WM8993_IN1_VU);
   1119	snd_soc_component_update_bits(component, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
   1120			    WM8993_IN1_VU, WM8993_IN1_VU);
   1121	snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
   1122			    WM8993_IN2_VU, WM8993_IN2_VU);
   1123	snd_soc_component_update_bits(component, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
   1124			    WM8993_IN2_VU, WM8993_IN2_VU);
   1125
   1126	snd_soc_component_update_bits(component, WM8993_SPEAKER_VOLUME_LEFT,
   1127			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
   1128	snd_soc_component_update_bits(component, WM8993_SPEAKER_VOLUME_RIGHT,
   1129			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
   1130
   1131	snd_soc_component_update_bits(component, WM8993_LEFT_OUTPUT_VOLUME,
   1132			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
   1133			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
   1134	snd_soc_component_update_bits(component, WM8993_RIGHT_OUTPUT_VOLUME,
   1135			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
   1136			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
   1137
   1138	snd_soc_component_update_bits(component, WM8993_LEFT_OPGA_VOLUME,
   1139			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
   1140			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
   1141	snd_soc_component_update_bits(component, WM8993_RIGHT_OPGA_VOLUME,
   1142			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
   1143			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
   1144
   1145	snd_soc_add_component_controls(component, analogue_snd_controls,
   1146			     ARRAY_SIZE(analogue_snd_controls));
   1147
   1148	snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
   1149				  ARRAY_SIZE(analogue_dapm_widgets));
   1150	return 0;
   1151}
   1152EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);
   1153
   1154int wm_hubs_add_analogue_routes(struct snd_soc_component *component,
   1155				int lineout1_diff, int lineout2_diff)
   1156{
   1157	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
   1158	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
   1159
   1160	hubs->component = component;
   1161
   1162	INIT_LIST_HEAD(&hubs->dcs_cache);
   1163	init_completion(&hubs->dcs_done);
   1164
   1165	snd_soc_dapm_add_routes(dapm, analogue_routes,
   1166				ARRAY_SIZE(analogue_routes));
   1167
   1168	if (lineout1_diff)
   1169		snd_soc_dapm_add_routes(dapm,
   1170					lineout1_diff_routes,
   1171					ARRAY_SIZE(lineout1_diff_routes));
   1172	else
   1173		snd_soc_dapm_add_routes(dapm,
   1174					lineout1_se_routes,
   1175					ARRAY_SIZE(lineout1_se_routes));
   1176
   1177	if (lineout2_diff)
   1178		snd_soc_dapm_add_routes(dapm,
   1179					lineout2_diff_routes,
   1180					ARRAY_SIZE(lineout2_diff_routes));
   1181	else
   1182		snd_soc_dapm_add_routes(dapm,
   1183					lineout2_se_routes,
   1184					ARRAY_SIZE(lineout2_se_routes));
   1185
   1186	return 0;
   1187}
   1188EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
   1189
   1190int wm_hubs_handle_analogue_pdata(struct snd_soc_component *component,
   1191				  int lineout1_diff, int lineout2_diff,
   1192				  int lineout1fb, int lineout2fb,
   1193				  int jd_scthr, int jd_thr,
   1194				  int micbias1_delay, int micbias2_delay,
   1195				  int micbias1_lvl, int micbias2_lvl)
   1196{
   1197	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
   1198
   1199	hubs->lineout1_se = !lineout1_diff;
   1200	hubs->lineout2_se = !lineout2_diff;
   1201	hubs->micb1_delay = micbias1_delay;
   1202	hubs->micb2_delay = micbias2_delay;
   1203
   1204	if (!lineout1_diff)
   1205		snd_soc_component_update_bits(component, WM8993_LINE_MIXER1,
   1206				    WM8993_LINEOUT1_MODE,
   1207				    WM8993_LINEOUT1_MODE);
   1208	if (!lineout2_diff)
   1209		snd_soc_component_update_bits(component, WM8993_LINE_MIXER2,
   1210				    WM8993_LINEOUT2_MODE,
   1211				    WM8993_LINEOUT2_MODE);
   1212
   1213	if (!lineout1_diff && !lineout2_diff)
   1214		snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
   1215				    WM8993_LINEOUT_VMID_BUF_ENA,
   1216				    WM8993_LINEOUT_VMID_BUF_ENA);
   1217
   1218	if (lineout1fb)
   1219		snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
   1220				    WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
   1221
   1222	if (lineout2fb)
   1223		snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
   1224				    WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
   1225
   1226	if (!hubs->micd_scthr)
   1227		return 0;
   1228
   1229	snd_soc_component_update_bits(component, WM8993_MICBIAS,
   1230			    WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
   1231			    WM8993_MICB1_LVL | WM8993_MICB2_LVL,
   1232			    jd_scthr << WM8993_JD_SCTHR_SHIFT |
   1233			    jd_thr << WM8993_JD_THR_SHIFT |
   1234			    micbias1_lvl |
   1235			    micbias2_lvl << WM8993_MICB2_LVL_SHIFT);
   1236
   1237	return 0;
   1238}
   1239EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
   1240
   1241void wm_hubs_vmid_ena(struct snd_soc_component *component)
   1242{
   1243	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
   1244	int val = 0;
   1245
   1246	if (hubs->lineout1_se)
   1247		val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
   1248
   1249	if (hubs->lineout2_se)
   1250		val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
   1251
   1252	/* Enable the line outputs while we power up */
   1253	snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_3, val, val);
   1254}
   1255EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);
   1256
   1257void wm_hubs_set_bias_level(struct snd_soc_component *component,
   1258			    enum snd_soc_bias_level level)
   1259{
   1260	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
   1261	int mask, val;
   1262
   1263	switch (level) {
   1264	case SND_SOC_BIAS_STANDBY:
   1265		/* Clamp the inputs to VMID while we ramp to charge caps */
   1266		snd_soc_component_update_bits(component, WM8993_INPUTS_CLAMP_REG,
   1267				    WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP);
   1268		break;
   1269
   1270	case SND_SOC_BIAS_ON:
   1271		/* Turn off any unneeded single ended outputs */
   1272		val = 0;
   1273		mask = 0;
   1274
   1275		if (hubs->lineout1_se)
   1276			mask |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
   1277
   1278		if (hubs->lineout2_se)
   1279			mask |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
   1280
   1281		if (hubs->lineout1_se && hubs->lineout1n_ena)
   1282			val |= WM8993_LINEOUT1N_ENA;
   1283
   1284		if (hubs->lineout1_se && hubs->lineout1p_ena)
   1285			val |= WM8993_LINEOUT1P_ENA;
   1286
   1287		if (hubs->lineout2_se && hubs->lineout2n_ena)
   1288			val |= WM8993_LINEOUT2N_ENA;
   1289
   1290		if (hubs->lineout2_se && hubs->lineout2p_ena)
   1291			val |= WM8993_LINEOUT2P_ENA;
   1292
   1293		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_3,
   1294				    mask, val);
   1295
   1296		/* Remove the input clamps */
   1297		snd_soc_component_update_bits(component, WM8993_INPUTS_CLAMP_REG,
   1298				    WM8993_INPUTS_CLAMP, 0);
   1299		break;
   1300
   1301	default:
   1302		break;
   1303	}
   1304}
   1305EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level);
   1306
   1307MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
   1308MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
   1309MODULE_LICENSE("GPL");