18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * tas2552.c - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Texas Instruments Incorporated -  https://www.ti.com
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Dan Murphy <dmurphy@ti.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/gpio.h>
158c2ecf20Sopenharmony_ci#include <linux/of_gpio.h>
168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
178c2ecf20Sopenharmony_ci#include <linux/regmap.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
218c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <sound/pcm.h>
248c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
258c2ecf20Sopenharmony_ci#include <sound/soc.h>
268c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h>
278c2ecf20Sopenharmony_ci#include <sound/tlv.h>
288c2ecf20Sopenharmony_ci#include <sound/tas2552-plat.h>
298c2ecf20Sopenharmony_ci#include <dt-bindings/sound/tas2552.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "tas2552.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic const struct reg_default tas2552_reg_defs[] = {
348c2ecf20Sopenharmony_ci	{TAS2552_CFG_1, 0x22},
358c2ecf20Sopenharmony_ci	{TAS2552_CFG_3, 0x80},
368c2ecf20Sopenharmony_ci	{TAS2552_DOUT, 0x00},
378c2ecf20Sopenharmony_ci	{TAS2552_OUTPUT_DATA, 0xc0},
388c2ecf20Sopenharmony_ci	{TAS2552_PDM_CFG, 0x01},
398c2ecf20Sopenharmony_ci	{TAS2552_PGA_GAIN, 0x00},
408c2ecf20Sopenharmony_ci	{TAS2552_BOOST_APT_CTRL, 0x0f},
418c2ecf20Sopenharmony_ci	{TAS2552_RESERVED_0D, 0xbe},
428c2ecf20Sopenharmony_ci	{TAS2552_LIMIT_RATE_HYS, 0x08},
438c2ecf20Sopenharmony_ci	{TAS2552_CFG_2, 0xef},
448c2ecf20Sopenharmony_ci	{TAS2552_SER_CTRL_1, 0x00},
458c2ecf20Sopenharmony_ci	{TAS2552_SER_CTRL_2, 0x00},
468c2ecf20Sopenharmony_ci	{TAS2552_PLL_CTRL_1, 0x10},
478c2ecf20Sopenharmony_ci	{TAS2552_PLL_CTRL_2, 0x00},
488c2ecf20Sopenharmony_ci	{TAS2552_PLL_CTRL_3, 0x00},
498c2ecf20Sopenharmony_ci	{TAS2552_BTIP, 0x8f},
508c2ecf20Sopenharmony_ci	{TAS2552_BTS_CTRL, 0x80},
518c2ecf20Sopenharmony_ci	{TAS2552_LIMIT_RELEASE, 0x04},
528c2ecf20Sopenharmony_ci	{TAS2552_LIMIT_INT_COUNT, 0x00},
538c2ecf20Sopenharmony_ci	{TAS2552_EDGE_RATE_CTRL, 0x40},
548c2ecf20Sopenharmony_ci	{TAS2552_VBAT_DATA, 0x00},
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define TAS2552_NUM_SUPPLIES	3
588c2ecf20Sopenharmony_cistatic const char *tas2552_supply_names[TAS2552_NUM_SUPPLIES] = {
598c2ecf20Sopenharmony_ci	"vbat",		/* vbat voltage */
608c2ecf20Sopenharmony_ci	"iovdd",	/* I/O Voltage */
618c2ecf20Sopenharmony_ci	"avdd",		/* Analog DAC Voltage */
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistruct tas2552_data {
658c2ecf20Sopenharmony_ci	struct snd_soc_component *component;
668c2ecf20Sopenharmony_ci	struct regmap *regmap;
678c2ecf20Sopenharmony_ci	struct i2c_client *tas2552_client;
688c2ecf20Sopenharmony_ci	struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
698c2ecf20Sopenharmony_ci	struct gpio_desc *enable_gpio;
708c2ecf20Sopenharmony_ci	unsigned char regs[TAS2552_VBAT_DATA];
718c2ecf20Sopenharmony_ci	unsigned int pll_clkin;
728c2ecf20Sopenharmony_ci	int pll_clk_id;
738c2ecf20Sopenharmony_ci	unsigned int pdm_clk;
748c2ecf20Sopenharmony_ci	int pdm_clk_id;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	unsigned int dai_fmt;
778c2ecf20Sopenharmony_ci	unsigned int tdm_delay;
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic int tas2552_post_event(struct snd_soc_dapm_widget *w,
818c2ecf20Sopenharmony_ci			      struct snd_kcontrol *kcontrol, int event)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	switch (event) {
868c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_POST_PMU:
878c2ecf20Sopenharmony_ci		snd_soc_component_write(component, TAS2552_RESERVED_0D, 0xc0);
888c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_LIMIT_RATE_HYS, (1 << 5),
898c2ecf20Sopenharmony_ci				    (1 << 5));
908c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_CFG_2, 1, 0);
918c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_SWS, 0);
928c2ecf20Sopenharmony_ci		break;
938c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
948c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_SWS,
958c2ecf20Sopenharmony_ci				    TAS2552_SWS);
968c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_CFG_2, 1, 1);
978c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
988c2ecf20Sopenharmony_ci		snd_soc_component_write(component, TAS2552_RESERVED_0D, 0xbe);
998c2ecf20Sopenharmony_ci		break;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/* Input mux controls */
1058c2ecf20Sopenharmony_cistatic const char * const tas2552_input_texts[] = {
1068c2ecf20Sopenharmony_ci	"Digital", "Analog" };
1078c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
1088c2ecf20Sopenharmony_ci			    tas2552_input_texts);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas2552_input_mux_control =
1118c2ecf20Sopenharmony_ci	SOC_DAPM_ENUM("Route", tas2552_input_mux_enum);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	SND_SOC_DAPM_INPUT("IN"),
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* MUX Controls */
1188c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
1198c2ecf20Sopenharmony_ci			 &tas2552_input_mux_control),
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
1228c2ecf20Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
1238c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
1248c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
1258c2ecf20Sopenharmony_ci	SND_SOC_DAPM_POST("Post Event", tas2552_post_event),
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("OUT")
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route tas2552_audio_map[] = {
1318c2ecf20Sopenharmony_ci	{"DAC", NULL, "DAC IN"},
1328c2ecf20Sopenharmony_ci	{"Input selection", "Digital", "DAC"},
1338c2ecf20Sopenharmony_ci	{"Input selection", "Analog", "IN"},
1348c2ecf20Sopenharmony_ci	{"ClassD", NULL, "Input selection"},
1358c2ecf20Sopenharmony_ci	{"OUT", NULL, "ClassD"},
1368c2ecf20Sopenharmony_ci	{"ClassD", NULL, "PLL"},
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
1408c2ecf20Sopenharmony_cistatic void tas2552_sw_shutdown(struct tas2552_data *tas2552, int sw_shutdown)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	u8 cfg1_reg = 0;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (!tas2552->component)
1458c2ecf20Sopenharmony_ci		return;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (sw_shutdown)
1488c2ecf20Sopenharmony_ci		cfg1_reg = TAS2552_SWS;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(tas2552->component, TAS2552_CFG_1, TAS2552_SWS,
1518c2ecf20Sopenharmony_ci			    cfg1_reg);
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci#endif
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic int tas2552_setup_pll(struct snd_soc_component *component,
1568c2ecf20Sopenharmony_ci			     struct snd_pcm_hw_params *params)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
1598c2ecf20Sopenharmony_ci	bool bypass_pll = false;
1608c2ecf20Sopenharmony_ci	unsigned int pll_clk = params_rate(params) * 512;
1618c2ecf20Sopenharmony_ci	unsigned int pll_clkin = tas2552->pll_clkin;
1628c2ecf20Sopenharmony_ci	u8 pll_enable;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (!pll_clkin) {
1658c2ecf20Sopenharmony_ci		if (tas2552->pll_clk_id != TAS2552_PLL_CLKIN_BCLK)
1668c2ecf20Sopenharmony_ci			return -EINVAL;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		pll_clkin = snd_soc_params_to_bclk(params);
1698c2ecf20Sopenharmony_ci		pll_clkin += tas2552->tdm_delay;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	pll_enable = snd_soc_component_read(component, TAS2552_CFG_2) & TAS2552_PLL_ENABLE;
1738c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (pll_clkin == pll_clk)
1768c2ecf20Sopenharmony_ci		bypass_pll = true;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (bypass_pll) {
1798c2ecf20Sopenharmony_ci		/* By pass the PLL configuration */
1808c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_PLL_CTRL_2,
1818c2ecf20Sopenharmony_ci				    TAS2552_PLL_BYPASS, TAS2552_PLL_BYPASS);
1828c2ecf20Sopenharmony_ci	} else {
1838c2ecf20Sopenharmony_ci		/* Fill in the PLL control registers for J & D
1848c2ecf20Sopenharmony_ci		 * pll_clk = (.5 * pll_clkin * J.D) / 2^p
1858c2ecf20Sopenharmony_ci		 * Need to fill in J and D here based on incoming freq
1868c2ecf20Sopenharmony_ci		 */
1878c2ecf20Sopenharmony_ci		unsigned int d, q, t;
1888c2ecf20Sopenharmony_ci		u8 j;
1898c2ecf20Sopenharmony_ci		u8 pll_sel = (tas2552->pll_clk_id << 3) & TAS2552_PLL_SRC_MASK;
1908c2ecf20Sopenharmony_ci		u8 p = snd_soc_component_read(component, TAS2552_PLL_CTRL_1);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		p = (p >> 7);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cirecalc:
1958c2ecf20Sopenharmony_ci		t = (pll_clk * 2) << p;
1968c2ecf20Sopenharmony_ci		j = t / pll_clkin;
1978c2ecf20Sopenharmony_ci		d = t % pll_clkin;
1988c2ecf20Sopenharmony_ci		t = pll_clkin / 10000;
1998c2ecf20Sopenharmony_ci		q = d / (t + 1);
2008c2ecf20Sopenharmony_ci		d = q + ((9999 - pll_clkin % 10000) * (d / t - q)) / 10000;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		if (d && (pll_clkin < 512000 || pll_clkin > 9200000)) {
2038c2ecf20Sopenharmony_ci			if (tas2552->pll_clk_id == TAS2552_PLL_CLKIN_BCLK) {
2048c2ecf20Sopenharmony_ci				pll_clkin = 1800000;
2058c2ecf20Sopenharmony_ci				pll_sel = (TAS2552_PLL_CLKIN_1_8_FIXED << 3) &
2068c2ecf20Sopenharmony_ci							TAS2552_PLL_SRC_MASK;
2078c2ecf20Sopenharmony_ci			} else {
2088c2ecf20Sopenharmony_ci				pll_clkin = snd_soc_params_to_bclk(params);
2098c2ecf20Sopenharmony_ci				pll_clkin += tas2552->tdm_delay;
2108c2ecf20Sopenharmony_ci				pll_sel = (TAS2552_PLL_CLKIN_BCLK << 3) &
2118c2ecf20Sopenharmony_ci							TAS2552_PLL_SRC_MASK;
2128c2ecf20Sopenharmony_ci			}
2138c2ecf20Sopenharmony_ci			goto recalc;
2148c2ecf20Sopenharmony_ci		}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_PLL_SRC_MASK,
2178c2ecf20Sopenharmony_ci				    pll_sel);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		snd_soc_component_update_bits(component, TAS2552_PLL_CTRL_1,
2208c2ecf20Sopenharmony_ci				    TAS2552_PLL_J_MASK, j);
2218c2ecf20Sopenharmony_ci		/* Will clear the PLL_BYPASS bit */
2228c2ecf20Sopenharmony_ci		snd_soc_component_write(component, TAS2552_PLL_CTRL_2,
2238c2ecf20Sopenharmony_ci			      TAS2552_PLL_D_UPPER(d));
2248c2ecf20Sopenharmony_ci		snd_soc_component_write(component, TAS2552_PLL_CTRL_3,
2258c2ecf20Sopenharmony_ci			      TAS2552_PLL_D_LOWER(d));
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	/* Restore PLL status */
2298c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
2308c2ecf20Sopenharmony_ci			    pll_enable);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return 0;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int tas2552_hw_params(struct snd_pcm_substream *substream,
2368c2ecf20Sopenharmony_ci			     struct snd_pcm_hw_params *params,
2378c2ecf20Sopenharmony_ci			     struct snd_soc_dai *dai)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
2408c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
2418c2ecf20Sopenharmony_ci	int cpf;
2428c2ecf20Sopenharmony_ci	u8 ser_ctrl1_reg, wclk_rate;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	switch (params_width(params)) {
2458c2ecf20Sopenharmony_ci	case 16:
2468c2ecf20Sopenharmony_ci		ser_ctrl1_reg = TAS2552_WORDLENGTH_16BIT;
2478c2ecf20Sopenharmony_ci		cpf = 32 + tas2552->tdm_delay;
2488c2ecf20Sopenharmony_ci		break;
2498c2ecf20Sopenharmony_ci	case 20:
2508c2ecf20Sopenharmony_ci		ser_ctrl1_reg = TAS2552_WORDLENGTH_20BIT;
2518c2ecf20Sopenharmony_ci		cpf = 64 + tas2552->tdm_delay;
2528c2ecf20Sopenharmony_ci		break;
2538c2ecf20Sopenharmony_ci	case 24:
2548c2ecf20Sopenharmony_ci		ser_ctrl1_reg = TAS2552_WORDLENGTH_24BIT;
2558c2ecf20Sopenharmony_ci		cpf = 64 + tas2552->tdm_delay;
2568c2ecf20Sopenharmony_ci		break;
2578c2ecf20Sopenharmony_ci	case 32:
2588c2ecf20Sopenharmony_ci		ser_ctrl1_reg = TAS2552_WORDLENGTH_32BIT;
2598c2ecf20Sopenharmony_ci		cpf = 64 + tas2552->tdm_delay;
2608c2ecf20Sopenharmony_ci		break;
2618c2ecf20Sopenharmony_ci	default:
2628c2ecf20Sopenharmony_ci		dev_err(component->dev, "Not supported sample size: %d\n",
2638c2ecf20Sopenharmony_ci			params_width(params));
2648c2ecf20Sopenharmony_ci		return -EINVAL;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (cpf <= 32)
2688c2ecf20Sopenharmony_ci		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_32;
2698c2ecf20Sopenharmony_ci	else if (cpf <= 64)
2708c2ecf20Sopenharmony_ci		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_64;
2718c2ecf20Sopenharmony_ci	else if (cpf <= 128)
2728c2ecf20Sopenharmony_ci		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_128;
2738c2ecf20Sopenharmony_ci	else
2748c2ecf20Sopenharmony_ci		ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_256;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, TAS2552_SER_CTRL_1,
2778c2ecf20Sopenharmony_ci			    TAS2552_WORDLENGTH_MASK | TAS2552_CLKSPERFRAME_MASK,
2788c2ecf20Sopenharmony_ci			    ser_ctrl1_reg);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	switch (params_rate(params)) {
2818c2ecf20Sopenharmony_ci	case 8000:
2828c2ecf20Sopenharmony_ci		wclk_rate = TAS2552_WCLK_FREQ_8KHZ;
2838c2ecf20Sopenharmony_ci		break;
2848c2ecf20Sopenharmony_ci	case 11025:
2858c2ecf20Sopenharmony_ci	case 12000:
2868c2ecf20Sopenharmony_ci		wclk_rate = TAS2552_WCLK_FREQ_11_12KHZ;
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	case 16000:
2898c2ecf20Sopenharmony_ci		wclk_rate = TAS2552_WCLK_FREQ_16KHZ;
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	case 22050:
2928c2ecf20Sopenharmony_ci	case 24000:
2938c2ecf20Sopenharmony_ci		wclk_rate = TAS2552_WCLK_FREQ_22_24KHZ;
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	case 32000:
2968c2ecf20Sopenharmony_ci		wclk_rate = TAS2552_WCLK_FREQ_32KHZ;
2978c2ecf20Sopenharmony_ci		break;
2988c2ecf20Sopenharmony_ci	case 44100:
2998c2ecf20Sopenharmony_ci	case 48000:
3008c2ecf20Sopenharmony_ci		wclk_rate = TAS2552_WCLK_FREQ_44_48KHZ;
3018c2ecf20Sopenharmony_ci		break;
3028c2ecf20Sopenharmony_ci	case 88200:
3038c2ecf20Sopenharmony_ci	case 96000:
3048c2ecf20Sopenharmony_ci		wclk_rate = TAS2552_WCLK_FREQ_88_96KHZ;
3058c2ecf20Sopenharmony_ci		break;
3068c2ecf20Sopenharmony_ci	case 176400:
3078c2ecf20Sopenharmony_ci	case 192000:
3088c2ecf20Sopenharmony_ci		wclk_rate = TAS2552_WCLK_FREQ_176_192KHZ;
3098c2ecf20Sopenharmony_ci		break;
3108c2ecf20Sopenharmony_ci	default:
3118c2ecf20Sopenharmony_ci		dev_err(component->dev, "Not supported sample rate: %d\n",
3128c2ecf20Sopenharmony_ci			params_rate(params));
3138c2ecf20Sopenharmony_ci		return -EINVAL;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
3178c2ecf20Sopenharmony_ci			    wclk_rate);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return tas2552_setup_pll(component, params);
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci#define TAS2552_DAI_FMT_MASK	(TAS2552_BCLKDIR | \
3238c2ecf20Sopenharmony_ci				 TAS2552_WCLKDIR | \
3248c2ecf20Sopenharmony_ci				 TAS2552_DATAFORMAT_MASK)
3258c2ecf20Sopenharmony_cistatic int tas2552_prepare(struct snd_pcm_substream *substream,
3268c2ecf20Sopenharmony_ci			   struct snd_soc_dai *dai)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
3298c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
3308c2ecf20Sopenharmony_ci	int delay = 0;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* TDM slot selection only valid in DSP_A/_B mode */
3338c2ecf20Sopenharmony_ci	if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_A)
3348c2ecf20Sopenharmony_ci		delay += (tas2552->tdm_delay + 1);
3358c2ecf20Sopenharmony_ci	else if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_B)
3368c2ecf20Sopenharmony_ci		delay += tas2552->tdm_delay;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/* Configure data delay */
3398c2ecf20Sopenharmony_ci	snd_soc_component_write(component, TAS2552_SER_CTRL_2, delay);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return 0;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
3478c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
3488c2ecf20Sopenharmony_ci	u8 serial_format;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3518c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFS:
3528c2ecf20Sopenharmony_ci		serial_format = 0x00;
3538c2ecf20Sopenharmony_ci		break;
3548c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFM:
3558c2ecf20Sopenharmony_ci		serial_format = TAS2552_WCLKDIR;
3568c2ecf20Sopenharmony_ci		break;
3578c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFS:
3588c2ecf20Sopenharmony_ci		serial_format = TAS2552_BCLKDIR;
3598c2ecf20Sopenharmony_ci		break;
3608c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFM:
3618c2ecf20Sopenharmony_ci		serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
3628c2ecf20Sopenharmony_ci		break;
3638c2ecf20Sopenharmony_ci	default:
3648c2ecf20Sopenharmony_ci		dev_vdbg(component->dev, "DAI Format master is not found\n");
3658c2ecf20Sopenharmony_ci		return -EINVAL;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
3698c2ecf20Sopenharmony_ci		       SND_SOC_DAIFMT_INV_MASK)) {
3708c2ecf20Sopenharmony_ci	case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
3718c2ecf20Sopenharmony_ci		break;
3728c2ecf20Sopenharmony_ci	case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
3738c2ecf20Sopenharmony_ci	case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
3748c2ecf20Sopenharmony_ci		serial_format |= TAS2552_DATAFORMAT_DSP;
3758c2ecf20Sopenharmony_ci		break;
3768c2ecf20Sopenharmony_ci	case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
3778c2ecf20Sopenharmony_ci		serial_format |= TAS2552_DATAFORMAT_RIGHT_J;
3788c2ecf20Sopenharmony_ci		break;
3798c2ecf20Sopenharmony_ci	case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
3808c2ecf20Sopenharmony_ci		serial_format |= TAS2552_DATAFORMAT_LEFT_J;
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	default:
3838c2ecf20Sopenharmony_ci		dev_vdbg(component->dev, "DAI Format is not found\n");
3848c2ecf20Sopenharmony_ci		return -EINVAL;
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci	tas2552->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK,
3898c2ecf20Sopenharmony_ci			    serial_format);
3908c2ecf20Sopenharmony_ci	return 0;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
3948c2ecf20Sopenharmony_ci				  unsigned int freq, int dir)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
3978c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
3988c2ecf20Sopenharmony_ci	u8 reg, mask, val;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	switch (clk_id) {
4018c2ecf20Sopenharmony_ci	case TAS2552_PLL_CLKIN_MCLK:
4028c2ecf20Sopenharmony_ci	case TAS2552_PLL_CLKIN_IVCLKIN:
4038c2ecf20Sopenharmony_ci		if (freq < 512000 || freq > 24576000) {
4048c2ecf20Sopenharmony_ci			/* out of range PLL_CLKIN, fall back to use BCLK */
4058c2ecf20Sopenharmony_ci			dev_warn(component->dev, "Out of range PLL_CLKIN: %u\n",
4068c2ecf20Sopenharmony_ci				 freq);
4078c2ecf20Sopenharmony_ci			clk_id = TAS2552_PLL_CLKIN_BCLK;
4088c2ecf20Sopenharmony_ci			freq = 0;
4098c2ecf20Sopenharmony_ci		}
4108c2ecf20Sopenharmony_ci		fallthrough;
4118c2ecf20Sopenharmony_ci	case TAS2552_PLL_CLKIN_BCLK:
4128c2ecf20Sopenharmony_ci	case TAS2552_PLL_CLKIN_1_8_FIXED:
4138c2ecf20Sopenharmony_ci		mask = TAS2552_PLL_SRC_MASK;
4148c2ecf20Sopenharmony_ci		val = (clk_id << 3) & mask; /* bit 4:5 in the register */
4158c2ecf20Sopenharmony_ci		reg = TAS2552_CFG_1;
4168c2ecf20Sopenharmony_ci		tas2552->pll_clk_id = clk_id;
4178c2ecf20Sopenharmony_ci		tas2552->pll_clkin = freq;
4188c2ecf20Sopenharmony_ci		break;
4198c2ecf20Sopenharmony_ci	case TAS2552_PDM_CLK_PLL:
4208c2ecf20Sopenharmony_ci	case TAS2552_PDM_CLK_IVCLKIN:
4218c2ecf20Sopenharmony_ci	case TAS2552_PDM_CLK_BCLK:
4228c2ecf20Sopenharmony_ci	case TAS2552_PDM_CLK_MCLK:
4238c2ecf20Sopenharmony_ci		mask = TAS2552_PDM_CLK_SEL_MASK;
4248c2ecf20Sopenharmony_ci		val = (clk_id >> 1) & mask; /* bit 0:1 in the register */
4258c2ecf20Sopenharmony_ci		reg = TAS2552_PDM_CFG;
4268c2ecf20Sopenharmony_ci		tas2552->pdm_clk_id = clk_id;
4278c2ecf20Sopenharmony_ci		tas2552->pdm_clk = freq;
4288c2ecf20Sopenharmony_ci		break;
4298c2ecf20Sopenharmony_ci	default:
4308c2ecf20Sopenharmony_ci		dev_err(component->dev, "Invalid clk id: %d\n", clk_id);
4318c2ecf20Sopenharmony_ci		return -EINVAL;
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, reg, mask, val);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	return 0;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai,
4408c2ecf20Sopenharmony_ci				    unsigned int tx_mask, unsigned int rx_mask,
4418c2ecf20Sopenharmony_ci				    int slots, int slot_width)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
4448c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
4458c2ecf20Sopenharmony_ci	unsigned int lsb;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (unlikely(!tx_mask)) {
4488c2ecf20Sopenharmony_ci		dev_err(component->dev, "tx masks need to be non 0\n");
4498c2ecf20Sopenharmony_ci		return -EINVAL;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* TDM based on DSP mode requires slots to be adjacent */
4538c2ecf20Sopenharmony_ci	lsb = __ffs(tx_mask);
4548c2ecf20Sopenharmony_ci	if ((lsb + 1) != __fls(tx_mask)) {
4558c2ecf20Sopenharmony_ci		dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
4568c2ecf20Sopenharmony_ci		return -EINVAL;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	tas2552->tdm_delay = lsb * slot_width;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* DOUT in high-impedance on inactive bit clocks */
4628c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, TAS2552_DOUT,
4638c2ecf20Sopenharmony_ci			    TAS2552_SDOUT_TRISTATE, TAS2552_SDOUT_TRISTATE);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return 0;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic int tas2552_mute(struct snd_soc_dai *dai, int mute, int direction)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	u8 cfg1_reg = 0;
4718c2ecf20Sopenharmony_ci	struct snd_soc_component *component = dai->component;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if (mute)
4748c2ecf20Sopenharmony_ci		cfg1_reg |= TAS2552_MUTE;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	return 0;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
4828c2ecf20Sopenharmony_cistatic int tas2552_runtime_suspend(struct device *dev)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = dev_get_drvdata(dev);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	tas2552_sw_shutdown(tas2552, 1);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	regcache_cache_only(tas2552->regmap, true);
4898c2ecf20Sopenharmony_ci	regcache_mark_dirty(tas2552->regmap);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	gpiod_set_value(tas2552->enable_gpio, 0);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	return 0;
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic int tas2552_runtime_resume(struct device *dev)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = dev_get_drvdata(dev);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	gpiod_set_value(tas2552->enable_gpio, 1);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	tas2552_sw_shutdown(tas2552, 0);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	regcache_cache_only(tas2552->regmap, false);
5058c2ecf20Sopenharmony_ci	regcache_sync(tas2552->regmap);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return 0;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci#endif
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic const struct dev_pm_ops tas2552_pm = {
5128c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume,
5138c2ecf20Sopenharmony_ci			   NULL)
5148c2ecf20Sopenharmony_ci};
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
5178c2ecf20Sopenharmony_ci	.hw_params	= tas2552_hw_params,
5188c2ecf20Sopenharmony_ci	.prepare	= tas2552_prepare,
5198c2ecf20Sopenharmony_ci	.set_sysclk	= tas2552_set_dai_sysclk,
5208c2ecf20Sopenharmony_ci	.set_fmt	= tas2552_set_dai_fmt,
5218c2ecf20Sopenharmony_ci	.set_tdm_slot	= tas2552_set_dai_tdm_slot,
5228c2ecf20Sopenharmony_ci	.mute_stream	= tas2552_mute,
5238c2ecf20Sopenharmony_ci	.no_capture_mute = 1,
5248c2ecf20Sopenharmony_ci};
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci/* Formats supported by TAS2552 driver. */
5278c2ecf20Sopenharmony_ci#define TAS2552_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
5288c2ecf20Sopenharmony_ci			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci/* TAS2552 dai structure. */
5318c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver tas2552_dai[] = {
5328c2ecf20Sopenharmony_ci	{
5338c2ecf20Sopenharmony_ci		.name = "tas2552-amplifier",
5348c2ecf20Sopenharmony_ci		.playback = {
5358c2ecf20Sopenharmony_ci			.stream_name = "Playback",
5368c2ecf20Sopenharmony_ci			.channels_min = 2,
5378c2ecf20Sopenharmony_ci			.channels_max = 2,
5388c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_192000,
5398c2ecf20Sopenharmony_ci			.formats = TAS2552_FORMATS,
5408c2ecf20Sopenharmony_ci		},
5418c2ecf20Sopenharmony_ci		.ops = &tas2552_speaker_dai_ops,
5428c2ecf20Sopenharmony_ci	},
5438c2ecf20Sopenharmony_ci};
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci/*
5468c2ecf20Sopenharmony_ci * DAC digital volumes. From -7 to 24 dB in 1 dB steps
5478c2ecf20Sopenharmony_ci */
5488c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(dac_tlv, -700, 100, 0);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic const char * const tas2552_din_source_select[] = {
5518c2ecf20Sopenharmony_ci	"Muted",
5528c2ecf20Sopenharmony_ci	"Left",
5538c2ecf20Sopenharmony_ci	"Right",
5548c2ecf20Sopenharmony_ci	"Left + Right average",
5558c2ecf20Sopenharmony_ci};
5568c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(tas2552_din_source_enum,
5578c2ecf20Sopenharmony_ci			    TAS2552_CFG_3, 3,
5588c2ecf20Sopenharmony_ci			    tas2552_din_source_select);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas2552_snd_controls[] = {
5618c2ecf20Sopenharmony_ci	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
5628c2ecf20Sopenharmony_ci			 TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv),
5638c2ecf20Sopenharmony_ci	SOC_ENUM("DIN source", tas2552_din_source_enum),
5648c2ecf20Sopenharmony_ci};
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic int tas2552_component_probe(struct snd_soc_component *component)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
5698c2ecf20Sopenharmony_ci	int ret;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	tas2552->component = component;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
5748c2ecf20Sopenharmony_ci				    tas2552->supplies);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (ret != 0) {
5778c2ecf20Sopenharmony_ci		dev_err(component->dev, "Failed to enable supplies: %d\n",
5788c2ecf20Sopenharmony_ci			ret);
5798c2ecf20Sopenharmony_ci		return ret;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	gpiod_set_value(tas2552->enable_gpio, 1);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(component->dev);
5858c2ecf20Sopenharmony_ci	if (ret < 0) {
5868c2ecf20Sopenharmony_ci		dev_err(component->dev, "Enabling device failed: %d\n",
5878c2ecf20Sopenharmony_ci			ret);
5888c2ecf20Sopenharmony_ci		goto probe_fail;
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	snd_soc_component_update_bits(component, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
5928c2ecf20Sopenharmony_ci	snd_soc_component_write(component, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
5938c2ecf20Sopenharmony_ci					    TAS2552_DIN_SRC_SEL_AVG_L_R);
5948c2ecf20Sopenharmony_ci	snd_soc_component_write(component, TAS2552_OUTPUT_DATA,
5958c2ecf20Sopenharmony_ci		      TAS2552_PDM_DATA_SEL_V_I |
5968c2ecf20Sopenharmony_ci		      TAS2552_R_DATA_OUT(TAS2552_DATA_OUT_V_DATA));
5978c2ecf20Sopenharmony_ci	snd_soc_component_write(component, TAS2552_BOOST_APT_CTRL, TAS2552_APT_DELAY_200 |
5988c2ecf20Sopenharmony_ci						     TAS2552_APT_THRESH_20_17);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	snd_soc_component_write(component, TAS2552_CFG_2, TAS2552_BOOST_EN | TAS2552_APT_EN |
6018c2ecf20Sopenharmony_ci					    TAS2552_LIM_EN);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	return 0;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ciprobe_fail:
6068c2ecf20Sopenharmony_ci	pm_runtime_put_noidle(component->dev);
6078c2ecf20Sopenharmony_ci	gpiod_set_value(tas2552->enable_gpio, 0);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
6108c2ecf20Sopenharmony_ci					tas2552->supplies);
6118c2ecf20Sopenharmony_ci	return ret;
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic void tas2552_component_remove(struct snd_soc_component *component)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	pm_runtime_put(component->dev);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	gpiod_set_value(tas2552->enable_gpio, 0);
6218c2ecf20Sopenharmony_ci};
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
6248c2ecf20Sopenharmony_cistatic int tas2552_suspend(struct snd_soc_component *component)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
6278c2ecf20Sopenharmony_ci	int ret;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	ret = regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
6308c2ecf20Sopenharmony_ci					tas2552->supplies);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (ret != 0)
6338c2ecf20Sopenharmony_ci		dev_err(component->dev, "Failed to disable supplies: %d\n",
6348c2ecf20Sopenharmony_ci			ret);
6358c2ecf20Sopenharmony_ci	return ret;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic int tas2552_resume(struct snd_soc_component *component)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	struct tas2552_data *tas2552 = snd_soc_component_get_drvdata(component);
6418c2ecf20Sopenharmony_ci	int ret;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
6448c2ecf20Sopenharmony_ci				    tas2552->supplies);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (ret != 0) {
6478c2ecf20Sopenharmony_ci		dev_err(component->dev, "Failed to enable supplies: %d\n",
6488c2ecf20Sopenharmony_ci			ret);
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	return ret;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci#else
6548c2ecf20Sopenharmony_ci#define tas2552_suspend NULL
6558c2ecf20Sopenharmony_ci#define tas2552_resume NULL
6568c2ecf20Sopenharmony_ci#endif
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_tas2552 = {
6598c2ecf20Sopenharmony_ci	.probe			= tas2552_component_probe,
6608c2ecf20Sopenharmony_ci	.remove			= tas2552_component_remove,
6618c2ecf20Sopenharmony_ci	.suspend		= tas2552_suspend,
6628c2ecf20Sopenharmony_ci	.resume			= tas2552_resume,
6638c2ecf20Sopenharmony_ci	.controls		= tas2552_snd_controls,
6648c2ecf20Sopenharmony_ci	.num_controls		= ARRAY_SIZE(tas2552_snd_controls),
6658c2ecf20Sopenharmony_ci	.dapm_widgets		= tas2552_dapm_widgets,
6668c2ecf20Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(tas2552_dapm_widgets),
6678c2ecf20Sopenharmony_ci	.dapm_routes		= tas2552_audio_map,
6688c2ecf20Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(tas2552_audio_map),
6698c2ecf20Sopenharmony_ci	.idle_bias_on		= 1,
6708c2ecf20Sopenharmony_ci	.endianness		= 1,
6718c2ecf20Sopenharmony_ci	.non_legacy_dai_naming	= 1,
6728c2ecf20Sopenharmony_ci};
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic const struct regmap_config tas2552_regmap_config = {
6758c2ecf20Sopenharmony_ci	.reg_bits = 8,
6768c2ecf20Sopenharmony_ci	.val_bits = 8,
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	.max_register = TAS2552_MAX_REG,
6798c2ecf20Sopenharmony_ci	.reg_defaults = tas2552_reg_defs,
6808c2ecf20Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(tas2552_reg_defs),
6818c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
6828c2ecf20Sopenharmony_ci};
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic int tas2552_probe(struct i2c_client *client,
6858c2ecf20Sopenharmony_ci			   const struct i2c_device_id *id)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	struct device *dev;
6888c2ecf20Sopenharmony_ci	struct tas2552_data *data;
6898c2ecf20Sopenharmony_ci	int ret;
6908c2ecf20Sopenharmony_ci	int i;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	dev = &client->dev;
6938c2ecf20Sopenharmony_ci	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
6948c2ecf20Sopenharmony_ci	if (data == NULL)
6958c2ecf20Sopenharmony_ci		return -ENOMEM;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	data->enable_gpio = devm_gpiod_get_optional(dev, "enable",
6988c2ecf20Sopenharmony_ci						    GPIOD_OUT_LOW);
6998c2ecf20Sopenharmony_ci	if (IS_ERR(data->enable_gpio))
7008c2ecf20Sopenharmony_ci		return PTR_ERR(data->enable_gpio);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	data->tas2552_client = client;
7038c2ecf20Sopenharmony_ci	data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
7048c2ecf20Sopenharmony_ci	if (IS_ERR(data->regmap)) {
7058c2ecf20Sopenharmony_ci		ret = PTR_ERR(data->regmap);
7068c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Failed to allocate register map: %d\n",
7078c2ecf20Sopenharmony_ci			ret);
7088c2ecf20Sopenharmony_ci		return ret;
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
7128c2ecf20Sopenharmony_ci		data->supplies[i].supply = tas2552_supply_names[i];
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
7158c2ecf20Sopenharmony_ci				      data->supplies);
7168c2ecf20Sopenharmony_ci	if (ret != 0) {
7178c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to request supplies: %d\n", ret);
7188c2ecf20Sopenharmony_ci		return ret;
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	pm_runtime_set_active(&client->dev);
7228c2ecf20Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&client->dev, 1000);
7238c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(&client->dev);
7248c2ecf20Sopenharmony_ci	pm_runtime_enable(&client->dev);
7258c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(&client->dev);
7268c2ecf20Sopenharmony_ci	pm_runtime_put_sync_autosuspend(&client->dev);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	dev_set_drvdata(&client->dev, data);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_component(&client->dev,
7318c2ecf20Sopenharmony_ci				      &soc_component_dev_tas2552,
7328c2ecf20Sopenharmony_ci				      tas2552_dai, ARRAY_SIZE(tas2552_dai));
7338c2ecf20Sopenharmony_ci	if (ret < 0)
7348c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Failed to register component: %d\n", ret);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	return ret;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic int tas2552_i2c_remove(struct i2c_client *client)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	pm_runtime_disable(&client->dev);
7428c2ecf20Sopenharmony_ci	return 0;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic const struct i2c_device_id tas2552_id[] = {
7468c2ecf20Sopenharmony_ci	{ "tas2552", 0 },
7478c2ecf20Sopenharmony_ci	{ }
7488c2ecf20Sopenharmony_ci};
7498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tas2552_id);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_OF)
7528c2ecf20Sopenharmony_cistatic const struct of_device_id tas2552_of_match[] = {
7538c2ecf20Sopenharmony_ci	{ .compatible = "ti,tas2552", },
7548c2ecf20Sopenharmony_ci	{},
7558c2ecf20Sopenharmony_ci};
7568c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tas2552_of_match);
7578c2ecf20Sopenharmony_ci#endif
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic struct i2c_driver tas2552_i2c_driver = {
7608c2ecf20Sopenharmony_ci	.driver = {
7618c2ecf20Sopenharmony_ci		.name = "tas2552",
7628c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(tas2552_of_match),
7638c2ecf20Sopenharmony_ci		.pm = &tas2552_pm,
7648c2ecf20Sopenharmony_ci	},
7658c2ecf20Sopenharmony_ci	.probe = tas2552_probe,
7668c2ecf20Sopenharmony_ci	.remove = tas2552_i2c_remove,
7678c2ecf20Sopenharmony_ci	.id_table = tas2552_id,
7688c2ecf20Sopenharmony_ci};
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cimodule_i2c_driver(tas2552_i2c_driver);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dan Muprhy <dmurphy@ti.com>");
7738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TAS2552 Audio amplifier driver");
7748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
775