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