// SPDX-License-Identifier: GPL-2.0
/*
 * ad82128.c  --  ad82128 ALSA SoC Audio driver
 *
 * Copyright 1998 Elite Semiconductor Memory Technology
 *
 * Author: ESMT Audio/Power Product BU Team
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/device.h>

#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/initval.h>
#include <linux/regmap.h>
#include <linux/of_gpio.h>
#include "ad82128.h"

// Define how often to check (and clear) the fault status register (in ms)
#define AD82128_FAULT_CHECK_INTERVAL 500
#define AD82128_VOLUME_MAX  (230)
#define AD82128_VOLUME_MIN  (0)

enum ad82128_type {
	AD82128,
};

static const char * const ad82128_supply_names[] = {
	"dvdd", /* Digital power supply. Connect to 3.3-V supply. */
	"pvdd", /* Class-D amp and analog power supply (connected). */
};

#define AD82128_NUM_SUPPLIES ARRAY_SIZE(ad82128_supply_names)

struct ad82128_data {
	struct snd_soc_component *component;
	struct regmap *regmap;
	struct i2c_client *ad82128_client;
	enum ad82128_type devtype;
	struct regulator_bulk_data supplies[AD82128_NUM_SUPPLIES];
	struct delayed_work fault_check_work;
	struct work_struct work;
	unsigned int last_fault;
	int mute;
	int reset_pin;
	int init_done;
	int vol;
};

static int ad82128_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params,
	struct snd_soc_dai *dai)
{
	struct snd_soc_component *component = dai->component;
	unsigned int rate = params_rate(params);
	bool ssz_ds;
	int ret;

	switch (rate) {
	case 44100:
	case 48000:
		ssz_ds = false;
		break;
	case 88200:
	case 96000:
		ssz_ds = true;
		break;
	default:
		dev_err(component->dev, "unsupported sample rate: %u\n", rate);
		return -EINVAL;
	}

	ret = snd_soc_component_update_bits(component, AD82128_STATE_CTRL2_REG,
		AD82128_SSZ_DS, ssz_ds);
	if (ret < 0) {
		dev_err(component->dev, "error setting sample rate: %d\n", ret);
		return ret;
	}

	return 0;
}

static int ad82128_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
	struct snd_soc_component *component = dai->component;
	u8 serial_format;
	int ret;

	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
		dev_vdbg(component->dev, "DAI Format master is not found\n");
		return -EINVAL;
	}

	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK)) {
	case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
		/* 1st data bit occur one BCLK cycle after the frame sync */
		serial_format = AD82128_SAIF_I2S;
		break;
	case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF):
		/*
		 * Note that although the AD82128 does not have a dedicated DSP
		 * mode it doesn't care about the LRCLK duty cycle during TDM
		 * operation. Therefore we can use the device's I2S mode with
		 * its delaying of the 1st data bit to receive DSP_A formatted
		 * data. See device datasheet for additional details.
		 */
		serial_format = AD82128_SAIF_I2S;
		break;
	case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF):
		/*
		 * Similar to DSP_A, we can use the fact that the AD82128 does
		 * not care about the LRCLK duty cycle during TDM to receive
		 * DSP_B formatted data in LEFTJ mode (no delaying of the 1st
		 * data bit).
		 */
		serial_format = AD82128_SAIF_LEFTJ;
		break;
	case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
		/* No delay after the frame sync */
		serial_format = AD82128_SAIF_LEFTJ;
		break;
	default:
		dev_vdbg(component->dev, "DAI Format is not found\n");
		return -EINVAL;
	}

	ret = snd_soc_component_update_bits(component, AD82128_STATE_CTRL1_REG,
		AD82128_SAIF_FORMAT_MASK,
		serial_format);
	if (ret < 0) {
		dev_err(component->dev, "error setting SAIF format: %d\n", ret);
		return ret;
	}

	return 0;
}

static int ad82128_vol_info(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->access =
	    (SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE);
	uinfo->count = 1;

	uinfo->value.integer.min = AD82128_VOLUME_MIN;
	uinfo->value.integer.max = AD82128_VOLUME_MAX;
	uinfo->value.integer.step = 1;

	return 0;
}

static int ad82128_mute_info(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->access =
	    (SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE);
	uinfo->count = 1;

	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = 1;
	uinfo->value.integer.step = 1;

	return 0;
}

static int ad82128_vol_locked_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);

	ucontrol->value.integer.value[0] = ad82128->vol;

	return 0;
}

static inline int get_volume_index(int vol)
{
	int index;

	index = vol;

	if (index < AD82128_VOLUME_MIN)
		index = AD82128_VOLUME_MIN;

	if (index > AD82128_VOLUME_MAX)
		index = AD82128_VOLUME_MAX;

	return index;
}

static void ad82128_set_volume(struct snd_soc_component *component, int vol)
{
	unsigned int index;
	u32 volume_hex;
	u8 byte;

	index = get_volume_index(vol);
	volume_hex = ad82128_volume[index];

	byte = (volume_hex & 0xFF);

	snd_soc_component_write(component, AD82128_VOLUME_CTRL_REG, byte);
}

static int ad82128_mute(struct snd_soc_component *component, int mute)
{
	int ret;

	if (mute) {
		//mute master volume
		ret = snd_soc_component_update_bits(component, AD82128_STATE_CTRL3_REG,
			AD82128_MUTE, AD82128_MUTE);
		if (ret < 0)
			dev_err(component->dev, "failed to write MUTE register: %d\n", ret);
	} else {
		//unmute
		ret = snd_soc_component_update_bits(component, AD82128_STATE_CTRL3_REG,
			AD82128_MUTE, 0);
		if (ret < 0)
			dev_err(component->dev, "failed to write MUTE register: %d\n", ret);
	}

	return 0;
}

static int ad82128_vol_locked_put(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);

	ad82128->vol = ucontrol->value.integer.value[0];
	ad82128_set_volume(component, ad82128->vol);

	return 0;
}

static int ad82128_mute_locked_put(struct snd_kcontrol *kcontrol,
				    struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);

	ad82128->mute = ucontrol->value.integer.value[0];
	ad82128_mute(component, ad82128->mute);

	return 0;
}

static int ad82128_mute_locked_get(struct snd_kcontrol *kcontrol,
				    struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);

	ucontrol->value.integer.value[0] = ad82128->mute;

	return 0;
}

#ifdef DEBUG_AD82128_SDZ
static void ad82128_fault_check_work(struct work_struct *work)
{
	struct ad82128_data *ad82128 = container_of(work, struct ad82128_data,
		fault_check_work.work);
	struct device *dev = ad82128->component->dev;
	unsigned int curr_fault;
	int ret;

	ret = regmap_read(ad82128->regmap, AD82128_FAULT_REG, &curr_fault);
	if (ret < 0) {
		dev_err(dev, "failed to read FAULT register: %d\n", ret);
		goto out;
	}

	/* Check/handle all errors except SAIF clock errors */
	curr_fault &= AD82128_OCE | AD82128_DCE | AD82128_OTE;

	/*
	 * Only flag errors once for a given occurrence. This is needed as
	 * the AD82128 will take time clearing the fault condition internally
	 * during which we don't want to bombard the system with the same
	 * error message over and over.
	 */
	if (!(curr_fault & AD82128_OCE) && (ad82128->last_fault & AD82128_OCE))
		dev_crit(dev, "experienced an over current hardware fault\n");

	if (!(curr_fault & AD82128_DCE) && (ad82128->last_fault & AD82128_DCE))
		dev_crit(dev, "experienced a DC detection fault\n");

	if (!(curr_fault & AD82128_OTE) && (ad82128->last_fault & AD82128_OTE))
		dev_crit(dev, "experienced an over temperature fault\n");

	/* Store current fault value so we can detect any changes next time */
	ad82128->last_fault = curr_fault;

	if (curr_fault)
		goto out;

	/*
	 * Periodically toggle SDZ (shutdown bit) H->L->H to clear any latching
	 * faults as long as a fault condition persists. Always going through
	 * the full sequence no matter the first return value to minimizes
	 * chances for the device to end up in shutdown mode.
	 */
	if (ad82128->reset_pin > 0) {
		ret = gpio_request(ad82128->reset_pin, NULL); // request amp PD pin control GPIO
		if (ret < 0)
			dev_err(dev, "failed to request gpio: %d\n", ret);

		gpio_direction_output(ad82128->reset_pin, 0); // pull low amp PD pin
		msleep(20);
		gpio_direction_output(ad82128->reset_pin, 1); // pull high amp PD pin
	}
out:
	/* Schedule the next fault check at the specified interval */
	schedule_delayed_work(&ad82128->fault_check_work,
		msecs_to_jiffies(AD82128_FAULT_CHECK_INTERVAL));
}
#endif

static void ad82128_init_func(struct work_struct *p_work)
{
	struct ad82128_data *ad82128;
	struct snd_soc_component *component;

	int ret;
	int i;
	int reg_data;

	ad82128 = container_of(p_work, struct ad82128_data, work);

	component = ad82128->component;

	dev_dbg(component->dev, "ad82128 i2c address = %p,  %s!\n",
		component, __func__);
	ret = regulator_bulk_enable(ARRAY_SIZE(ad82128->supplies),
		ad82128->supplies);
	if (ret != 0) {
		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
		return;
	}

	/* Set device to mute */
	ad82128_mute(component, 1);

	// Write register table
	for (i = 0; i < AD82128_REGISTER_COUNT; i++) {
		reg_data = m_reg_tab[i][1];

		if (m_reg_tab[i][0] == 0x02)
			continue;

		if (m_reg_tab[i][0] >= 0x71 && m_reg_tab[i][0] <= 0x7C)
			continue;

		// set stereo
		if (m_reg_tab[i][0] == 0x1A)
			reg_data &= (~0x40);

		if (m_reg_tab[i][0] == 0x5B)
			reg_data = 0x00;

		if (m_reg_tab[i][0] == 0x5C)
			reg_data = 0x00;

		// set stereo end
		ret = regmap_write(ad82128->regmap, m_reg_tab[i][0], reg_data);
		if (ret < 0)
			goto error_snd_soc_component_update_bits;
	}

	// Write ram1
	for (i = 0; i < AD82128_RAM_TABLE_COUNT; i++) {
		regmap_write(ad82128->regmap, CFADDR, m_ram1_tab[i][0]);
		regmap_write(ad82128->regmap, A1CF1, m_ram1_tab[i][1]);
		regmap_write(ad82128->regmap, A1CF2, m_ram1_tab[i][2]);
		regmap_write(ad82128->regmap, A1CF3, m_ram1_tab[i][3]);
		regmap_write(ad82128->regmap, A1CF4, m_ram1_tab[i][4]);
		regmap_write(ad82128->regmap, CFUD, 0x01);
	}
	// Write ram2
	for (i = 0; i < AD82128_RAM_TABLE_COUNT; i++) {
		regmap_write(ad82128->regmap, CFADDR, m_ram2_tab[i][0]);
		regmap_write(ad82128->regmap, A1CF1, m_ram2_tab[i][1]);
		regmap_write(ad82128->regmap, A1CF2, m_ram2_tab[i][2]);
		regmap_write(ad82128->regmap, A1CF3, m_ram2_tab[i][3]);
		regmap_write(ad82128->regmap, A1CF4, m_ram2_tab[i][4]);
		regmap_write(ad82128->regmap, CFUD, 0x41);
	}

	usleep_range(2 * 1000, 3 * 1000);

	/* Set device to unmute */
	ad82128_mute(component, 0);

#ifdef DEBUG_AD82128_SDZ
	INIT_DELAYED_WORK(&ad82128->fault_check_work, ad82128_fault_check_work);
#endif

	ad82128->init_done = 1;
	return;
error_snd_soc_component_update_bits:
	dev_err(component->dev, "error configuring device registers: %d\n", ret);
}

static int ad82128_codec_probe(struct snd_soc_component *component)
{
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);

	ad82128->component = component;
	ad82128->mute = 0;

	// software reset amp
	snd_soc_component_update_bits(component, AD82128_STATE_CTRL5_REG,
		AD82128_SW_RESET, 0);
	usleep_range(5 * 1000, 6 * 1000);
	snd_soc_component_update_bits(component, AD82128_STATE_CTRL5_REG,
		AD82128_SW_RESET, AD82128_SW_RESET);
	msleep(20);
	INIT_WORK(&ad82128->work, ad82128_init_func);
	schedule_work(&ad82128->work);

	return 0;
}

static void ad82128_codec_remove(struct snd_soc_component *component)
{
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);
	int ret;

#ifdef DEBUG_AD82128_SDZ
	cancel_delayed_work_sync(&ad82128->fault_check_work);
#endif

	ret = regulator_bulk_disable(ARRAY_SIZE(ad82128->supplies),
		ad82128->supplies);
	if (ret < 0)
		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
};

static int ad82128_dac_event(struct snd_soc_dapm_widget *w,
	struct snd_kcontrol *kcontrol, int event)
{
	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);

	// wait until codec ready
	while (!ad82128->init_done) {
		dev_err(component->dev, "wait for ad82128 init done\n");
		msleep(20);
	}
	if (event & SND_SOC_DAPM_POST_PMU) {
		/*
		 * Observe codec shutdown-to-active time. The datasheet only
		 * lists a nominal value however just use-it as-is without
		 * additional padding to minimize the delay introduced in
		 * starting to play audio (actually there is other setup done
		 * by the ASoC framework that will provide additional delays,
		 * so we should always be safe).
		 */
		msleep(25);

		if (!ad82128->mute)
			ad82128_mute(component, 0);
		/* Turn on AD82128 periodic fault checking/handling */
		ad82128->last_fault = 0xFE;

#ifdef DEBUG_AD82128_SDZ
		schedule_delayed_work(&ad82128->fault_check_work,
			msecs_to_jiffies(AD82128_FAULT_CHECK_INTERVAL));
#endif
	} else if (event & SND_SOC_DAPM_PRE_PMD) {
		/* Disable AD82128 periodic fault checking/handling */

#ifdef DEBUG_AD82128_SDZ
		cancel_delayed_work_sync(&ad82128->fault_check_work);
#endif
		/* Place AD82128 in shutdown mode to minimize current draw */
		if (!ad82128->mute)
			ad82128_mute(component, 1);

		msleep(20);
	}

	return 0;
}

#ifdef CONFIG_PM
static int ad82128_suspend(struct snd_soc_component *component)
{
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);
	int ret;

	regcache_cache_only(ad82128->regmap, true);
	regcache_mark_dirty(ad82128->regmap);

	ret = regulator_bulk_disable(ARRAY_SIZE(ad82128->supplies),
		ad82128->supplies);
	if (ret < 0)
		dev_err(component->dev, "failed to disable supplies: %d\n", ret);

	if (ad82128->reset_pin >= 0) {
		gpio_direction_output(ad82128->reset_pin, 0);
		msleep(20);
	}
	pr_info("ad82128_suspend\n");

	return ret;
}

static int ad82128_resume(struct snd_soc_component *component)
{
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);
	int ret;

	ret = regulator_bulk_enable(ARRAY_SIZE(ad82128->supplies),
		ad82128->supplies);
	if (ret < 0) {
		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
		return ret;
	}

	if (ad82128->reset_pin >= 0) {
		gpio_direction_output(ad82128->reset_pin, 0);
		msleep(20);
		gpio_direction_output(ad82128->reset_pin, 1);
		/* need delay before regcache for spec request */
		msleep(20);
	}
	// software reset amp
	snd_soc_component_update_bits(component, AD82128_STATE_CTRL5_REG,
		AD82128_SW_RESET, 0);
	usleep_range(5 * 1000, 6 * 1000);
	snd_soc_component_update_bits(component, AD82128_STATE_CTRL5_REG,
		AD82128_SW_RESET, AD82128_SW_RESET);
	msleep(20);

	regcache_cache_only(ad82128->regmap, false);

	ret = regcache_sync(ad82128->regmap);
	if (ret < 0) {
		dev_err(component->dev, "failed to sync regcache: %d\n", ret);
		return ret;
	}
	ad82128_mute(component, ad82128->mute);
	pr_info("ad82128_resume mute %d\n", ad82128->mute);

	return 0;
}
#else
#define ad82128_suspend NULL
#define ad82128_resume NULL
#endif

static bool ad82128_is_volatile_reg(struct device *dev, unsigned int reg)
{
#ifdef AD82128_REG_RAM_CHECK
	if (reg < AD82128_MAX_REG)
		return true;
	else
		return false;
#else
	switch (reg) {
	case AD82128_FAULT_REG:
	case AD82128_STATE_CTRL1_REG:
	case AD82128_STATE_CTRL2_REG:
	case AD82128_STATE_CTRL3_REG:
	case AD82128_STATE_CTRL5_REG:
		return true;
	default:
		return false;
	}
#endif
}

static const struct regmap_config ad82128_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
	.max_register = AD82128_MAX_REG,
	.cache_type = REGCACHE_RBTREE,
	.volatile_reg = ad82128_is_volatile_reg,
};

/*
 * DAC analog gain. There are four discrete values to select from, ranging
 * from 19.2 dB to 26.3dB.
 */
static const DECLARE_TLV_DB_RANGE(dac_analog_tlv,
	0x0, 0x0, TLV_DB_SCALE_ITEM(1920, 0, 0),
	0x1, 0x1, TLV_DB_SCALE_ITEM(2070, 0, 0),
	0x2, 0x2, TLV_DB_SCALE_ITEM(2350, 0, 0),
	0x3, 0x3, TLV_DB_SCALE_ITEM(2630, 0, 0),
);

/*
 * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
 * setting the gain below -100 dB (register value <0x7) is effectively a MUTE
 * as per device datasheet.
 */
static const DECLARE_TLV_DB_SCALE(chvol_tlv, -10300, 50, 1);

static const struct snd_kcontrol_new ad82128_snd_controls[] = {
	{
	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	 .name = "Master Volume",
	 .info = ad82128_vol_info,
	 .get = ad82128_vol_locked_get,
	 .put = ad82128_vol_locked_put,
	 },
	SOC_SINGLE_TLV("Ch1 Volume", AD82128_VOLUME_CTRL_REG_CH1,
		0, 0xff, 1, chvol_tlv),
	SOC_SINGLE_TLV("Ch2 Volume", AD82128_VOLUME_CTRL_REG_CH2,
		0, 0xff, 1, chvol_tlv),
	SOC_SINGLE_TLV("Speaker Driver Analog Gain", AD82128_ANALOG_CTRL_REG,
		AD82128_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
	{
	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
	 .name = "Master Mute",
	 .info = ad82128_mute_info,
	 .get = ad82128_mute_locked_get,
	 .put = ad82128_mute_locked_put,
	},
};

static int ad82128_trigger(struct snd_pcm_substream *substream, int cmd,
			       struct snd_soc_dai *codec_dai)
{
	struct ad82128_data *ad82128 = snd_soc_dai_get_drvdata(codec_dai);
	struct snd_soc_component *component = ad82128->component;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		switch (cmd) {
		case SNDRV_PCM_TRIGGER_START:
		case SNDRV_PCM_TRIGGER_RESUME:
		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
			if (!ad82128->mute)
				ad82128_mute(component, 0);
			break;
		case SNDRV_PCM_TRIGGER_STOP:
		case SNDRV_PCM_TRIGGER_SUSPEND:
		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
			if (!ad82128->mute)
				ad82128_mute(component, 1);
			break;
		}
	}
	return 0;
}

static const struct snd_soc_dapm_widget ad82128_dapm_widgets[] = {
	SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, ad82128_dac_event,
		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
	SND_SOC_DAPM_OUTPUT("OUT")
};

static const struct snd_soc_dapm_route ad82128_audio_map[] = {
	{ "DAC", NULL, "DAC IN" },
	{ "OUT", NULL, "DAC" },
};

static const struct snd_soc_component_driver soc_component_dev_ad82128 = {
	.probe = ad82128_codec_probe,
	.remove = ad82128_codec_remove,
	.suspend = ad82128_suspend,
	.resume = ad82128_resume,
	.controls = ad82128_snd_controls,
	.num_controls = ARRAY_SIZE(ad82128_snd_controls),
	.dapm_widgets = ad82128_dapm_widgets,
	.num_dapm_widgets = ARRAY_SIZE(ad82128_dapm_widgets),
	.dapm_routes = ad82128_audio_map,
	.num_dapm_routes = ARRAY_SIZE(ad82128_audio_map),
	.idle_bias_on = 1,
	.use_pmdown_time = 1,
	.endianness = 1,
	.non_legacy_dai_naming = 1,
};

/* PCM rates supported by the AD82128 driver */
#define AD82128_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
	SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)

/* Formats supported by AD82128 driver */
#define AD82128_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
	SNDRV_PCM_FMTBIT_S20_LE | \
	SNDRV_PCM_FMTBIT_S24_LE | \
	SNDRV_PCM_FMTBIT_S32_LE)

static int ad82128_mute_stream
		(struct snd_soc_dai *dai, int mute,
		int stream)
{
	struct snd_soc_component *component = dai->component;
	struct ad82128_data *ad82128 = snd_soc_component_get_drvdata(component);

	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
		if (mute)
			ad82128_mute(component, 1);
		else if (!mute && !ad82128->mute)
			ad82128_mute(component, 0);
	}

	return 0;
}

static const struct snd_soc_dai_ops ad82128_speaker_dai_ops = {
	.hw_params = ad82128_hw_params,
	.set_fmt = ad82128_set_dai_fmt,
	.mute_stream = ad82128_mute_stream,
	.trigger = ad82128_trigger,
};

/*
 * AD82128 DAI structure
 *
 * Note that were are advertising .playback.channels_max = 2 despite this being
 * a mono amplifier. The reason for that is that some serial ports such as ESMT's
 * McASP module have a minimum number of channels (2) that they can output.
 * Advertising more channels than we have will allow us to interface with such
 * a serial port without really any negative side effects as the AD82128 will
 * simply ignore any extra channel(s) asides from the one channel that is
 * configured to be played back.
 */
static struct snd_soc_dai_driver ad82128_dai[] = {
	{
		.name = "ad82128",
		.playback = {
			.stream_name = "Playback",
			.channels_min = 1,
			.channels_max = 2,
			.rates = AD82128_RATES,
			.formats = AD82128_FORMATS,
		},
		.ops = &ad82128_speaker_dai_ops,
	},
};

static int ad82128_parse_dt(struct ad82128_data *ad82128,
	struct device_node *np)
{
	int ret = 0;
	int reset_pin = -1;

	reset_pin = of_get_named_gpio(np, "reset_pin", 0);
	if (reset_pin < 0) {
		ret = -1;
		reset_pin = -1;
	} else {
		pr_info("%s pdata->reset_pin = %d!\n", __func__,
			reset_pin);
	}
	ad82128->reset_pin = reset_pin;

	return ret;
}

static int ad82128_probe(struct i2c_client *client,
	const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct ad82128_data *data;
	const struct regmap_config *regmap_config;
	int ret;
	int i;

	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;
	data->init_done = 0;
	data->ad82128_client = client;
	data->devtype = id->driver_data;
	ret = ad82128_parse_dt(data, client->dev.of_node);
	if (data->reset_pin > 0) {
		// request amp PD pin control GPIO
		ret = gpio_request(data->reset_pin, NULL);
		if (ret < 0)
			dev_err(dev, "failed to request gpio: %d\n", ret);
		// pull high amp PD pin
		gpio_direction_output(data->reset_pin, 1);
		msleep(150);
	}

	switch (id->driver_data) {
	case AD82128:
		regmap_config = &ad82128_regmap_config;
		break;
	default:
		dev_err(dev, "unexpected private driver data\n");
		return -EINVAL;
	}
	data->regmap = devm_regmap_init_i2c(client, regmap_config);
	if (IS_ERR(data->regmap)) {
		ret = PTR_ERR(data->regmap);
		dev_err(dev, "failed to allocate register map: %d\n", ret);
		return ret;
	}

	for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
		data->supplies[i].supply = ad82128_supply_names[i];

	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
		data->supplies);
	if (ret != 0) {
		dev_err(dev, "failed to request supplies: %d\n", ret);
		return ret;
	}

	dev_set_drvdata(dev, data);

	ret = devm_snd_soc_register_component(&client->dev,
		&soc_component_dev_ad82128,
		ad82128_dai, ARRAY_SIZE(ad82128_dai));
	if (ret < 0) {
		dev_err(dev, "failed to register component: %d\n", ret);
		return ret;
	}

	return 0;
}

static void ad82128_i2c_shutdown(struct i2c_client *client)
{
	struct ad82128_data *data = i2c_get_clientdata(client);

	if (!data)
		return;

	if (data->reset_pin)
		gpio_direction_output(data->reset_pin, GPIOF_OUT_INIT_LOW);
}

static const struct i2c_device_id ad82128_id[] = {
	{ "ad82128", AD82128 },
	{}
};

MODULE_DEVICE_TABLE(i2c, ad82128_id);

#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id ad82128_of_match[] = {
	{
		.compatible = "ESMT,ad82128",
	},
	{},
};
MODULE_DEVICE_TABLE(of, ad82128_of_match);
#endif

static struct i2c_driver ad82128_i2c_driver = {
	.driver = {
		.name = "ad82128",
		.of_match_table = of_match_ptr(ad82128_of_match),
	},
	.probe = ad82128_probe,
	.shutdown = ad82128_i2c_shutdown,
	.id_table = ad82128_id,
};

module_i2c_driver(ad82128_i2c_driver);

MODULE_AUTHOR("ESMT BU2");
MODULE_DESCRIPTION("AD82128 Audio amplifier driver");
MODULE_LICENSE("GPL");
