18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (c) 2020 BayLibre, SAS. 48c2ecf20Sopenharmony_ci// Author: Jerome Brunet <jbrunet@baylibre.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/regmap.h> 108c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/reset.h> 128c2ecf20Sopenharmony_ci#include <sound/soc.h> 138c2ecf20Sopenharmony_ci#include <sound/tlv.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define BLOCK_EN 0x00 168c2ecf20Sopenharmony_ci#define LORN_EN 0 178c2ecf20Sopenharmony_ci#define LORP_EN 1 188c2ecf20Sopenharmony_ci#define LOLN_EN 2 198c2ecf20Sopenharmony_ci#define LOLP_EN 3 208c2ecf20Sopenharmony_ci#define DACR_EN 4 218c2ecf20Sopenharmony_ci#define DACL_EN 5 228c2ecf20Sopenharmony_ci#define DACR_INV 20 238c2ecf20Sopenharmony_ci#define DACL_INV 21 248c2ecf20Sopenharmony_ci#define DACR_SRC 22 258c2ecf20Sopenharmony_ci#define DACL_SRC 23 268c2ecf20Sopenharmony_ci#define REFP_BUF_EN BIT(12) 278c2ecf20Sopenharmony_ci#define BIAS_CURRENT_EN BIT(13) 288c2ecf20Sopenharmony_ci#define VMID_GEN_FAST BIT(14) 298c2ecf20Sopenharmony_ci#define VMID_GEN_EN BIT(15) 308c2ecf20Sopenharmony_ci#define I2S_MODE BIT(30) 318c2ecf20Sopenharmony_ci#define VOL_CTRL0 0x04 328c2ecf20Sopenharmony_ci#define GAIN_H 31 338c2ecf20Sopenharmony_ci#define GAIN_L 23 348c2ecf20Sopenharmony_ci#define VOL_CTRL1 0x08 358c2ecf20Sopenharmony_ci#define DAC_MONO 8 368c2ecf20Sopenharmony_ci#define RAMP_RATE 10 378c2ecf20Sopenharmony_ci#define VC_RAMP_MODE 12 388c2ecf20Sopenharmony_ci#define MUTE_MODE 13 398c2ecf20Sopenharmony_ci#define UNMUTE_MODE 14 408c2ecf20Sopenharmony_ci#define DAC_SOFT_MUTE 15 418c2ecf20Sopenharmony_ci#define DACR_VC 16 428c2ecf20Sopenharmony_ci#define DACL_VC 24 438c2ecf20Sopenharmony_ci#define LINEOUT_CFG 0x0c 448c2ecf20Sopenharmony_ci#define LORN_POL 0 458c2ecf20Sopenharmony_ci#define LORP_POL 4 468c2ecf20Sopenharmony_ci#define LOLN_POL 8 478c2ecf20Sopenharmony_ci#define LOLP_POL 12 488c2ecf20Sopenharmony_ci#define POWER_CFG 0x10 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct t9015 { 518c2ecf20Sopenharmony_ci struct clk *pclk; 528c2ecf20Sopenharmony_ci struct regulator *avdd; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 588c2ecf20Sopenharmony_ci unsigned int val; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 618c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 628c2ecf20Sopenharmony_ci val = I2S_MODE; 638c2ecf20Sopenharmony_ci break; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 668c2ecf20Sopenharmony_ci val = 0; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci default: 708c2ecf20Sopenharmony_ci return -EINVAL; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, BLOCK_EN, I2S_MODE, val); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) && 768c2ecf20Sopenharmony_ci ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_LEFT_J)) 778c2ecf20Sopenharmony_ci return -EINVAL; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops t9015_dai_ops = { 838c2ecf20Sopenharmony_ci .set_fmt = t9015_dai_set_fmt, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver t9015_dai = { 878c2ecf20Sopenharmony_ci .name = "t9015-hifi", 888c2ecf20Sopenharmony_ci .playback = { 898c2ecf20Sopenharmony_ci .stream_name = "Playback", 908c2ecf20Sopenharmony_ci .channels_min = 1, 918c2ecf20Sopenharmony_ci .channels_max = 2, 928c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_96000, 938c2ecf20Sopenharmony_ci .formats = (SNDRV_PCM_FMTBIT_S8 | 948c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | 958c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_LE | 968c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE), 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci .ops = &t9015_dai_ops, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_MINMAX_MUTE(dac_vol_tlv, -9525, 0); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic const char * const ramp_rate_txt[] = { "Fast", "Slow" }; 1048c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(ramp_rate_enum, VOL_CTRL1, RAMP_RATE, 1058c2ecf20Sopenharmony_ci ramp_rate_txt); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic const char * const dacr_in_txt[] = { "Right", "Left" }; 1088c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dacr_in_enum, BLOCK_EN, DACR_SRC, dacr_in_txt); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic const char * const dacl_in_txt[] = { "Left", "Right" }; 1118c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dacl_in_enum, BLOCK_EN, DACL_SRC, dacl_in_txt); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic const char * const mono_txt[] = { "Stereo", "Mono"}; 1148c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(mono_enum, VOL_CTRL1, DAC_MONO, mono_txt); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new t9015_snd_controls[] = { 1178c2ecf20Sopenharmony_ci /* Volume Controls */ 1188c2ecf20Sopenharmony_ci SOC_ENUM("Playback Channel Mode", mono_enum), 1198c2ecf20Sopenharmony_ci SOC_SINGLE("Playback Switch", VOL_CTRL1, DAC_SOFT_MUTE, 1, 1), 1208c2ecf20Sopenharmony_ci SOC_DOUBLE_TLV("Playback Volume", VOL_CTRL1, DACL_VC, DACR_VC, 1218c2ecf20Sopenharmony_ci 0xff, 0, dac_vol_tlv), 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* Ramp Controls */ 1248c2ecf20Sopenharmony_ci SOC_ENUM("Ramp Rate", ramp_rate_enum), 1258c2ecf20Sopenharmony_ci SOC_SINGLE("Volume Ramp Switch", VOL_CTRL1, VC_RAMP_MODE, 1, 0), 1268c2ecf20Sopenharmony_ci SOC_SINGLE("Mute Ramp Switch", VOL_CTRL1, MUTE_MODE, 1, 0), 1278c2ecf20Sopenharmony_ci SOC_SINGLE("Unmute Ramp Switch", VOL_CTRL1, UNMUTE_MODE, 1, 0), 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new t9015_right_dac_mux = 1318c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Right DAC Source", dacr_in_enum); 1328c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new t9015_left_dac_mux = 1338c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Left DAC Source", dacl_in_enum); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget t9015_dapm_widgets[] = { 1368c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("Right IN", NULL, 0, SND_SOC_NOPM, 0, 0), 1378c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("Left IN", NULL, 0, SND_SOC_NOPM, 0, 0), 1388c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Right DAC Sel", SND_SOC_NOPM, 0, 0, 1398c2ecf20Sopenharmony_ci &t9015_right_dac_mux), 1408c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Left DAC Sel", SND_SOC_NOPM, 0, 0, 1418c2ecf20Sopenharmony_ci &t9015_left_dac_mux), 1428c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("Right DAC", NULL, BLOCK_EN, DACR_EN, 0), 1438c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("Left DAC", NULL, BLOCK_EN, DACL_EN, 0), 1448c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUT_DRV("Right- Driver", BLOCK_EN, LORN_EN, 0, 1458c2ecf20Sopenharmony_ci NULL, 0), 1468c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUT_DRV("Right+ Driver", BLOCK_EN, LORP_EN, 0, 1478c2ecf20Sopenharmony_ci NULL, 0), 1488c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUT_DRV("Left- Driver", BLOCK_EN, LOLN_EN, 0, 1498c2ecf20Sopenharmony_ci NULL, 0), 1508c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUT_DRV("Left+ Driver", BLOCK_EN, LOLP_EN, 0, 1518c2ecf20Sopenharmony_ci NULL, 0), 1528c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LORN"), 1538c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LORP"), 1548c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LOLN"), 1558c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LOLP"), 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route t9015_dapm_routes[] = { 1598c2ecf20Sopenharmony_ci { "Right IN", NULL, "Playback" }, 1608c2ecf20Sopenharmony_ci { "Left IN", NULL, "Playback" }, 1618c2ecf20Sopenharmony_ci { "Right DAC Sel", "Right", "Right IN" }, 1628c2ecf20Sopenharmony_ci { "Right DAC Sel", "Left", "Left IN" }, 1638c2ecf20Sopenharmony_ci { "Left DAC Sel", "Right", "Right IN" }, 1648c2ecf20Sopenharmony_ci { "Left DAC Sel", "Left", "Left IN" }, 1658c2ecf20Sopenharmony_ci { "Right DAC", NULL, "Right DAC Sel" }, 1668c2ecf20Sopenharmony_ci { "Left DAC", NULL, "Left DAC Sel" }, 1678c2ecf20Sopenharmony_ci { "Right- Driver", NULL, "Right DAC" }, 1688c2ecf20Sopenharmony_ci { "Right+ Driver", NULL, "Right DAC" }, 1698c2ecf20Sopenharmony_ci { "Left- Driver", NULL, "Left DAC" }, 1708c2ecf20Sopenharmony_ci { "Left+ Driver", NULL, "Left DAC" }, 1718c2ecf20Sopenharmony_ci { "LORN", NULL, "Right- Driver", }, 1728c2ecf20Sopenharmony_ci { "LORP", NULL, "Right+ Driver", }, 1738c2ecf20Sopenharmony_ci { "LOLN", NULL, "Left- Driver", }, 1748c2ecf20Sopenharmony_ci { "LOLP", NULL, "Left+ Driver", }, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int t9015_set_bias_level(struct snd_soc_component *component, 1788c2ecf20Sopenharmony_ci enum snd_soc_bias_level level) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct t9015 *priv = snd_soc_component_get_drvdata(component); 1818c2ecf20Sopenharmony_ci enum snd_soc_bias_level now = 1828c2ecf20Sopenharmony_ci snd_soc_component_get_bias_level(component); 1838c2ecf20Sopenharmony_ci int ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci switch (level) { 1868c2ecf20Sopenharmony_ci case SND_SOC_BIAS_ON: 1878c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, BLOCK_EN, 1888c2ecf20Sopenharmony_ci BIAS_CURRENT_EN, 1898c2ecf20Sopenharmony_ci BIAS_CURRENT_EN); 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 1928c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, BLOCK_EN, 1938c2ecf20Sopenharmony_ci BIAS_CURRENT_EN, 1948c2ecf20Sopenharmony_ci 0); 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 1978c2ecf20Sopenharmony_ci ret = regulator_enable(priv->avdd); 1988c2ecf20Sopenharmony_ci if (ret) { 1998c2ecf20Sopenharmony_ci dev_err(component->dev, "AVDD enable failed\n"); 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (now == SND_SOC_BIAS_OFF) { 2048c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, BLOCK_EN, 2058c2ecf20Sopenharmony_ci VMID_GEN_EN | VMID_GEN_FAST | REFP_BUF_EN, 2068c2ecf20Sopenharmony_ci VMID_GEN_EN | VMID_GEN_FAST | REFP_BUF_EN); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci mdelay(200); 2098c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, BLOCK_EN, 2108c2ecf20Sopenharmony_ci VMID_GEN_FAST, 2118c2ecf20Sopenharmony_ci 0); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci case SND_SOC_BIAS_OFF: 2168c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, BLOCK_EN, 2178c2ecf20Sopenharmony_ci VMID_GEN_EN | VMID_GEN_FAST | REFP_BUF_EN, 2188c2ecf20Sopenharmony_ci 0); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci regulator_disable(priv->avdd); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver t9015_codec_driver = { 2288c2ecf20Sopenharmony_ci .set_bias_level = t9015_set_bias_level, 2298c2ecf20Sopenharmony_ci .controls = t9015_snd_controls, 2308c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(t9015_snd_controls), 2318c2ecf20Sopenharmony_ci .dapm_widgets = t9015_dapm_widgets, 2328c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(t9015_dapm_widgets), 2338c2ecf20Sopenharmony_ci .dapm_routes = t9015_dapm_routes, 2348c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(t9015_dapm_routes), 2358c2ecf20Sopenharmony_ci .suspend_bias_off = 1, 2368c2ecf20Sopenharmony_ci .endianness = 1, 2378c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic const struct regmap_config t9015_regmap_config = { 2418c2ecf20Sopenharmony_ci .reg_bits = 32, 2428c2ecf20Sopenharmony_ci .reg_stride = 4, 2438c2ecf20Sopenharmony_ci .val_bits = 32, 2448c2ecf20Sopenharmony_ci .max_register = POWER_CFG, 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int t9015_probe(struct platform_device *pdev) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2508c2ecf20Sopenharmony_ci struct t9015 *priv; 2518c2ecf20Sopenharmony_ci void __iomem *regs; 2528c2ecf20Sopenharmony_ci struct regmap *regmap; 2538c2ecf20Sopenharmony_ci int ret; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 2568c2ecf20Sopenharmony_ci if (!priv) 2578c2ecf20Sopenharmony_ci return -ENOMEM; 2588c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci priv->pclk = devm_clk_get(dev, "pclk"); 2618c2ecf20Sopenharmony_ci if (IS_ERR(priv->pclk)) { 2628c2ecf20Sopenharmony_ci if (PTR_ERR(priv->pclk) != -EPROBE_DEFER) 2638c2ecf20Sopenharmony_ci dev_err(dev, "failed to get core clock\n"); 2648c2ecf20Sopenharmony_ci return PTR_ERR(priv->pclk); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci priv->avdd = devm_regulator_get(dev, "AVDD"); 2688c2ecf20Sopenharmony_ci if (IS_ERR(priv->avdd)) { 2698c2ecf20Sopenharmony_ci if (PTR_ERR(priv->avdd) != -EPROBE_DEFER) 2708c2ecf20Sopenharmony_ci dev_err(dev, "failed to AVDD\n"); 2718c2ecf20Sopenharmony_ci return PTR_ERR(priv->avdd); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->pclk); 2758c2ecf20Sopenharmony_ci if (ret) { 2768c2ecf20Sopenharmony_ci dev_err(dev, "core clock enable failed\n"); 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(dev, 2818c2ecf20Sopenharmony_ci (void(*)(void *))clk_disable_unprepare, 2828c2ecf20Sopenharmony_ci priv->pclk); 2838c2ecf20Sopenharmony_ci if (ret) 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci ret = device_reset(dev); 2878c2ecf20Sopenharmony_ci if (ret) { 2888c2ecf20Sopenharmony_ci dev_err(dev, "reset failed\n"); 2898c2ecf20Sopenharmony_ci return ret; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 2938c2ecf20Sopenharmony_ci if (IS_ERR(regs)) { 2948c2ecf20Sopenharmony_ci dev_err(dev, "register map failed\n"); 2958c2ecf20Sopenharmony_ci return PTR_ERR(regs); 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci regmap = devm_regmap_init_mmio(dev, regs, &t9015_regmap_config); 2998c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 3008c2ecf20Sopenharmony_ci dev_err(dev, "regmap init failed\n"); 3018c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* 3058c2ecf20Sopenharmony_ci * Initialize output polarity: 3068c2ecf20Sopenharmony_ci * ATM the output polarity is fixed but in the future it might useful 3078c2ecf20Sopenharmony_ci * to add DT property to set this depending on the platform needs 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci regmap_write(regmap, LINEOUT_CFG, 0x1111); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(dev, &t9015_codec_driver, 3128c2ecf20Sopenharmony_ci &t9015_dai, 1); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic const struct of_device_id t9015_ids[] = { 3168c2ecf20Sopenharmony_ci { .compatible = "amlogic,t9015", }, 3178c2ecf20Sopenharmony_ci { } 3188c2ecf20Sopenharmony_ci}; 3198c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, t9015_ids); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic struct platform_driver t9015_driver = { 3228c2ecf20Sopenharmony_ci .driver = { 3238c2ecf20Sopenharmony_ci .name = "t9015-codec", 3248c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(t9015_ids), 3258c2ecf20Sopenharmony_ci }, 3268c2ecf20Sopenharmony_ci .probe = t9015_probe, 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cimodule_platform_driver(t9015_driver); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC Amlogic T9015 codec driver"); 3328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 3338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 334