18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * wm_hubs.c  --  WM8993/4 common code
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2009-12 Wolfson Microelectronics plc
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/pm.h>
158c2ecf20Sopenharmony_ci#include <linux/i2c.h>
168c2ecf20Sopenharmony_ci#include <linux/mfd/wm8994/registers.h>
178c2ecf20Sopenharmony_ci#include <sound/core.h>
188c2ecf20Sopenharmony_ci#include <sound/pcm.h>
198c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
208c2ecf20Sopenharmony_ci#include <sound/soc.h>
218c2ecf20Sopenharmony_ci#include <sound/initval.h>
228c2ecf20Sopenharmony_ci#include <sound/tlv.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "wm8993.h"
258c2ecf20Sopenharmony_ci#include "wm_hubs.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciconst DECLARE_TLV_DB_SCALE(wm_hubs_spkmix_tlv, -300, 300, 0);
288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_spkmix_tlv);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0);
318c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0);
328c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1);
338c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
348c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
358c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
368c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
378c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(spkboost_tlv,
388c2ecf20Sopenharmony_ci	0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
398c2ecf20Sopenharmony_ci	7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
408c2ecf20Sopenharmony_ci);
418c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic const char *speaker_ref_text[] = {
448c2ecf20Sopenharmony_ci	"SPKVDD/2",
458c2ecf20Sopenharmony_ci	"VMID",
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(speaker_ref,
498c2ecf20Sopenharmony_ci			    WM8993_SPEAKER_MIXER, 8, speaker_ref_text);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const char *speaker_mode_text[] = {
528c2ecf20Sopenharmony_ci	"Class D",
538c2ecf20Sopenharmony_ci	"Class AB",
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(speaker_mode,
578c2ecf20Sopenharmony_ci			    WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic void wait_for_dc_servo(struct snd_soc_component *component, unsigned int op)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
628c2ecf20Sopenharmony_ci	unsigned int reg;
638c2ecf20Sopenharmony_ci	int count = 0;
648c2ecf20Sopenharmony_ci	int timeout;
658c2ecf20Sopenharmony_ci	unsigned int val;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* Trigger the command */
708c2ecf20Sopenharmony_ci	snd_soc_component_write(component, WM8993_DC_SERVO_0, val);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	dev_dbg(component->dev, "Waiting for DC servo...\n");
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (hubs->dcs_done_irq)
758c2ecf20Sopenharmony_ci		timeout = 4;
768c2ecf20Sopenharmony_ci	else
778c2ecf20Sopenharmony_ci		timeout = 400;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	do {
808c2ecf20Sopenharmony_ci		count++;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci		if (hubs->dcs_done_irq)
838c2ecf20Sopenharmony_ci			wait_for_completion_timeout(&hubs->dcs_done,
848c2ecf20Sopenharmony_ci						    msecs_to_jiffies(250));
858c2ecf20Sopenharmony_ci		else
868c2ecf20Sopenharmony_ci			msleep(1);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		reg = snd_soc_component_read(component, WM8993_DC_SERVO_0);
898c2ecf20Sopenharmony_ci		dev_dbg(component->dev, "DC servo: %x\n", reg);
908c2ecf20Sopenharmony_ci	} while (reg & op && count < timeout);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (reg & op)
938c2ecf20Sopenharmony_ci		dev_err(component->dev, "Timed out waiting for DC Servo %x\n",
948c2ecf20Sopenharmony_ci			op);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciirqreturn_t wm_hubs_dcs_done(int irq, void *data)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = data;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	complete(&hubs->dcs_done);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic bool wm_hubs_dac_hp_direct(struct snd_soc_component *component)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	int reg;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* If we're going via the mixer we'll need to do additional checks */
1128c2ecf20Sopenharmony_ci	reg = snd_soc_component_read(component, WM8993_OUTPUT_MIXER1);
1138c2ecf20Sopenharmony_ci	if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
1148c2ecf20Sopenharmony_ci		if (reg & ~WM8993_DACL_TO_MIXOUTL) {
1158c2ecf20Sopenharmony_ci			dev_vdbg(component->dev, "Analogue paths connected: %x\n",
1168c2ecf20Sopenharmony_ci				 reg & ~WM8993_DACL_TO_HPOUT1L);
1178c2ecf20Sopenharmony_ci			return false;
1188c2ecf20Sopenharmony_ci		} else {
1198c2ecf20Sopenharmony_ci			dev_vdbg(component->dev, "HPL connected to mixer\n");
1208c2ecf20Sopenharmony_ci		}
1218c2ecf20Sopenharmony_ci	} else {
1228c2ecf20Sopenharmony_ci		dev_vdbg(component->dev, "HPL connected to DAC\n");
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	reg = snd_soc_component_read(component, WM8993_OUTPUT_MIXER2);
1268c2ecf20Sopenharmony_ci	if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
1278c2ecf20Sopenharmony_ci		if (reg & ~WM8993_DACR_TO_MIXOUTR) {
1288c2ecf20Sopenharmony_ci			dev_vdbg(component->dev, "Analogue paths connected: %x\n",
1298c2ecf20Sopenharmony_ci				 reg & ~WM8993_DACR_TO_HPOUT1R);
1308c2ecf20Sopenharmony_ci			return false;
1318c2ecf20Sopenharmony_ci		} else {
1328c2ecf20Sopenharmony_ci			dev_vdbg(component->dev, "HPR connected to mixer\n");
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci	} else {
1358c2ecf20Sopenharmony_ci		dev_vdbg(component->dev, "HPR connected to DAC\n");
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return true;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistruct wm_hubs_dcs_cache {
1428c2ecf20Sopenharmony_ci	struct list_head list;
1438c2ecf20Sopenharmony_ci	unsigned int left;
1448c2ecf20Sopenharmony_ci	unsigned int right;
1458c2ecf20Sopenharmony_ci	u16 dcs_cfg;
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic bool wm_hubs_dcs_cache_get(struct snd_soc_component *component,
1498c2ecf20Sopenharmony_ci				  struct wm_hubs_dcs_cache **entry)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
1528c2ecf20Sopenharmony_ci	struct wm_hubs_dcs_cache *cache;
1538c2ecf20Sopenharmony_ci	unsigned int left, right;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	left = snd_soc_component_read(component, WM8993_LEFT_OUTPUT_VOLUME);
1568c2ecf20Sopenharmony_ci	left &= WM8993_HPOUT1L_VOL_MASK;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	right = snd_soc_component_read(component, WM8993_RIGHT_OUTPUT_VOLUME);
1598c2ecf20Sopenharmony_ci	right &= WM8993_HPOUT1R_VOL_MASK;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	list_for_each_entry(cache, &hubs->dcs_cache, list) {
1628c2ecf20Sopenharmony_ci		if (cache->left != left || cache->right != right)
1638c2ecf20Sopenharmony_ci			continue;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		*entry = cache;
1668c2ecf20Sopenharmony_ci		return true;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	return false;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic void wm_hubs_dcs_cache_set(struct snd_soc_component *component, u16 dcs_cfg)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
1758c2ecf20Sopenharmony_ci	struct wm_hubs_dcs_cache *cache;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (hubs->no_cache_dac_hp_direct)
1788c2ecf20Sopenharmony_ci		return;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	cache = devm_kzalloc(component->dev, sizeof(*cache), GFP_KERNEL);
1818c2ecf20Sopenharmony_ci	if (!cache)
1828c2ecf20Sopenharmony_ci		return;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	cache->left = snd_soc_component_read(component, WM8993_LEFT_OUTPUT_VOLUME);
1858c2ecf20Sopenharmony_ci	cache->left &= WM8993_HPOUT1L_VOL_MASK;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	cache->right = snd_soc_component_read(component, WM8993_RIGHT_OUTPUT_VOLUME);
1888c2ecf20Sopenharmony_ci	cache->right &= WM8993_HPOUT1R_VOL_MASK;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	cache->dcs_cfg = dcs_cfg;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	list_add_tail(&cache->list, &hubs->dcs_cache);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int wm_hubs_read_dc_servo(struct snd_soc_component *component,
1968c2ecf20Sopenharmony_ci				  u16 *reg_l, u16 *reg_r)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
1998c2ecf20Sopenharmony_ci	u16 dcs_reg, reg;
2008c2ecf20Sopenharmony_ci	int ret = 0;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	switch (hubs->dcs_readback_mode) {
2038c2ecf20Sopenharmony_ci	case 2:
2048c2ecf20Sopenharmony_ci		dcs_reg = WM8994_DC_SERVO_4E;
2058c2ecf20Sopenharmony_ci		break;
2068c2ecf20Sopenharmony_ci	case 1:
2078c2ecf20Sopenharmony_ci		dcs_reg = WM8994_DC_SERVO_READBACK;
2088c2ecf20Sopenharmony_ci		break;
2098c2ecf20Sopenharmony_ci	default:
2108c2ecf20Sopenharmony_ci		dcs_reg = WM8993_DC_SERVO_3;
2118c2ecf20Sopenharmony_ci		break;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/* Different chips in the family support different readback
2158c2ecf20Sopenharmony_ci	 * methods.
2168c2ecf20Sopenharmony_ci	 */
2178c2ecf20Sopenharmony_ci	switch (hubs->dcs_readback_mode) {
2188c2ecf20Sopenharmony_ci	case 0:
2198c2ecf20Sopenharmony_ci		*reg_l = snd_soc_component_read(component, WM8993_DC_SERVO_READBACK_1)
2208c2ecf20Sopenharmony_ci			& WM8993_DCS_INTEG_CHAN_0_MASK;
2218c2ecf20Sopenharmony_ci		*reg_r = snd_soc_component_read(component, WM8993_DC_SERVO_READBACK_2)
2228c2ecf20Sopenharmony_ci			& WM8993_DCS_INTEG_CHAN_1_MASK;
2238c2ecf20Sopenharmony_ci		break;
2248c2ecf20Sopenharmony_ci	case 2:
2258c2ecf20Sopenharmony_ci	case 1:
2268c2ecf20Sopenharmony_ci		reg = snd_soc_component_read(component, dcs_reg);
2278c2ecf20Sopenharmony_ci		*reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
2288c2ecf20Sopenharmony_ci			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
2298c2ecf20Sopenharmony_ci		*reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
2308c2ecf20Sopenharmony_ci		break;
2318c2ecf20Sopenharmony_ci	default:
2328c2ecf20Sopenharmony_ci		WARN(1, "Unknown DCS readback method\n");
2338c2ecf20Sopenharmony_ci		ret = -1;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	return ret;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci/*
2398c2ecf20Sopenharmony_ci * Startup calibration of the DC servo
2408c2ecf20Sopenharmony_ci */
2418c2ecf20Sopenharmony_cistatic void enable_dc_servo(struct snd_soc_component *component)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
2448c2ecf20Sopenharmony_ci	struct wm_hubs_dcs_cache *cache;
2458c2ecf20Sopenharmony_ci	s8 offset;
2468c2ecf20Sopenharmony_ci	u16 reg_l, reg_r, dcs_cfg, dcs_reg;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	switch (hubs->dcs_readback_mode) {
2498c2ecf20Sopenharmony_ci	case 2:
2508c2ecf20Sopenharmony_ci		dcs_reg = WM8994_DC_SERVO_4E;
2518c2ecf20Sopenharmony_ci		break;
2528c2ecf20Sopenharmony_ci	default:
2538c2ecf20Sopenharmony_ci		dcs_reg = WM8993_DC_SERVO_3;
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* If we're using a digital only path and have a previously
2588c2ecf20Sopenharmony_ci	 * callibrated DC servo offset stored then use that. */
2598c2ecf20Sopenharmony_ci	if (wm_hubs_dac_hp_direct(component) &&
2608c2ecf20Sopenharmony_ci	    wm_hubs_dcs_cache_get(component, &cache)) {
2618c2ecf20Sopenharmony_ci		dev_dbg(component->dev, "Using cached DCS offset %x for %d,%d\n",
2628c2ecf20Sopenharmony_ci			cache->dcs_cfg, cache->left, cache->right);
2638c2ecf20Sopenharmony_ci		snd_soc_component_write(component, dcs_reg, cache->dcs_cfg);
2648c2ecf20Sopenharmony_ci		wait_for_dc_servo(component,
2658c2ecf20Sopenharmony_ci				  WM8993_DCS_TRIG_DAC_WR_0 |
2668c2ecf20Sopenharmony_ci				  WM8993_DCS_TRIG_DAC_WR_1);
2678c2ecf20Sopenharmony_ci		return;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (hubs->series_startup) {
2718c2ecf20Sopenharmony_ci		/* Set for 32 series updates */
2728c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_DC_SERVO_1,
2738c2ecf20Sopenharmony_ci				    WM8993_DCS_SERIES_NO_01_MASK,
2748c2ecf20Sopenharmony_ci				    32 << WM8993_DCS_SERIES_NO_01_SHIFT);
2758c2ecf20Sopenharmony_ci		wait_for_dc_servo(component,
2768c2ecf20Sopenharmony_ci				  WM8993_DCS_TRIG_SERIES_0 |
2778c2ecf20Sopenharmony_ci				  WM8993_DCS_TRIG_SERIES_1);
2788c2ecf20Sopenharmony_ci	} else {
2798c2ecf20Sopenharmony_ci		wait_for_dc_servo(component,
2808c2ecf20Sopenharmony_ci				  WM8993_DCS_TRIG_STARTUP_0 |
2818c2ecf20Sopenharmony_ci				  WM8993_DCS_TRIG_STARTUP_1);
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (wm_hubs_read_dc_servo(component, &reg_l, &reg_r) < 0)
2858c2ecf20Sopenharmony_ci		return;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	dev_dbg(component->dev, "DCS input: %x %x\n", reg_l, reg_r);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* Apply correction to DC servo result */
2908c2ecf20Sopenharmony_ci	if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
2918c2ecf20Sopenharmony_ci		dev_dbg(component->dev,
2928c2ecf20Sopenharmony_ci			"Applying %d/%d code DC servo correction\n",
2938c2ecf20Sopenharmony_ci			hubs->dcs_codes_l, hubs->dcs_codes_r);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		/* HPOUT1R */
2968c2ecf20Sopenharmony_ci		offset = (s8)reg_r;
2978c2ecf20Sopenharmony_ci		dev_dbg(component->dev, "DCS right %d->%d\n", offset,
2988c2ecf20Sopenharmony_ci			offset + hubs->dcs_codes_r);
2998c2ecf20Sopenharmony_ci		offset += hubs->dcs_codes_r;
3008c2ecf20Sopenharmony_ci		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		/* HPOUT1L */
3038c2ecf20Sopenharmony_ci		offset = (s8)reg_l;
3048c2ecf20Sopenharmony_ci		dev_dbg(component->dev, "DCS left %d->%d\n", offset,
3058c2ecf20Sopenharmony_ci			offset + hubs->dcs_codes_l);
3068c2ecf20Sopenharmony_ci		offset += hubs->dcs_codes_l;
3078c2ecf20Sopenharmony_ci		dcs_cfg |= (u8)offset;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		dev_dbg(component->dev, "DCS result: %x\n", dcs_cfg);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci		/* Do it */
3128c2ecf20Sopenharmony_ci		snd_soc_component_write(component, dcs_reg, dcs_cfg);
3138c2ecf20Sopenharmony_ci		wait_for_dc_servo(component,
3148c2ecf20Sopenharmony_ci				  WM8993_DCS_TRIG_DAC_WR_0 |
3158c2ecf20Sopenharmony_ci				  WM8993_DCS_TRIG_DAC_WR_1);
3168c2ecf20Sopenharmony_ci	} else {
3178c2ecf20Sopenharmony_ci		dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
3188c2ecf20Sopenharmony_ci		dcs_cfg |= reg_l;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	/* Save the callibrated offset if we're in class W mode and
3228c2ecf20Sopenharmony_ci	 * therefore don't have any analogue signal mixed in. */
3238c2ecf20Sopenharmony_ci	if (wm_hubs_dac_hp_direct(component))
3248c2ecf20Sopenharmony_ci		wm_hubs_dcs_cache_set(component, dcs_cfg);
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci/*
3288c2ecf20Sopenharmony_ci * Update the DC servo calibration on gain changes
3298c2ecf20Sopenharmony_ci */
3308c2ecf20Sopenharmony_cistatic int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
3318c2ecf20Sopenharmony_ci			       struct snd_ctl_elem_value *ucontrol)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3348c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
3358c2ecf20Sopenharmony_ci	int ret;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	ret = snd_soc_put_volsw(kcontrol, ucontrol);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* If we're applying an offset correction then updating the
3408c2ecf20Sopenharmony_ci	 * callibration would be likely to introduce further offsets. */
3418c2ecf20Sopenharmony_ci	if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
3428c2ecf20Sopenharmony_ci		return ret;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/* Only need to do this if the outputs are active */
3458c2ecf20Sopenharmony_ci	if (snd_soc_component_read(component, WM8993_POWER_MANAGEMENT_1)
3468c2ecf20Sopenharmony_ci	    & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
3478c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component,
3488c2ecf20Sopenharmony_ci				    WM8993_DC_SERVO_0,
3498c2ecf20Sopenharmony_ci				    WM8993_DCS_TRIG_SINGLE_0 |
3508c2ecf20Sopenharmony_ci				    WM8993_DCS_TRIG_SINGLE_1,
3518c2ecf20Sopenharmony_ci				    WM8993_DCS_TRIG_SINGLE_0 |
3528c2ecf20Sopenharmony_ci				    WM8993_DCS_TRIG_SINGLE_1);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return ret;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new analogue_snd_controls[] = {
3588c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
3598c2ecf20Sopenharmony_ci	       inpga_tlv),
3608c2ecf20Sopenharmony_ciSOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
3618c2ecf20Sopenharmony_ciSOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
3648c2ecf20Sopenharmony_ci	       inpga_tlv),
3658c2ecf20Sopenharmony_ciSOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
3668c2ecf20Sopenharmony_ciSOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
3708c2ecf20Sopenharmony_ci	       inpga_tlv),
3718c2ecf20Sopenharmony_ciSOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
3728c2ecf20Sopenharmony_ciSOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
3758c2ecf20Sopenharmony_ci	       inpga_tlv),
3768c2ecf20Sopenharmony_ciSOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
3778c2ecf20Sopenharmony_ciSOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
3808c2ecf20Sopenharmony_ci	       inmix_sw_tlv),
3818c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0,
3828c2ecf20Sopenharmony_ci	       inmix_sw_tlv),
3838c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0,
3848c2ecf20Sopenharmony_ci	       inmix_tlv),
3858c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv),
3868c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0,
3878c2ecf20Sopenharmony_ci	       inmix_tlv),
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0,
3908c2ecf20Sopenharmony_ci	       inmix_sw_tlv),
3918c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0,
3928c2ecf20Sopenharmony_ci	       inmix_sw_tlv),
3938c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0,
3948c2ecf20Sopenharmony_ci	       inmix_tlv),
3958c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv),
3968c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0,
3978c2ecf20Sopenharmony_ci	       inmix_tlv),
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1,
4008c2ecf20Sopenharmony_ci	       outmix_tlv),
4018c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1,
4028c2ecf20Sopenharmony_ci	       outmix_tlv),
4038c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1,
4048c2ecf20Sopenharmony_ci	       outmix_tlv),
4058c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1,
4068c2ecf20Sopenharmony_ci	       outmix_tlv),
4078c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1,
4088c2ecf20Sopenharmony_ci	       outmix_tlv),
4098c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Left Output Mixer Right Input Volume",
4108c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv),
4118c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Left Output Mixer Left Input Volume",
4128c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv),
4138c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1,
4148c2ecf20Sopenharmony_ci	       outmix_tlv),
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Right Output Mixer IN2LN Volume",
4178c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
4188c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Right Output Mixer IN2RN Volume",
4198c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv),
4208c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Right Output Mixer IN1L Volume",
4218c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv),
4228c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Right Output Mixer IN1R Volume",
4238c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv),
4248c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Right Output Mixer IN2RP Volume",
4258c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv),
4268c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Right Output Mixer Left Input Volume",
4278c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv),
4288c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Right Output Mixer Right Input Volume",
4298c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
4308c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Right Output Mixer DAC Volume",
4318c2ecf20Sopenharmony_ci	       WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv),
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ciSOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME,
4348c2ecf20Sopenharmony_ci		 WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv),
4358c2ecf20Sopenharmony_ciSOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME,
4368c2ecf20Sopenharmony_ci	     WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0),
4378c2ecf20Sopenharmony_ciSOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME,
4388c2ecf20Sopenharmony_ci	     WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0),
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ciSOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1),
4418c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv),
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION,
4448c2ecf20Sopenharmony_ci	       5, 1, 1, wm_hubs_spkmix_tlv),
4458c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION,
4468c2ecf20Sopenharmony_ci	       4, 1, 1, wm_hubs_spkmix_tlv),
4478c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION,
4488c2ecf20Sopenharmony_ci	       3, 1, 1, wm_hubs_spkmix_tlv),
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION,
4518c2ecf20Sopenharmony_ci	       5, 1, 1, wm_hubs_spkmix_tlv),
4528c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION,
4538c2ecf20Sopenharmony_ci	       4, 1, 1, wm_hubs_spkmix_tlv),
4548c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION,
4558c2ecf20Sopenharmony_ci	       3, 1, 1, wm_hubs_spkmix_tlv),
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ciSOC_DOUBLE_R_TLV("Speaker Mixer Volume",
4588c2ecf20Sopenharmony_ci		 WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION,
4598c2ecf20Sopenharmony_ci		 0, 3, 1, spkmixout_tlv),
4608c2ecf20Sopenharmony_ciSOC_DOUBLE_R_TLV("Speaker Volume",
4618c2ecf20Sopenharmony_ci		 WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
4628c2ecf20Sopenharmony_ci		 0, 63, 0, outpga_tlv),
4638c2ecf20Sopenharmony_ciSOC_DOUBLE_R("Speaker Switch",
4648c2ecf20Sopenharmony_ci	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
4658c2ecf20Sopenharmony_ci	     6, 1, 0),
4668c2ecf20Sopenharmony_ciSOC_DOUBLE_R("Speaker ZC Switch",
4678c2ecf20Sopenharmony_ci	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
4688c2ecf20Sopenharmony_ci	     7, 1, 0),
4698c2ecf20Sopenharmony_ciSOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
4708c2ecf20Sopenharmony_ci	       spkboost_tlv),
4718c2ecf20Sopenharmony_ciSOC_ENUM("Speaker Reference", speaker_ref),
4728c2ecf20Sopenharmony_ciSOC_ENUM("Speaker Mode", speaker_mode),
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ciSOC_DOUBLE_R_EXT_TLV("Headphone Volume",
4758c2ecf20Sopenharmony_ci		     WM8993_LEFT_OUTPUT_VOLUME, WM8993_RIGHT_OUTPUT_VOLUME,
4768c2ecf20Sopenharmony_ci		     0, 63, 0, snd_soc_get_volsw, wm8993_put_dc_servo,
4778c2ecf20Sopenharmony_ci		     outpga_tlv),
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ciSOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
4808c2ecf20Sopenharmony_ci	     WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
4818c2ecf20Sopenharmony_ciSOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
4828c2ecf20Sopenharmony_ci	     WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ciSOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1),
4858c2ecf20Sopenharmony_ciSOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1),
4868c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1,
4878c2ecf20Sopenharmony_ci	       line_tlv),
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ciSOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1),
4908c2ecf20Sopenharmony_ciSOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1),
4918c2ecf20Sopenharmony_ciSOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
4928c2ecf20Sopenharmony_ci	       line_tlv),
4938c2ecf20Sopenharmony_ci};
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic int hp_supply_event(struct snd_soc_dapm_widget *w,
4968c2ecf20Sopenharmony_ci			   struct snd_kcontrol *kcontrol, int event)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
4998c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	switch (event) {
5028c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
5038c2ecf20Sopenharmony_ci		switch (hubs->hp_startup_mode) {
5048c2ecf20Sopenharmony_ci		case 0:
5058c2ecf20Sopenharmony_ci			break;
5068c2ecf20Sopenharmony_ci		case 1:
5078c2ecf20Sopenharmony_ci			/* Enable the headphone amp */
5088c2ecf20Sopenharmony_ci			snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
5098c2ecf20Sopenharmony_ci					    WM8993_HPOUT1L_ENA |
5108c2ecf20Sopenharmony_ci					    WM8993_HPOUT1R_ENA,
5118c2ecf20Sopenharmony_ci					    WM8993_HPOUT1L_ENA |
5128c2ecf20Sopenharmony_ci					    WM8993_HPOUT1R_ENA);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci			/* Enable the second stage */
5158c2ecf20Sopenharmony_ci			snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
5168c2ecf20Sopenharmony_ci					    WM8993_HPOUT1L_DLY |
5178c2ecf20Sopenharmony_ci					    WM8993_HPOUT1R_DLY,
5188c2ecf20Sopenharmony_ci					    WM8993_HPOUT1L_DLY |
5198c2ecf20Sopenharmony_ci					    WM8993_HPOUT1R_DLY);
5208c2ecf20Sopenharmony_ci			break;
5218c2ecf20Sopenharmony_ci		default:
5228c2ecf20Sopenharmony_ci			dev_err(component->dev, "Unknown HP startup mode %d\n",
5238c2ecf20Sopenharmony_ci				hubs->hp_startup_mode);
5248c2ecf20Sopenharmony_ci			break;
5258c2ecf20Sopenharmony_ci		}
5268c2ecf20Sopenharmony_ci		break;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMD:
5298c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_CHARGE_PUMP_1,
5308c2ecf20Sopenharmony_ci				    WM8993_CP_ENA, 0);
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	return 0;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic int hp_event(struct snd_soc_dapm_widget *w,
5388c2ecf20Sopenharmony_ci		    struct snd_kcontrol *kcontrol, int event)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
5418c2ecf20Sopenharmony_ci	unsigned int reg = snd_soc_component_read(component, WM8993_ANALOGUE_HP_0);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	switch (event) {
5448c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_POST_PMU:
5458c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_CHARGE_PUMP_1,
5468c2ecf20Sopenharmony_ci				    WM8993_CP_ENA, WM8993_CP_ENA);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci		msleep(5);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
5518c2ecf20Sopenharmony_ci				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
5528c2ecf20Sopenharmony_ci				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci		reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
5558c2ecf20Sopenharmony_ci		snd_soc_component_write(component, WM8993_ANALOGUE_HP_0, reg);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_DC_SERVO_1,
5588c2ecf20Sopenharmony_ci				    WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci		enable_dc_servo(component);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci		reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
5638c2ecf20Sopenharmony_ci			WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
5648c2ecf20Sopenharmony_ci		snd_soc_component_write(component, WM8993_ANALOGUE_HP_0, reg);
5658c2ecf20Sopenharmony_ci		break;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMD:
5688c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
5698c2ecf20Sopenharmony_ci				    WM8993_HPOUT1L_OUTP |
5708c2ecf20Sopenharmony_ci				    WM8993_HPOUT1R_OUTP |
5718c2ecf20Sopenharmony_ci				    WM8993_HPOUT1L_RMV_SHORT |
5728c2ecf20Sopenharmony_ci				    WM8993_HPOUT1R_RMV_SHORT, 0);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
5758c2ecf20Sopenharmony_ci				    WM8993_HPOUT1L_DLY |
5768c2ecf20Sopenharmony_ci				    WM8993_HPOUT1R_DLY, 0);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci		snd_soc_component_write(component, WM8993_DC_SERVO_0, 0);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
5818c2ecf20Sopenharmony_ci				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
5828c2ecf20Sopenharmony_ci				    0);
5838c2ecf20Sopenharmony_ci		break;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	return 0;
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cistatic int earpiece_event(struct snd_soc_dapm_widget *w,
5908c2ecf20Sopenharmony_ci			  struct snd_kcontrol *control, int event)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
5938c2ecf20Sopenharmony_ci	u16 reg = snd_soc_component_read(component, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	switch (event) {
5968c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
5978c2ecf20Sopenharmony_ci		reg |= WM8993_HPOUT2_IN_ENA;
5988c2ecf20Sopenharmony_ci		snd_soc_component_write(component, WM8993_ANTIPOP1, reg);
5998c2ecf20Sopenharmony_ci		udelay(50);
6008c2ecf20Sopenharmony_ci		break;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
6038c2ecf20Sopenharmony_ci		snd_soc_component_write(component, WM8993_ANTIPOP1, reg);
6048c2ecf20Sopenharmony_ci		break;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	default:
6078c2ecf20Sopenharmony_ci		WARN(1, "Invalid event %d\n", event);
6088c2ecf20Sopenharmony_ci		break;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	return 0;
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic int lineout_event(struct snd_soc_dapm_widget *w,
6158c2ecf20Sopenharmony_ci			 struct snd_kcontrol *control, int event)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
6188c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
6198c2ecf20Sopenharmony_ci	bool *flag;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	switch (w->shift) {
6228c2ecf20Sopenharmony_ci	case WM8993_LINEOUT1N_ENA_SHIFT:
6238c2ecf20Sopenharmony_ci		flag = &hubs->lineout1n_ena;
6248c2ecf20Sopenharmony_ci		break;
6258c2ecf20Sopenharmony_ci	case WM8993_LINEOUT1P_ENA_SHIFT:
6268c2ecf20Sopenharmony_ci		flag = &hubs->lineout1p_ena;
6278c2ecf20Sopenharmony_ci		break;
6288c2ecf20Sopenharmony_ci	case WM8993_LINEOUT2N_ENA_SHIFT:
6298c2ecf20Sopenharmony_ci		flag = &hubs->lineout2n_ena;
6308c2ecf20Sopenharmony_ci		break;
6318c2ecf20Sopenharmony_ci	case WM8993_LINEOUT2P_ENA_SHIFT:
6328c2ecf20Sopenharmony_ci		flag = &hubs->lineout2p_ena;
6338c2ecf20Sopenharmony_ci		break;
6348c2ecf20Sopenharmony_ci	default:
6358c2ecf20Sopenharmony_ci		WARN(1, "Unknown line output");
6368c2ecf20Sopenharmony_ci		return -EINVAL;
6378c2ecf20Sopenharmony_ci	}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	*flag = SND_SOC_DAPM_EVENT_ON(event);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	return 0;
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic int micbias_event(struct snd_soc_dapm_widget *w,
6458c2ecf20Sopenharmony_ci			 struct snd_kcontrol *kcontrol, int event)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
6488c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	switch (w->shift) {
6518c2ecf20Sopenharmony_ci	case WM8993_MICB1_ENA_SHIFT:
6528c2ecf20Sopenharmony_ci		if (hubs->micb1_delay)
6538c2ecf20Sopenharmony_ci			msleep(hubs->micb1_delay);
6548c2ecf20Sopenharmony_ci		break;
6558c2ecf20Sopenharmony_ci	case WM8993_MICB2_ENA_SHIFT:
6568c2ecf20Sopenharmony_ci		if (hubs->micb2_delay)
6578c2ecf20Sopenharmony_ci			msleep(hubs->micb2_delay);
6588c2ecf20Sopenharmony_ci		break;
6598c2ecf20Sopenharmony_ci	default:
6608c2ecf20Sopenharmony_ci		return -EINVAL;
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	return 0;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_civoid wm_hubs_update_class_w(struct snd_soc_component *component)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
6698c2ecf20Sopenharmony_ci	int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	if (!wm_hubs_dac_hp_direct(component))
6728c2ecf20Sopenharmony_ci		enable = false;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	if (hubs->check_class_w_digital && !hubs->check_class_w_digital(component))
6758c2ecf20Sopenharmony_ci		enable = false;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	dev_vdbg(component->dev, "Class W %s\n", enable ? "enabled" : "disabled");
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_CLASS_W_0,
6808c2ecf20Sopenharmony_ci			    WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	snd_soc_component_write(component, WM8993_LEFT_OUTPUT_VOLUME,
6838c2ecf20Sopenharmony_ci		      snd_soc_component_read(component, WM8993_LEFT_OUTPUT_VOLUME));
6848c2ecf20Sopenharmony_ci	snd_soc_component_write(component, WM8993_RIGHT_OUTPUT_VOLUME,
6858c2ecf20Sopenharmony_ci		      snd_soc_component_read(component, WM8993_RIGHT_OUTPUT_VOLUME));
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci#define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
6908c2ecf20Sopenharmony_ci	SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
6918c2ecf20Sopenharmony_ci		snd_soc_dapm_get_volsw, class_w_put_volsw)
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cistatic int class_w_put_volsw(struct snd_kcontrol *kcontrol,
6948c2ecf20Sopenharmony_ci			      struct snd_ctl_elem_value *ucontrol)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
6978c2ecf20Sopenharmony_ci	int ret;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	wm_hubs_update_class_w(component);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	return ret;
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci#define WM_HUBS_ENUM_W(xname, xenum) \
7078c2ecf20Sopenharmony_ci{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
7088c2ecf20Sopenharmony_ci	.info = snd_soc_info_enum_double, \
7098c2ecf20Sopenharmony_ci	.get = snd_soc_dapm_get_enum_double, \
7108c2ecf20Sopenharmony_ci	.put = class_w_put_double, \
7118c2ecf20Sopenharmony_ci	.private_value = (unsigned long)&xenum }
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic int class_w_put_double(struct snd_kcontrol *kcontrol,
7148c2ecf20Sopenharmony_ci			      struct snd_ctl_elem_value *ucontrol)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
7178c2ecf20Sopenharmony_ci	int ret;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	wm_hubs_update_class_w(component);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	return ret;
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic const char *hp_mux_text[] = {
7278c2ecf20Sopenharmony_ci	"Mixer",
7288c2ecf20Sopenharmony_ci	"DAC",
7298c2ecf20Sopenharmony_ci};
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(hpl_enum,
7328c2ecf20Sopenharmony_ci			    WM8993_OUTPUT_MIXER1, 8, hp_mux_text);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ciconst struct snd_kcontrol_new wm_hubs_hpl_mux =
7358c2ecf20Sopenharmony_ci	WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
7368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(hpr_enum,
7398c2ecf20Sopenharmony_ci			    WM8993_OUTPUT_MIXER2, 8, hp_mux_text);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ciconst struct snd_kcontrol_new wm_hubs_hpr_mux =
7428c2ecf20Sopenharmony_ci	WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
7438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_hpr_mux);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new in1l_pga[] = {
7468c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
7478c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
7488c2ecf20Sopenharmony_ci};
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new in1r_pga[] = {
7518c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0),
7528c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0),
7538c2ecf20Sopenharmony_ci};
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new in2l_pga[] = {
7568c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0),
7578c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0),
7588c2ecf20Sopenharmony_ci};
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new in2r_pga[] = {
7618c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0),
7628c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0),
7638c2ecf20Sopenharmony_ci};
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mixinl[] = {
7668c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0),
7678c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0),
7688c2ecf20Sopenharmony_ci};
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mixinr[] = {
7718c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0),
7728c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
7738c2ecf20Sopenharmony_ci};
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new left_output_mixer[] = {
7768c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
7778c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
7788c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
7798c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
7808c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
7818c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
7828c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
7838c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
7848c2ecf20Sopenharmony_ci};
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new right_output_mixer[] = {
7878c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
7888c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
7898c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
7908c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
7918c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
7928c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
7938c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
7948c2ecf20Sopenharmony_ciWM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
7958c2ecf20Sopenharmony_ci};
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new earpiece_mixer[] = {
7988c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0),
7998c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0),
8008c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0),
8018c2ecf20Sopenharmony_ci};
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new left_speaker_boost[] = {
8048c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0),
8058c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0),
8068c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0),
8078c2ecf20Sopenharmony_ci};
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new right_speaker_boost[] = {
8108c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0),
8118c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0),
8128c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0),
8138c2ecf20Sopenharmony_ci};
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new line1_mix[] = {
8168c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0),
8178c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0),
8188c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
8198c2ecf20Sopenharmony_ci};
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new line1n_mix[] = {
8228c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0),
8238c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0),
8248c2ecf20Sopenharmony_ci};
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new line1p_mix[] = {
8278c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
8288c2ecf20Sopenharmony_ci};
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new line2_mix[] = {
8318c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0),
8328c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0),
8338c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
8348c2ecf20Sopenharmony_ci};
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new line2n_mix[] = {
8378c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
8388c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
8398c2ecf20Sopenharmony_ci};
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new line2p_mix[] = {
8428c2ecf20Sopenharmony_ciSOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
8438c2ecf20Sopenharmony_ci};
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget analogue_dapm_widgets[] = {
8468c2ecf20Sopenharmony_ciSND_SOC_DAPM_INPUT("IN1LN"),
8478c2ecf20Sopenharmony_ciSND_SOC_DAPM_INPUT("IN1LP"),
8488c2ecf20Sopenharmony_ciSND_SOC_DAPM_INPUT("IN2LN"),
8498c2ecf20Sopenharmony_ciSND_SOC_DAPM_INPUT("IN2LP:VXRN"),
8508c2ecf20Sopenharmony_ciSND_SOC_DAPM_INPUT("IN1RN"),
8518c2ecf20Sopenharmony_ciSND_SOC_DAPM_INPUT("IN1RP"),
8528c2ecf20Sopenharmony_ciSND_SOC_DAPM_INPUT("IN2RN"),
8538c2ecf20Sopenharmony_ciSND_SOC_DAPM_INPUT("IN2RP:VXRP"),
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ciSND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0,
8568c2ecf20Sopenharmony_ci		    micbias_event, SND_SOC_DAPM_POST_PMU),
8578c2ecf20Sopenharmony_ciSND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0,
8588c2ecf20Sopenharmony_ci		    micbias_event, SND_SOC_DAPM_POST_PMU),
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
8618c2ecf20Sopenharmony_ci		   in1l_pga, ARRAY_SIZE(in1l_pga)),
8628c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
8638c2ecf20Sopenharmony_ci		   in1r_pga, ARRAY_SIZE(in1r_pga)),
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
8668c2ecf20Sopenharmony_ci		   in2l_pga, ARRAY_SIZE(in2l_pga)),
8678c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
8688c2ecf20Sopenharmony_ci		   in2r_pga, ARRAY_SIZE(in2r_pga)),
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
8718c2ecf20Sopenharmony_ci		   mixinl, ARRAY_SIZE(mixinl)),
8728c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
8738c2ecf20Sopenharmony_ci		   mixinr, ARRAY_SIZE(mixinr)),
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0,
8768c2ecf20Sopenharmony_ci		   left_output_mixer, ARRAY_SIZE(left_output_mixer)),
8778c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
8788c2ecf20Sopenharmony_ci		   right_output_mixer, ARRAY_SIZE(right_output_mixer)),
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ciSND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
8818c2ecf20Sopenharmony_ciSND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ciSND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event,
8848c2ecf20Sopenharmony_ci		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
8858c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
8868c2ecf20Sopenharmony_ci		       hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
8898c2ecf20Sopenharmony_ci		   earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
8908c2ecf20Sopenharmony_ciSND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0,
8918c2ecf20Sopenharmony_ci		   NULL, 0, earpiece_event,
8928c2ecf20Sopenharmony_ci		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
8958c2ecf20Sopenharmony_ci		   left_speaker_boost, ARRAY_SIZE(left_speaker_boost)),
8968c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
8978c2ecf20Sopenharmony_ci		   right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ciSND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
9008c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
9018c2ecf20Sopenharmony_ci		     NULL, 0),
9028c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
9038c2ecf20Sopenharmony_ci		     NULL, 0),
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
9068c2ecf20Sopenharmony_ci		   line1_mix, ARRAY_SIZE(line1_mix)),
9078c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
9088c2ecf20Sopenharmony_ci		   line2_mix, ARRAY_SIZE(line2_mix)),
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0,
9118c2ecf20Sopenharmony_ci		   line1n_mix, ARRAY_SIZE(line1n_mix)),
9128c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0,
9138c2ecf20Sopenharmony_ci		   line1p_mix, ARRAY_SIZE(line1p_mix)),
9148c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
9158c2ecf20Sopenharmony_ci		   line2n_mix, ARRAY_SIZE(line2n_mix)),
9168c2ecf20Sopenharmony_ciSND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
9178c2ecf20Sopenharmony_ci		   line2p_mix, ARRAY_SIZE(line2p_mix)),
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
9208c2ecf20Sopenharmony_ci		       NULL, 0, lineout_event,
9218c2ecf20Sopenharmony_ci		     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
9228c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
9238c2ecf20Sopenharmony_ci		       NULL, 0, lineout_event,
9248c2ecf20Sopenharmony_ci		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
9258c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
9268c2ecf20Sopenharmony_ci		       NULL, 0, lineout_event,
9278c2ecf20Sopenharmony_ci		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
9288c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
9298c2ecf20Sopenharmony_ci		       NULL, 0, lineout_event,
9308c2ecf20Sopenharmony_ci		       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("SPKOUTLP"),
9338c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("SPKOUTLN"),
9348c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("SPKOUTRP"),
9358c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("SPKOUTRN"),
9368c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("HPOUT1L"),
9378c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("HPOUT1R"),
9388c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("HPOUT2P"),
9398c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("HPOUT2N"),
9408c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("LINEOUT1P"),
9418c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("LINEOUT1N"),
9428c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("LINEOUT2P"),
9438c2ecf20Sopenharmony_ciSND_SOC_DAPM_OUTPUT("LINEOUT2N"),
9448c2ecf20Sopenharmony_ci};
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route analogue_routes[] = {
9478c2ecf20Sopenharmony_ci	{ "MICBIAS1", NULL, "CLK_SYS" },
9488c2ecf20Sopenharmony_ci	{ "MICBIAS2", NULL, "CLK_SYS" },
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	{ "IN1L PGA", "IN1LP Switch", "IN1LP" },
9518c2ecf20Sopenharmony_ci	{ "IN1L PGA", "IN1LN Switch", "IN1LN" },
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	{ "IN1L PGA", NULL, "VMID" },
9548c2ecf20Sopenharmony_ci	{ "IN1R PGA", NULL, "VMID" },
9558c2ecf20Sopenharmony_ci	{ "IN2L PGA", NULL, "VMID" },
9568c2ecf20Sopenharmony_ci	{ "IN2R PGA", NULL, "VMID" },
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	{ "IN1R PGA", "IN1RP Switch", "IN1RP" },
9598c2ecf20Sopenharmony_ci	{ "IN1R PGA", "IN1RN Switch", "IN1RN" },
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	{ "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" },
9628c2ecf20Sopenharmony_ci	{ "IN2L PGA", "IN2LN Switch", "IN2LN" },
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	{ "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" },
9658c2ecf20Sopenharmony_ci	{ "IN2R PGA", "IN2RN Switch", "IN2RN" },
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	{ "Direct Voice", NULL, "IN2LP:VXRN" },
9688c2ecf20Sopenharmony_ci	{ "Direct Voice", NULL, "IN2RP:VXRP" },
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	{ "MIXINL", "IN1L Switch", "IN1L PGA" },
9718c2ecf20Sopenharmony_ci	{ "MIXINL", "IN2L Switch", "IN2L PGA" },
9728c2ecf20Sopenharmony_ci	{ "MIXINL", NULL, "Direct Voice" },
9738c2ecf20Sopenharmony_ci	{ "MIXINL", NULL, "IN1LP" },
9748c2ecf20Sopenharmony_ci	{ "MIXINL", NULL, "Left Output Mixer" },
9758c2ecf20Sopenharmony_ci	{ "MIXINL", NULL, "VMID" },
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	{ "MIXINR", "IN1R Switch", "IN1R PGA" },
9788c2ecf20Sopenharmony_ci	{ "MIXINR", "IN2R Switch", "IN2R PGA" },
9798c2ecf20Sopenharmony_ci	{ "MIXINR", NULL, "Direct Voice" },
9808c2ecf20Sopenharmony_ci	{ "MIXINR", NULL, "IN1RP" },
9818c2ecf20Sopenharmony_ci	{ "MIXINR", NULL, "Right Output Mixer" },
9828c2ecf20Sopenharmony_ci	{ "MIXINR", NULL, "VMID" },
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	{ "ADCL", NULL, "MIXINL" },
9858c2ecf20Sopenharmony_ci	{ "ADCR", NULL, "MIXINR" },
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	{ "Left Output Mixer", "Left Input Switch", "MIXINL" },
9888c2ecf20Sopenharmony_ci	{ "Left Output Mixer", "Right Input Switch", "MIXINR" },
9898c2ecf20Sopenharmony_ci	{ "Left Output Mixer", "IN2RN Switch", "IN2RN" },
9908c2ecf20Sopenharmony_ci	{ "Left Output Mixer", "IN2LN Switch", "IN2LN" },
9918c2ecf20Sopenharmony_ci	{ "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" },
9928c2ecf20Sopenharmony_ci	{ "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
9938c2ecf20Sopenharmony_ci	{ "Left Output Mixer", "IN1R Switch", "IN1R PGA" },
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	{ "Right Output Mixer", "Left Input Switch", "MIXINL" },
9968c2ecf20Sopenharmony_ci	{ "Right Output Mixer", "Right Input Switch", "MIXINR" },
9978c2ecf20Sopenharmony_ci	{ "Right Output Mixer", "IN2LN Switch", "IN2LN" },
9988c2ecf20Sopenharmony_ci	{ "Right Output Mixer", "IN2RN Switch", "IN2RN" },
9998c2ecf20Sopenharmony_ci	{ "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" },
10008c2ecf20Sopenharmony_ci	{ "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
10018c2ecf20Sopenharmony_ci	{ "Right Output Mixer", "IN1R Switch", "IN1R PGA" },
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	{ "Left Output PGA", NULL, "Left Output Mixer" },
10048c2ecf20Sopenharmony_ci	{ "Left Output PGA", NULL, "TOCLK" },
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	{ "Right Output PGA", NULL, "Right Output Mixer" },
10078c2ecf20Sopenharmony_ci	{ "Right Output PGA", NULL, "TOCLK" },
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	{ "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" },
10108c2ecf20Sopenharmony_ci	{ "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
10118c2ecf20Sopenharmony_ci	{ "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	{ "Earpiece Driver", NULL, "VMID" },
10148c2ecf20Sopenharmony_ci	{ "Earpiece Driver", NULL, "Earpiece Mixer" },
10158c2ecf20Sopenharmony_ci	{ "HPOUT2N", NULL, "Earpiece Driver" },
10168c2ecf20Sopenharmony_ci	{ "HPOUT2P", NULL, "Earpiece Driver" },
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	{ "SPKL", "Input Switch", "MIXINL" },
10198c2ecf20Sopenharmony_ci	{ "SPKL", "IN1LP Switch", "IN1LP" },
10208c2ecf20Sopenharmony_ci	{ "SPKL", "Output Switch", "Left Output PGA" },
10218c2ecf20Sopenharmony_ci	{ "SPKL", NULL, "TOCLK" },
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	{ "SPKR", "Input Switch", "MIXINR" },
10248c2ecf20Sopenharmony_ci	{ "SPKR", "IN1RP Switch", "IN1RP" },
10258c2ecf20Sopenharmony_ci	{ "SPKR", "Output Switch", "Right Output PGA" },
10268c2ecf20Sopenharmony_ci	{ "SPKR", NULL, "TOCLK" },
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	{ "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
10298c2ecf20Sopenharmony_ci	{ "SPKL Boost", "SPKL Switch", "SPKL" },
10308c2ecf20Sopenharmony_ci	{ "SPKL Boost", "SPKR Switch", "SPKR" },
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	{ "SPKR Boost", "Direct Voice Switch", "Direct Voice" },
10338c2ecf20Sopenharmony_ci	{ "SPKR Boost", "SPKR Switch", "SPKR" },
10348c2ecf20Sopenharmony_ci	{ "SPKR Boost", "SPKL Switch", "SPKL" },
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	{ "SPKL Driver", NULL, "VMID" },
10378c2ecf20Sopenharmony_ci	{ "SPKL Driver", NULL, "SPKL Boost" },
10388c2ecf20Sopenharmony_ci	{ "SPKL Driver", NULL, "CLK_SYS" },
10398c2ecf20Sopenharmony_ci	{ "SPKL Driver", NULL, "TSHUT" },
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	{ "SPKR Driver", NULL, "VMID" },
10428c2ecf20Sopenharmony_ci	{ "SPKR Driver", NULL, "SPKR Boost" },
10438c2ecf20Sopenharmony_ci	{ "SPKR Driver", NULL, "CLK_SYS" },
10448c2ecf20Sopenharmony_ci	{ "SPKR Driver", NULL, "TSHUT" },
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	{ "SPKOUTLP", NULL, "SPKL Driver" },
10478c2ecf20Sopenharmony_ci	{ "SPKOUTLN", NULL, "SPKL Driver" },
10488c2ecf20Sopenharmony_ci	{ "SPKOUTRP", NULL, "SPKR Driver" },
10498c2ecf20Sopenharmony_ci	{ "SPKOUTRN", NULL, "SPKR Driver" },
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	{ "Left Headphone Mux", "Mixer", "Left Output PGA" },
10528c2ecf20Sopenharmony_ci	{ "Right Headphone Mux", "Mixer", "Right Output PGA" },
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	{ "Headphone PGA", NULL, "Left Headphone Mux" },
10558c2ecf20Sopenharmony_ci	{ "Headphone PGA", NULL, "Right Headphone Mux" },
10568c2ecf20Sopenharmony_ci	{ "Headphone PGA", NULL, "VMID" },
10578c2ecf20Sopenharmony_ci	{ "Headphone PGA", NULL, "CLK_SYS" },
10588c2ecf20Sopenharmony_ci	{ "Headphone PGA", NULL, "Headphone Supply" },
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	{ "HPOUT1L", NULL, "Headphone PGA" },
10618c2ecf20Sopenharmony_ci	{ "HPOUT1R", NULL, "Headphone PGA" },
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	{ "LINEOUT1N Driver", NULL, "VMID" },
10648c2ecf20Sopenharmony_ci	{ "LINEOUT1P Driver", NULL, "VMID" },
10658c2ecf20Sopenharmony_ci	{ "LINEOUT2N Driver", NULL, "VMID" },
10668c2ecf20Sopenharmony_ci	{ "LINEOUT2P Driver", NULL, "VMID" },
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	{ "LINEOUT1N", NULL, "LINEOUT1N Driver" },
10698c2ecf20Sopenharmony_ci	{ "LINEOUT1P", NULL, "LINEOUT1P Driver" },
10708c2ecf20Sopenharmony_ci	{ "LINEOUT2N", NULL, "LINEOUT2N Driver" },
10718c2ecf20Sopenharmony_ci	{ "LINEOUT2P", NULL, "LINEOUT2P Driver" },
10728c2ecf20Sopenharmony_ci};
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route lineout1_diff_routes[] = {
10758c2ecf20Sopenharmony_ci	{ "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
10768c2ecf20Sopenharmony_ci	{ "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
10778c2ecf20Sopenharmony_ci	{ "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" },
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	{ "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
10808c2ecf20Sopenharmony_ci	{ "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
10818c2ecf20Sopenharmony_ci};
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route lineout1_se_routes[] = {
10848c2ecf20Sopenharmony_ci	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
10858c2ecf20Sopenharmony_ci	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
10908c2ecf20Sopenharmony_ci	{ "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
10918c2ecf20Sopenharmony_ci};
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route lineout2_diff_routes[] = {
10948c2ecf20Sopenharmony_ci	{ "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" },
10958c2ecf20Sopenharmony_ci	{ "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" },
10968c2ecf20Sopenharmony_ci	{ "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
10998c2ecf20Sopenharmony_ci	{ "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
11008c2ecf20Sopenharmony_ci};
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route lineout2_se_routes[] = {
11038c2ecf20Sopenharmony_ci	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
11048c2ecf20Sopenharmony_ci	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
11098c2ecf20Sopenharmony_ci	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
11108c2ecf20Sopenharmony_ci};
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ciint wm_hubs_add_analogue_controls(struct snd_soc_component *component)
11138c2ecf20Sopenharmony_ci{
11148c2ecf20Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	/* Latch volume update bits & default ZC on */
11178c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
11188c2ecf20Sopenharmony_ci			    WM8993_IN1_VU, WM8993_IN1_VU);
11198c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
11208c2ecf20Sopenharmony_ci			    WM8993_IN1_VU, WM8993_IN1_VU);
11218c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
11228c2ecf20Sopenharmony_ci			    WM8993_IN2_VU, WM8993_IN2_VU);
11238c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
11248c2ecf20Sopenharmony_ci			    WM8993_IN2_VU, WM8993_IN2_VU);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_SPEAKER_VOLUME_LEFT,
11278c2ecf20Sopenharmony_ci			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
11288c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_SPEAKER_VOLUME_RIGHT,
11298c2ecf20Sopenharmony_ci			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_LEFT_OUTPUT_VOLUME,
11328c2ecf20Sopenharmony_ci			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
11338c2ecf20Sopenharmony_ci			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
11348c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_RIGHT_OUTPUT_VOLUME,
11358c2ecf20Sopenharmony_ci			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
11368c2ecf20Sopenharmony_ci			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_LEFT_OPGA_VOLUME,
11398c2ecf20Sopenharmony_ci			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
11408c2ecf20Sopenharmony_ci			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
11418c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_RIGHT_OPGA_VOLUME,
11428c2ecf20Sopenharmony_ci			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
11438c2ecf20Sopenharmony_ci			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	snd_soc_add_component_controls(component, analogue_snd_controls,
11468c2ecf20Sopenharmony_ci			     ARRAY_SIZE(analogue_snd_controls));
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
11498c2ecf20Sopenharmony_ci				  ARRAY_SIZE(analogue_dapm_widgets));
11508c2ecf20Sopenharmony_ci	return 0;
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ciint wm_hubs_add_analogue_routes(struct snd_soc_component *component,
11558c2ecf20Sopenharmony_ci				int lineout1_diff, int lineout2_diff)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
11588c2ecf20Sopenharmony_ci	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	hubs->component = component;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hubs->dcs_cache);
11638c2ecf20Sopenharmony_ci	init_completion(&hubs->dcs_done);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	snd_soc_dapm_add_routes(dapm, analogue_routes,
11668c2ecf20Sopenharmony_ci				ARRAY_SIZE(analogue_routes));
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	if (lineout1_diff)
11698c2ecf20Sopenharmony_ci		snd_soc_dapm_add_routes(dapm,
11708c2ecf20Sopenharmony_ci					lineout1_diff_routes,
11718c2ecf20Sopenharmony_ci					ARRAY_SIZE(lineout1_diff_routes));
11728c2ecf20Sopenharmony_ci	else
11738c2ecf20Sopenharmony_ci		snd_soc_dapm_add_routes(dapm,
11748c2ecf20Sopenharmony_ci					lineout1_se_routes,
11758c2ecf20Sopenharmony_ci					ARRAY_SIZE(lineout1_se_routes));
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	if (lineout2_diff)
11788c2ecf20Sopenharmony_ci		snd_soc_dapm_add_routes(dapm,
11798c2ecf20Sopenharmony_ci					lineout2_diff_routes,
11808c2ecf20Sopenharmony_ci					ARRAY_SIZE(lineout2_diff_routes));
11818c2ecf20Sopenharmony_ci	else
11828c2ecf20Sopenharmony_ci		snd_soc_dapm_add_routes(dapm,
11838c2ecf20Sopenharmony_ci					lineout2_se_routes,
11848c2ecf20Sopenharmony_ci					ARRAY_SIZE(lineout2_se_routes));
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	return 0;
11878c2ecf20Sopenharmony_ci}
11888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ciint wm_hubs_handle_analogue_pdata(struct snd_soc_component *component,
11918c2ecf20Sopenharmony_ci				  int lineout1_diff, int lineout2_diff,
11928c2ecf20Sopenharmony_ci				  int lineout1fb, int lineout2fb,
11938c2ecf20Sopenharmony_ci				  int jd_scthr, int jd_thr,
11948c2ecf20Sopenharmony_ci				  int micbias1_delay, int micbias2_delay,
11958c2ecf20Sopenharmony_ci				  int micbias1_lvl, int micbias2_lvl)
11968c2ecf20Sopenharmony_ci{
11978c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	hubs->lineout1_se = !lineout1_diff;
12008c2ecf20Sopenharmony_ci	hubs->lineout2_se = !lineout2_diff;
12018c2ecf20Sopenharmony_ci	hubs->micb1_delay = micbias1_delay;
12028c2ecf20Sopenharmony_ci	hubs->micb2_delay = micbias2_delay;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	if (!lineout1_diff)
12058c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_LINE_MIXER1,
12068c2ecf20Sopenharmony_ci				    WM8993_LINEOUT1_MODE,
12078c2ecf20Sopenharmony_ci				    WM8993_LINEOUT1_MODE);
12088c2ecf20Sopenharmony_ci	if (!lineout2_diff)
12098c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_LINE_MIXER2,
12108c2ecf20Sopenharmony_ci				    WM8993_LINEOUT2_MODE,
12118c2ecf20Sopenharmony_ci				    WM8993_LINEOUT2_MODE);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	if (!lineout1_diff && !lineout2_diff)
12148c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
12158c2ecf20Sopenharmony_ci				    WM8993_LINEOUT_VMID_BUF_ENA,
12168c2ecf20Sopenharmony_ci				    WM8993_LINEOUT_VMID_BUF_ENA);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (lineout1fb)
12198c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
12208c2ecf20Sopenharmony_ci				    WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	if (lineout2fb)
12238c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_ADDITIONAL_CONTROL,
12248c2ecf20Sopenharmony_ci				    WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	if (!hubs->micd_scthr)
12278c2ecf20Sopenharmony_ci		return 0;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_MICBIAS,
12308c2ecf20Sopenharmony_ci			    WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
12318c2ecf20Sopenharmony_ci			    WM8993_MICB1_LVL | WM8993_MICB2_LVL,
12328c2ecf20Sopenharmony_ci			    jd_scthr << WM8993_JD_SCTHR_SHIFT |
12338c2ecf20Sopenharmony_ci			    jd_thr << WM8993_JD_THR_SHIFT |
12348c2ecf20Sopenharmony_ci			    micbias1_lvl |
12358c2ecf20Sopenharmony_ci			    micbias2_lvl << WM8993_MICB2_LVL_SHIFT);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	return 0;
12388c2ecf20Sopenharmony_ci}
12398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_civoid wm_hubs_vmid_ena(struct snd_soc_component *component)
12428c2ecf20Sopenharmony_ci{
12438c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
12448c2ecf20Sopenharmony_ci	int val = 0;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	if (hubs->lineout1_se)
12478c2ecf20Sopenharmony_ci		val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	if (hubs->lineout2_se)
12508c2ecf20Sopenharmony_ci		val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	/* Enable the line outputs while we power up */
12538c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_3, val, val);
12548c2ecf20Sopenharmony_ci}
12558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_civoid wm_hubs_set_bias_level(struct snd_soc_component *component,
12588c2ecf20Sopenharmony_ci			    enum snd_soc_bias_level level)
12598c2ecf20Sopenharmony_ci{
12608c2ecf20Sopenharmony_ci	struct wm_hubs_data *hubs = snd_soc_component_get_drvdata(component);
12618c2ecf20Sopenharmony_ci	int mask, val;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	switch (level) {
12648c2ecf20Sopenharmony_ci	case SND_SOC_BIAS_STANDBY:
12658c2ecf20Sopenharmony_ci		/* Clamp the inputs to VMID while we ramp to charge caps */
12668c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_INPUTS_CLAMP_REG,
12678c2ecf20Sopenharmony_ci				    WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP);
12688c2ecf20Sopenharmony_ci		break;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	case SND_SOC_BIAS_ON:
12718c2ecf20Sopenharmony_ci		/* Turn off any unneeded single ended outputs */
12728c2ecf20Sopenharmony_ci		val = 0;
12738c2ecf20Sopenharmony_ci		mask = 0;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci		if (hubs->lineout1_se)
12768c2ecf20Sopenharmony_ci			mask |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci		if (hubs->lineout2_se)
12798c2ecf20Sopenharmony_ci			mask |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci		if (hubs->lineout1_se && hubs->lineout1n_ena)
12828c2ecf20Sopenharmony_ci			val |= WM8993_LINEOUT1N_ENA;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci		if (hubs->lineout1_se && hubs->lineout1p_ena)
12858c2ecf20Sopenharmony_ci			val |= WM8993_LINEOUT1P_ENA;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci		if (hubs->lineout2_se && hubs->lineout2n_ena)
12888c2ecf20Sopenharmony_ci			val |= WM8993_LINEOUT2N_ENA;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		if (hubs->lineout2_se && hubs->lineout2p_ena)
12918c2ecf20Sopenharmony_ci			val |= WM8993_LINEOUT2P_ENA;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_3,
12948c2ecf20Sopenharmony_ci				    mask, val);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci		/* Remove the input clamps */
12978c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, WM8993_INPUTS_CLAMP_REG,
12988c2ecf20Sopenharmony_ci				    WM8993_INPUTS_CLAMP, 0);
12998c2ecf20Sopenharmony_ci		break;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	default:
13028c2ecf20Sopenharmony_ci		break;
13038c2ecf20Sopenharmony_ci	}
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wm_hubs_set_bias_level);
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Shared support for Wolfson hubs products");
13088c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
13098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1310