18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TAS5086 ASoC codec driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013 Daniel Mack <zonque@gmail.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * TODO: 88c2ecf20Sopenharmony_ci * - implement DAPM and input muxing 98c2ecf20Sopenharmony_ci * - implement modulation limit 108c2ecf20Sopenharmony_ci * - implement non-default PWM start 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Note that this chip has a very unusual register layout, specifically 138c2ecf20Sopenharmony_ci * because the registers are of unequal size, and multi-byte registers 148c2ecf20Sopenharmony_ci * require bulk writes to take effect. Regmap does not support that kind 158c2ecf20Sopenharmony_ci * of devices. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Currently, the driver does not touch any of the registers >= 0x20, so 188c2ecf20Sopenharmony_ci * it doesn't matter because the entire map can be accessed as 8-bit 198c2ecf20Sopenharmony_ci * array. In case more features will be added in the future 208c2ecf20Sopenharmony_ci * that require access to higher registers, the entire regmap H/W I/O 218c2ecf20Sopenharmony_ci * routines have to be open-coded. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/module.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <linux/delay.h> 278c2ecf20Sopenharmony_ci#include <linux/gpio.h> 288c2ecf20Sopenharmony_ci#include <linux/i2c.h> 298c2ecf20Sopenharmony_ci#include <linux/regmap.h> 308c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 318c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 328c2ecf20Sopenharmony_ci#include <linux/of.h> 338c2ecf20Sopenharmony_ci#include <linux/of_device.h> 348c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 358c2ecf20Sopenharmony_ci#include <sound/pcm.h> 368c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 378c2ecf20Sopenharmony_ci#include <sound/soc.h> 388c2ecf20Sopenharmony_ci#include <sound/tlv.h> 398c2ecf20Sopenharmony_ci#include <sound/tas5086.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define TAS5086_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 428c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | \ 438c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define TAS5086_PCM_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 468c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ 478c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ 488c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_192000) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * TAS5086 registers 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci#define TAS5086_CLOCK_CONTROL 0x00 /* Clock control register */ 548c2ecf20Sopenharmony_ci#define TAS5086_CLOCK_RATE(val) (val << 5) 558c2ecf20Sopenharmony_ci#define TAS5086_CLOCK_RATE_MASK (0x7 << 5) 568c2ecf20Sopenharmony_ci#define TAS5086_CLOCK_RATIO(val) (val << 2) 578c2ecf20Sopenharmony_ci#define TAS5086_CLOCK_RATIO_MASK (0x7 << 2) 588c2ecf20Sopenharmony_ci#define TAS5086_CLOCK_SCLK_RATIO_48 (1 << 1) 598c2ecf20Sopenharmony_ci#define TAS5086_CLOCK_VALID (1 << 0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define TAS5086_DEEMPH_MASK 0x03 628c2ecf20Sopenharmony_ci#define TAS5086_SOFT_MUTE_ALL 0x3f 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define TAS5086_DEV_ID 0x01 /* Device ID register */ 658c2ecf20Sopenharmony_ci#define TAS5086_ERROR_STATUS 0x02 /* Error status register */ 668c2ecf20Sopenharmony_ci#define TAS5086_SYS_CONTROL_1 0x03 /* System control register 1 */ 678c2ecf20Sopenharmony_ci#define TAS5086_SERIAL_DATA_IF 0x04 /* Serial data interface register */ 688c2ecf20Sopenharmony_ci#define TAS5086_SYS_CONTROL_2 0x05 /* System control register 2 */ 698c2ecf20Sopenharmony_ci#define TAS5086_SOFT_MUTE 0x06 /* Soft mute register */ 708c2ecf20Sopenharmony_ci#define TAS5086_MASTER_VOL 0x07 /* Master volume */ 718c2ecf20Sopenharmony_ci#define TAS5086_CHANNEL_VOL(X) (0x08 + (X)) /* Channel 1-6 volume */ 728c2ecf20Sopenharmony_ci#define TAS5086_VOLUME_CONTROL 0x09 /* Volume control register */ 738c2ecf20Sopenharmony_ci#define TAS5086_MOD_LIMIT 0x10 /* Modulation limit register */ 748c2ecf20Sopenharmony_ci#define TAS5086_PWM_START 0x18 /* PWM start register */ 758c2ecf20Sopenharmony_ci#define TAS5086_SURROUND 0x19 /* Surround register */ 768c2ecf20Sopenharmony_ci#define TAS5086_SPLIT_CAP_CHARGE 0x1a /* Split cap charge period register */ 778c2ecf20Sopenharmony_ci#define TAS5086_OSC_TRIM 0x1b /* Oscillator trim register */ 788c2ecf20Sopenharmony_ci#define TAS5086_BKNDERR 0x1c 798c2ecf20Sopenharmony_ci#define TAS5086_INPUT_MUX 0x20 808c2ecf20Sopenharmony_ci#define TAS5086_PWM_OUTPUT_MUX 0x25 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define TAS5086_MAX_REGISTER TAS5086_PWM_OUTPUT_MUX 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define TAS5086_PWM_START_MIDZ_FOR_START_1 (1 << 7) 858c2ecf20Sopenharmony_ci#define TAS5086_PWM_START_MIDZ_FOR_START_2 (1 << 6) 868c2ecf20Sopenharmony_ci#define TAS5086_PWM_START_CHANNEL_MASK (0x3f) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * Default TAS5086 power-up configuration 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_cistatic const struct reg_default tas5086_reg_defaults[] = { 928c2ecf20Sopenharmony_ci { 0x00, 0x6c }, 938c2ecf20Sopenharmony_ci { 0x01, 0x03 }, 948c2ecf20Sopenharmony_ci { 0x02, 0x00 }, 958c2ecf20Sopenharmony_ci { 0x03, 0xa0 }, 968c2ecf20Sopenharmony_ci { 0x04, 0x05 }, 978c2ecf20Sopenharmony_ci { 0x05, 0x60 }, 988c2ecf20Sopenharmony_ci { 0x06, 0x00 }, 998c2ecf20Sopenharmony_ci { 0x07, 0xff }, 1008c2ecf20Sopenharmony_ci { 0x08, 0x30 }, 1018c2ecf20Sopenharmony_ci { 0x09, 0x30 }, 1028c2ecf20Sopenharmony_ci { 0x0a, 0x30 }, 1038c2ecf20Sopenharmony_ci { 0x0b, 0x30 }, 1048c2ecf20Sopenharmony_ci { 0x0c, 0x30 }, 1058c2ecf20Sopenharmony_ci { 0x0d, 0x30 }, 1068c2ecf20Sopenharmony_ci { 0x0e, 0xb1 }, 1078c2ecf20Sopenharmony_ci { 0x0f, 0x00 }, 1088c2ecf20Sopenharmony_ci { 0x10, 0x02 }, 1098c2ecf20Sopenharmony_ci { 0x11, 0x00 }, 1108c2ecf20Sopenharmony_ci { 0x12, 0x00 }, 1118c2ecf20Sopenharmony_ci { 0x13, 0x00 }, 1128c2ecf20Sopenharmony_ci { 0x14, 0x00 }, 1138c2ecf20Sopenharmony_ci { 0x15, 0x00 }, 1148c2ecf20Sopenharmony_ci { 0x16, 0x00 }, 1158c2ecf20Sopenharmony_ci { 0x17, 0x00 }, 1168c2ecf20Sopenharmony_ci { 0x18, 0x3f }, 1178c2ecf20Sopenharmony_ci { 0x19, 0x00 }, 1188c2ecf20Sopenharmony_ci { 0x1a, 0x18 }, 1198c2ecf20Sopenharmony_ci { 0x1b, 0x82 }, 1208c2ecf20Sopenharmony_ci { 0x1c, 0x05 }, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int tas5086_register_size(struct device *dev, unsigned int reg) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci switch (reg) { 1268c2ecf20Sopenharmony_ci case TAS5086_CLOCK_CONTROL ... TAS5086_BKNDERR: 1278c2ecf20Sopenharmony_ci return 1; 1288c2ecf20Sopenharmony_ci case TAS5086_INPUT_MUX: 1298c2ecf20Sopenharmony_ci case TAS5086_PWM_OUTPUT_MUX: 1308c2ecf20Sopenharmony_ci return 4; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported register address: %d\n", reg); 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic bool tas5086_accessible_reg(struct device *dev, unsigned int reg) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci switch (reg) { 1408c2ecf20Sopenharmony_ci case 0x0f: 1418c2ecf20Sopenharmony_ci case 0x11 ... 0x17: 1428c2ecf20Sopenharmony_ci case 0x1d ... 0x1f: 1438c2ecf20Sopenharmony_ci return false; 1448c2ecf20Sopenharmony_ci default: 1458c2ecf20Sopenharmony_ci return true; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic bool tas5086_volatile_reg(struct device *dev, unsigned int reg) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci switch (reg) { 1528c2ecf20Sopenharmony_ci case TAS5086_DEV_ID: 1538c2ecf20Sopenharmony_ci case TAS5086_ERROR_STATUS: 1548c2ecf20Sopenharmony_ci return true; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return false; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic bool tas5086_writeable_reg(struct device *dev, unsigned int reg) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int tas5086_reg_write(void *context, unsigned int reg, 1668c2ecf20Sopenharmony_ci unsigned int value) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct i2c_client *client = context; 1698c2ecf20Sopenharmony_ci unsigned int i, size; 1708c2ecf20Sopenharmony_ci uint8_t buf[5]; 1718c2ecf20Sopenharmony_ci int ret; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci size = tas5086_register_size(&client->dev, reg); 1748c2ecf20Sopenharmony_ci if (size == 0) 1758c2ecf20Sopenharmony_ci return -EINVAL; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci buf[0] = reg; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci for (i = size; i >= 1; --i) { 1808c2ecf20Sopenharmony_ci buf[i] = value; 1818c2ecf20Sopenharmony_ci value >>= 8; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ret = i2c_master_send(client, buf, size + 1); 1858c2ecf20Sopenharmony_ci if (ret == size + 1) 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci else if (ret < 0) 1888c2ecf20Sopenharmony_ci return ret; 1898c2ecf20Sopenharmony_ci else 1908c2ecf20Sopenharmony_ci return -EIO; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int tas5086_reg_read(void *context, unsigned int reg, 1948c2ecf20Sopenharmony_ci unsigned int *value) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct i2c_client *client = context; 1978c2ecf20Sopenharmony_ci uint8_t send_buf, recv_buf[4]; 1988c2ecf20Sopenharmony_ci struct i2c_msg msgs[2]; 1998c2ecf20Sopenharmony_ci unsigned int size; 2008c2ecf20Sopenharmony_ci unsigned int i; 2018c2ecf20Sopenharmony_ci int ret; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci size = tas5086_register_size(&client->dev, reg); 2048c2ecf20Sopenharmony_ci if (size == 0) 2058c2ecf20Sopenharmony_ci return -EINVAL; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci send_buf = reg; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci msgs[0].addr = client->addr; 2108c2ecf20Sopenharmony_ci msgs[0].len = sizeof(send_buf); 2118c2ecf20Sopenharmony_ci msgs[0].buf = &send_buf; 2128c2ecf20Sopenharmony_ci msgs[0].flags = 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci msgs[1].addr = client->addr; 2158c2ecf20Sopenharmony_ci msgs[1].len = size; 2168c2ecf20Sopenharmony_ci msgs[1].buf = recv_buf; 2178c2ecf20Sopenharmony_ci msgs[1].flags = I2C_M_RD; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 2208c2ecf20Sopenharmony_ci if (ret < 0) 2218c2ecf20Sopenharmony_ci return ret; 2228c2ecf20Sopenharmony_ci else if (ret != ARRAY_SIZE(msgs)) 2238c2ecf20Sopenharmony_ci return -EIO; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci *value = 0; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 2288c2ecf20Sopenharmony_ci *value <<= 8; 2298c2ecf20Sopenharmony_ci *value |= recv_buf[i]; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic const char * const supply_names[] = { 2368c2ecf20Sopenharmony_ci "dvdd", "avdd" 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistruct tas5086_private { 2408c2ecf20Sopenharmony_ci struct regmap *regmap; 2418c2ecf20Sopenharmony_ci unsigned int mclk, sclk; 2428c2ecf20Sopenharmony_ci unsigned int format; 2438c2ecf20Sopenharmony_ci bool deemph; 2448c2ecf20Sopenharmony_ci unsigned int charge_period; 2458c2ecf20Sopenharmony_ci unsigned int pwm_start_mid_z; 2468c2ecf20Sopenharmony_ci /* Current sample rate for de-emphasis control */ 2478c2ecf20Sopenharmony_ci int rate; 2488c2ecf20Sopenharmony_ci /* GPIO driving Reset pin, if any */ 2498c2ecf20Sopenharmony_ci int gpio_nreset; 2508c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic int tas5086_deemph[] = { 0, 32000, 44100, 48000 }; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int tas5086_set_deemph(struct snd_soc_component *component) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 2588c2ecf20Sopenharmony_ci int i, val = 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (priv->deemph) { 2618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) { 2628c2ecf20Sopenharmony_ci if (tas5086_deemph[i] == priv->rate) { 2638c2ecf20Sopenharmony_ci val = i; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1, 2708c2ecf20Sopenharmony_ci TAS5086_DEEMPH_MASK, val); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int tas5086_get_deemph(struct snd_kcontrol *kcontrol, 2748c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2778c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = priv->deemph; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int tas5086_put_deemph(struct snd_kcontrol *kcontrol, 2858c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2888c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci priv->deemph = ucontrol->value.integer.value[0]; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return tas5086_set_deemph(component); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai, 2978c2ecf20Sopenharmony_ci int clk_id, unsigned int freq, int dir) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 3008c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci switch (clk_id) { 3038c2ecf20Sopenharmony_ci case TAS5086_CLK_IDX_MCLK: 3048c2ecf20Sopenharmony_ci priv->mclk = freq; 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci case TAS5086_CLK_IDX_SCLK: 3078c2ecf20Sopenharmony_ci priv->sclk = freq; 3088c2ecf20Sopenharmony_ci break; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai, 3158c2ecf20Sopenharmony_ci unsigned int format) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 3188c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* The TAS5086 can only be slave to all clocks */ 3218c2ecf20Sopenharmony_ci if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { 3228c2ecf20Sopenharmony_ci dev_err(component->dev, "Invalid clocking mode\n"); 3238c2ecf20Sopenharmony_ci return -EINVAL; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* we need to refer to the data format from hw_params() */ 3278c2ecf20Sopenharmony_ci priv->format = format; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic const int tas5086_sample_rates[] = { 3338c2ecf20Sopenharmony_ci 32000, 38000, 44100, 48000, 88200, 96000, 176400, 192000 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic const int tas5086_ratios[] = { 3378c2ecf20Sopenharmony_ci 64, 128, 192, 256, 384, 512 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int index_in_array(const int *array, int len, int needle) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci int i; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 3458c2ecf20Sopenharmony_ci if (array[i] == needle) 3468c2ecf20Sopenharmony_ci return i; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return -ENOENT; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic int tas5086_hw_params(struct snd_pcm_substream *substream, 3528c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 3538c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3568c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 3578c2ecf20Sopenharmony_ci int val; 3588c2ecf20Sopenharmony_ci int ret; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci priv->rate = params_rate(params); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Look up the sample rate and refer to the offset in the list */ 3638c2ecf20Sopenharmony_ci val = index_in_array(tas5086_sample_rates, 3648c2ecf20Sopenharmony_ci ARRAY_SIZE(tas5086_sample_rates), priv->rate); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (val < 0) { 3678c2ecf20Sopenharmony_ci dev_err(component->dev, "Invalid sample rate\n"); 3688c2ecf20Sopenharmony_ci return -EINVAL; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, 3728c2ecf20Sopenharmony_ci TAS5086_CLOCK_RATE_MASK, 3738c2ecf20Sopenharmony_ci TAS5086_CLOCK_RATE(val)); 3748c2ecf20Sopenharmony_ci if (ret < 0) 3758c2ecf20Sopenharmony_ci return ret; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* MCLK / Fs ratio */ 3788c2ecf20Sopenharmony_ci val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios), 3798c2ecf20Sopenharmony_ci priv->mclk / priv->rate); 3808c2ecf20Sopenharmony_ci if (val < 0) { 3818c2ecf20Sopenharmony_ci dev_err(component->dev, "Invalid MCLK / Fs ratio\n"); 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, 3868c2ecf20Sopenharmony_ci TAS5086_CLOCK_RATIO_MASK, 3878c2ecf20Sopenharmony_ci TAS5086_CLOCK_RATIO(val)); 3888c2ecf20Sopenharmony_ci if (ret < 0) 3898c2ecf20Sopenharmony_ci return ret; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, 3938c2ecf20Sopenharmony_ci TAS5086_CLOCK_SCLK_RATIO_48, 3948c2ecf20Sopenharmony_ci (priv->sclk == 48 * priv->rate) ? 3958c2ecf20Sopenharmony_ci TAS5086_CLOCK_SCLK_RATIO_48 : 0); 3968c2ecf20Sopenharmony_ci if (ret < 0) 3978c2ecf20Sopenharmony_ci return ret; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* 4008c2ecf20Sopenharmony_ci * The chip has a very unituitive register mapping and muxes information 4018c2ecf20Sopenharmony_ci * about data format and sample depth into the same register, but not on 4028c2ecf20Sopenharmony_ci * a logical bit-boundary. Hence, we have to refer to the format passed 4038c2ecf20Sopenharmony_ci * in the set_dai_fmt() callback and set up everything from here. 4048c2ecf20Sopenharmony_ci * 4058c2ecf20Sopenharmony_ci * First, determine the 'base' value, using the format ... 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_ci switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { 4088c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 4098c2ecf20Sopenharmony_ci val = 0x00; 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 4128c2ecf20Sopenharmony_ci val = 0x03; 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 4158c2ecf20Sopenharmony_ci val = 0x06; 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci default: 4188c2ecf20Sopenharmony_ci dev_err(component->dev, "Invalid DAI format\n"); 4198c2ecf20Sopenharmony_ci return -EINVAL; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* ... then add the offset for the sample bit depth. */ 4238c2ecf20Sopenharmony_ci switch (params_width(params)) { 4248c2ecf20Sopenharmony_ci case 16: 4258c2ecf20Sopenharmony_ci val += 0; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case 20: 4288c2ecf20Sopenharmony_ci val += 1; 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci case 24: 4318c2ecf20Sopenharmony_ci val += 2; 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci default: 4348c2ecf20Sopenharmony_ci dev_err(component->dev, "Invalid bit width\n"); 4358c2ecf20Sopenharmony_ci return -EINVAL; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val); 4398c2ecf20Sopenharmony_ci if (ret < 0) 4408c2ecf20Sopenharmony_ci return ret; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* clock is considered valid now */ 4438c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, 4448c2ecf20Sopenharmony_ci TAS5086_CLOCK_VALID, TAS5086_CLOCK_VALID); 4458c2ecf20Sopenharmony_ci if (ret < 0) 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return tas5086_set_deemph(component); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 4548c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 4558c2ecf20Sopenharmony_ci unsigned int val = 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (mute) 4588c2ecf20Sopenharmony_ci val = TAS5086_SOFT_MUTE_ALL; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic void tas5086_reset(struct tas5086_private *priv) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci if (gpio_is_valid(priv->gpio_nreset)) { 4668c2ecf20Sopenharmony_ci /* Reset codec - minimum assertion time is 400ns */ 4678c2ecf20Sopenharmony_ci gpio_direction_output(priv->gpio_nreset, 0); 4688c2ecf20Sopenharmony_ci udelay(1); 4698c2ecf20Sopenharmony_ci gpio_set_value(priv->gpio_nreset, 1); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Codec needs ~15ms to wake up */ 4728c2ecf20Sopenharmony_ci msleep(15); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/* charge period values in microseconds */ 4778c2ecf20Sopenharmony_cistatic const int tas5086_charge_period[] = { 4788c2ecf20Sopenharmony_ci 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200, 4798c2ecf20Sopenharmony_ci 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000, 4808c2ecf20Sopenharmony_ci 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int tas5086_init(struct device *dev, struct tas5086_private *priv) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci int ret, i; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * If any of the channels is configured to start in Mid-Z mode, 4898c2ecf20Sopenharmony_ci * configure 'part 1' of the PWM starts to use Mid-Z, and tell 4908c2ecf20Sopenharmony_ci * all configured mid-z channels to start under 'part 1'. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ci if (priv->pwm_start_mid_z) 4938c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TAS5086_PWM_START, 4948c2ecf20Sopenharmony_ci TAS5086_PWM_START_MIDZ_FOR_START_1 | 4958c2ecf20Sopenharmony_ci priv->pwm_start_mid_z); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* lookup and set split-capacitor charge period */ 4988c2ecf20Sopenharmony_ci if (priv->charge_period == 0) { 4998c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); 5008c2ecf20Sopenharmony_ci } else { 5018c2ecf20Sopenharmony_ci i = index_in_array(tas5086_charge_period, 5028c2ecf20Sopenharmony_ci ARRAY_SIZE(tas5086_charge_period), 5038c2ecf20Sopenharmony_ci priv->charge_period); 5048c2ecf20Sopenharmony_ci if (i >= 0) 5058c2ecf20Sopenharmony_ci regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 5068c2ecf20Sopenharmony_ci i + 0x08); 5078c2ecf20Sopenharmony_ci else 5088c2ecf20Sopenharmony_ci dev_warn(dev, 5098c2ecf20Sopenharmony_ci "Invalid split-cap charge period of %d ns.\n", 5108c2ecf20Sopenharmony_ci priv->charge_period); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* enable factory trim */ 5148c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); 5158c2ecf20Sopenharmony_ci if (ret < 0) 5168c2ecf20Sopenharmony_ci return ret; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* start all channels */ 5198c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); 5208c2ecf20Sopenharmony_ci if (ret < 0) 5218c2ecf20Sopenharmony_ci return ret; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* mute all channels for now */ 5248c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, 5258c2ecf20Sopenharmony_ci TAS5086_SOFT_MUTE_ALL); 5268c2ecf20Sopenharmony_ci if (ret < 0) 5278c2ecf20Sopenharmony_ci return ret; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* TAS5086 controls */ 5338c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas5086_controls[] = { 5368c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL, 5378c2ecf20Sopenharmony_ci 0, 0xff, 1, tas5086_dac_tlv), 5388c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume", 5398c2ecf20Sopenharmony_ci TAS5086_CHANNEL_VOL(0), TAS5086_CHANNEL_VOL(1), 5408c2ecf20Sopenharmony_ci 0, 0xff, 1, tas5086_dac_tlv), 5418c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume", 5428c2ecf20Sopenharmony_ci TAS5086_CHANNEL_VOL(2), TAS5086_CHANNEL_VOL(3), 5438c2ecf20Sopenharmony_ci 0, 0xff, 1, tas5086_dac_tlv), 5448c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume", 5458c2ecf20Sopenharmony_ci TAS5086_CHANNEL_VOL(4), TAS5086_CHANNEL_VOL(5), 5468c2ecf20Sopenharmony_ci 0, 0xff, 1, tas5086_dac_tlv), 5478c2ecf20Sopenharmony_ci SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0, 5488c2ecf20Sopenharmony_ci tas5086_get_deemph, tas5086_put_deemph), 5498c2ecf20Sopenharmony_ci}; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/* Input mux controls */ 5528c2ecf20Sopenharmony_cistatic const char *tas5086_dapm_sdin_texts[] = 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci "SDIN1-L", "SDIN1-R", "SDIN2-L", "SDIN2-R", 5558c2ecf20Sopenharmony_ci "SDIN3-L", "SDIN3-R", "Ground (0)", "nc" 5568c2ecf20Sopenharmony_ci}; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic const struct soc_enum tas5086_dapm_input_mux_enum[] = { 5598c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 20, 8, tas5086_dapm_sdin_texts), 5608c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 16, 8, tas5086_dapm_sdin_texts), 5618c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 12, 8, tas5086_dapm_sdin_texts), 5628c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 8, 8, tas5086_dapm_sdin_texts), 5638c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 4, 8, tas5086_dapm_sdin_texts), 5648c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 0, 8, tas5086_dapm_sdin_texts), 5658c2ecf20Sopenharmony_ci}; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas5086_dapm_input_mux_controls[] = { 5688c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Channel 1 input", tas5086_dapm_input_mux_enum[0]), 5698c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Channel 2 input", tas5086_dapm_input_mux_enum[1]), 5708c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Channel 3 input", tas5086_dapm_input_mux_enum[2]), 5718c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Channel 4 input", tas5086_dapm_input_mux_enum[3]), 5728c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Channel 5 input", tas5086_dapm_input_mux_enum[4]), 5738c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("Channel 6 input", tas5086_dapm_input_mux_enum[5]), 5748c2ecf20Sopenharmony_ci}; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci/* Output mux controls */ 5778c2ecf20Sopenharmony_cistatic const char *tas5086_dapm_channel_texts[] = 5788c2ecf20Sopenharmony_ci { "Channel 1 Mux", "Channel 2 Mux", "Channel 3 Mux", 5798c2ecf20Sopenharmony_ci "Channel 4 Mux", "Channel 5 Mux", "Channel 6 Mux" }; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic const struct soc_enum tas5086_dapm_output_mux_enum[] = { 5828c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 20, 6, tas5086_dapm_channel_texts), 5838c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 16, 6, tas5086_dapm_channel_texts), 5848c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 12, 6, tas5086_dapm_channel_texts), 5858c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 8, 6, tas5086_dapm_channel_texts), 5868c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 4, 6, tas5086_dapm_channel_texts), 5878c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 0, 6, tas5086_dapm_channel_texts), 5888c2ecf20Sopenharmony_ci}; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas5086_dapm_output_mux_controls[] = { 5918c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("PWM1 Output", tas5086_dapm_output_mux_enum[0]), 5928c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("PWM2 Output", tas5086_dapm_output_mux_enum[1]), 5938c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("PWM3 Output", tas5086_dapm_output_mux_enum[2]), 5948c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("PWM4 Output", tas5086_dapm_output_mux_enum[3]), 5958c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("PWM5 Output", tas5086_dapm_output_mux_enum[4]), 5968c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("PWM6 Output", tas5086_dapm_output_mux_enum[5]), 5978c2ecf20Sopenharmony_ci}; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget tas5086_dapm_widgets[] = { 6008c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("SDIN1-L"), 6018c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("SDIN1-R"), 6028c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("SDIN2-L"), 6038c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("SDIN2-R"), 6048c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("SDIN3-L"), 6058c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("SDIN3-R"), 6068c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("SDIN4-L"), 6078c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("SDIN4-R"), 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("PWM1"), 6108c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("PWM2"), 6118c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("PWM3"), 6128c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("PWM4"), 6138c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("PWM5"), 6148c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("PWM6"), 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Channel 1 Mux", SND_SOC_NOPM, 0, 0, 6178c2ecf20Sopenharmony_ci &tas5086_dapm_input_mux_controls[0]), 6188c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Channel 2 Mux", SND_SOC_NOPM, 0, 0, 6198c2ecf20Sopenharmony_ci &tas5086_dapm_input_mux_controls[1]), 6208c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Channel 3 Mux", SND_SOC_NOPM, 0, 0, 6218c2ecf20Sopenharmony_ci &tas5086_dapm_input_mux_controls[2]), 6228c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Channel 4 Mux", SND_SOC_NOPM, 0, 0, 6238c2ecf20Sopenharmony_ci &tas5086_dapm_input_mux_controls[3]), 6248c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Channel 5 Mux", SND_SOC_NOPM, 0, 0, 6258c2ecf20Sopenharmony_ci &tas5086_dapm_input_mux_controls[4]), 6268c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Channel 6 Mux", SND_SOC_NOPM, 0, 0, 6278c2ecf20Sopenharmony_ci &tas5086_dapm_input_mux_controls[5]), 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("PWM1 Mux", SND_SOC_NOPM, 0, 0, 6308c2ecf20Sopenharmony_ci &tas5086_dapm_output_mux_controls[0]), 6318c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("PWM2 Mux", SND_SOC_NOPM, 0, 0, 6328c2ecf20Sopenharmony_ci &tas5086_dapm_output_mux_controls[1]), 6338c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("PWM3 Mux", SND_SOC_NOPM, 0, 0, 6348c2ecf20Sopenharmony_ci &tas5086_dapm_output_mux_controls[2]), 6358c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("PWM4 Mux", SND_SOC_NOPM, 0, 0, 6368c2ecf20Sopenharmony_ci &tas5086_dapm_output_mux_controls[3]), 6378c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("PWM5 Mux", SND_SOC_NOPM, 0, 0, 6388c2ecf20Sopenharmony_ci &tas5086_dapm_output_mux_controls[4]), 6398c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("PWM6 Mux", SND_SOC_NOPM, 0, 0, 6408c2ecf20Sopenharmony_ci &tas5086_dapm_output_mux_controls[5]), 6418c2ecf20Sopenharmony_ci}; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route tas5086_dapm_routes[] = { 6448c2ecf20Sopenharmony_ci /* SDIN inputs -> channel muxes */ 6458c2ecf20Sopenharmony_ci { "Channel 1 Mux", "SDIN1-L", "SDIN1-L" }, 6468c2ecf20Sopenharmony_ci { "Channel 1 Mux", "SDIN1-R", "SDIN1-R" }, 6478c2ecf20Sopenharmony_ci { "Channel 1 Mux", "SDIN2-L", "SDIN2-L" }, 6488c2ecf20Sopenharmony_ci { "Channel 1 Mux", "SDIN2-R", "SDIN2-R" }, 6498c2ecf20Sopenharmony_ci { "Channel 1 Mux", "SDIN3-L", "SDIN3-L" }, 6508c2ecf20Sopenharmony_ci { "Channel 1 Mux", "SDIN3-R", "SDIN3-R" }, 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" }, 6538c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" }, 6548c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" }, 6558c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" }, 6568c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" }, 6578c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" }, 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" }, 6608c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" }, 6618c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" }, 6628c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" }, 6638c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" }, 6648c2ecf20Sopenharmony_ci { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" }, 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci { "Channel 3 Mux", "SDIN1-L", "SDIN1-L" }, 6678c2ecf20Sopenharmony_ci { "Channel 3 Mux", "SDIN1-R", "SDIN1-R" }, 6688c2ecf20Sopenharmony_ci { "Channel 3 Mux", "SDIN2-L", "SDIN2-L" }, 6698c2ecf20Sopenharmony_ci { "Channel 3 Mux", "SDIN2-R", "SDIN2-R" }, 6708c2ecf20Sopenharmony_ci { "Channel 3 Mux", "SDIN3-L", "SDIN3-L" }, 6718c2ecf20Sopenharmony_ci { "Channel 3 Mux", "SDIN3-R", "SDIN3-R" }, 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci { "Channel 4 Mux", "SDIN1-L", "SDIN1-L" }, 6748c2ecf20Sopenharmony_ci { "Channel 4 Mux", "SDIN1-R", "SDIN1-R" }, 6758c2ecf20Sopenharmony_ci { "Channel 4 Mux", "SDIN2-L", "SDIN2-L" }, 6768c2ecf20Sopenharmony_ci { "Channel 4 Mux", "SDIN2-R", "SDIN2-R" }, 6778c2ecf20Sopenharmony_ci { "Channel 4 Mux", "SDIN3-L", "SDIN3-L" }, 6788c2ecf20Sopenharmony_ci { "Channel 4 Mux", "SDIN3-R", "SDIN3-R" }, 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci { "Channel 5 Mux", "SDIN1-L", "SDIN1-L" }, 6818c2ecf20Sopenharmony_ci { "Channel 5 Mux", "SDIN1-R", "SDIN1-R" }, 6828c2ecf20Sopenharmony_ci { "Channel 5 Mux", "SDIN2-L", "SDIN2-L" }, 6838c2ecf20Sopenharmony_ci { "Channel 5 Mux", "SDIN2-R", "SDIN2-R" }, 6848c2ecf20Sopenharmony_ci { "Channel 5 Mux", "SDIN3-L", "SDIN3-L" }, 6858c2ecf20Sopenharmony_ci { "Channel 5 Mux", "SDIN3-R", "SDIN3-R" }, 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci { "Channel 6 Mux", "SDIN1-L", "SDIN1-L" }, 6888c2ecf20Sopenharmony_ci { "Channel 6 Mux", "SDIN1-R", "SDIN1-R" }, 6898c2ecf20Sopenharmony_ci { "Channel 6 Mux", "SDIN2-L", "SDIN2-L" }, 6908c2ecf20Sopenharmony_ci { "Channel 6 Mux", "SDIN2-R", "SDIN2-R" }, 6918c2ecf20Sopenharmony_ci { "Channel 6 Mux", "SDIN3-L", "SDIN3-L" }, 6928c2ecf20Sopenharmony_ci { "Channel 6 Mux", "SDIN3-R", "SDIN3-R" }, 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* Channel muxes -> PWM muxes */ 6958c2ecf20Sopenharmony_ci { "PWM1 Mux", "Channel 1 Mux", "Channel 1 Mux" }, 6968c2ecf20Sopenharmony_ci { "PWM2 Mux", "Channel 1 Mux", "Channel 1 Mux" }, 6978c2ecf20Sopenharmony_ci { "PWM3 Mux", "Channel 1 Mux", "Channel 1 Mux" }, 6988c2ecf20Sopenharmony_ci { "PWM4 Mux", "Channel 1 Mux", "Channel 1 Mux" }, 6998c2ecf20Sopenharmony_ci { "PWM5 Mux", "Channel 1 Mux", "Channel 1 Mux" }, 7008c2ecf20Sopenharmony_ci { "PWM6 Mux", "Channel 1 Mux", "Channel 1 Mux" }, 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci { "PWM1 Mux", "Channel 2 Mux", "Channel 2 Mux" }, 7038c2ecf20Sopenharmony_ci { "PWM2 Mux", "Channel 2 Mux", "Channel 2 Mux" }, 7048c2ecf20Sopenharmony_ci { "PWM3 Mux", "Channel 2 Mux", "Channel 2 Mux" }, 7058c2ecf20Sopenharmony_ci { "PWM4 Mux", "Channel 2 Mux", "Channel 2 Mux" }, 7068c2ecf20Sopenharmony_ci { "PWM5 Mux", "Channel 2 Mux", "Channel 2 Mux" }, 7078c2ecf20Sopenharmony_ci { "PWM6 Mux", "Channel 2 Mux", "Channel 2 Mux" }, 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci { "PWM1 Mux", "Channel 3 Mux", "Channel 3 Mux" }, 7108c2ecf20Sopenharmony_ci { "PWM2 Mux", "Channel 3 Mux", "Channel 3 Mux" }, 7118c2ecf20Sopenharmony_ci { "PWM3 Mux", "Channel 3 Mux", "Channel 3 Mux" }, 7128c2ecf20Sopenharmony_ci { "PWM4 Mux", "Channel 3 Mux", "Channel 3 Mux" }, 7138c2ecf20Sopenharmony_ci { "PWM5 Mux", "Channel 3 Mux", "Channel 3 Mux" }, 7148c2ecf20Sopenharmony_ci { "PWM6 Mux", "Channel 3 Mux", "Channel 3 Mux" }, 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci { "PWM1 Mux", "Channel 4 Mux", "Channel 4 Mux" }, 7178c2ecf20Sopenharmony_ci { "PWM2 Mux", "Channel 4 Mux", "Channel 4 Mux" }, 7188c2ecf20Sopenharmony_ci { "PWM3 Mux", "Channel 4 Mux", "Channel 4 Mux" }, 7198c2ecf20Sopenharmony_ci { "PWM4 Mux", "Channel 4 Mux", "Channel 4 Mux" }, 7208c2ecf20Sopenharmony_ci { "PWM5 Mux", "Channel 4 Mux", "Channel 4 Mux" }, 7218c2ecf20Sopenharmony_ci { "PWM6 Mux", "Channel 4 Mux", "Channel 4 Mux" }, 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci { "PWM1 Mux", "Channel 5 Mux", "Channel 5 Mux" }, 7248c2ecf20Sopenharmony_ci { "PWM2 Mux", "Channel 5 Mux", "Channel 5 Mux" }, 7258c2ecf20Sopenharmony_ci { "PWM3 Mux", "Channel 5 Mux", "Channel 5 Mux" }, 7268c2ecf20Sopenharmony_ci { "PWM4 Mux", "Channel 5 Mux", "Channel 5 Mux" }, 7278c2ecf20Sopenharmony_ci { "PWM5 Mux", "Channel 5 Mux", "Channel 5 Mux" }, 7288c2ecf20Sopenharmony_ci { "PWM6 Mux", "Channel 5 Mux", "Channel 5 Mux" }, 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci { "PWM1 Mux", "Channel 6 Mux", "Channel 6 Mux" }, 7318c2ecf20Sopenharmony_ci { "PWM2 Mux", "Channel 6 Mux", "Channel 6 Mux" }, 7328c2ecf20Sopenharmony_ci { "PWM3 Mux", "Channel 6 Mux", "Channel 6 Mux" }, 7338c2ecf20Sopenharmony_ci { "PWM4 Mux", "Channel 6 Mux", "Channel 6 Mux" }, 7348c2ecf20Sopenharmony_ci { "PWM5 Mux", "Channel 6 Mux", "Channel 6 Mux" }, 7358c2ecf20Sopenharmony_ci { "PWM6 Mux", "Channel 6 Mux", "Channel 6 Mux" }, 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* The PWM muxes are directly connected to the PWM outputs */ 7388c2ecf20Sopenharmony_ci { "PWM1", NULL, "PWM1 Mux" }, 7398c2ecf20Sopenharmony_ci { "PWM2", NULL, "PWM2 Mux" }, 7408c2ecf20Sopenharmony_ci { "PWM3", NULL, "PWM3 Mux" }, 7418c2ecf20Sopenharmony_ci { "PWM4", NULL, "PWM4 Mux" }, 7428c2ecf20Sopenharmony_ci { "PWM5", NULL, "PWM5 Mux" }, 7438c2ecf20Sopenharmony_ci { "PWM6", NULL, "PWM6 Mux" }, 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci}; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops tas5086_dai_ops = { 7488c2ecf20Sopenharmony_ci .hw_params = tas5086_hw_params, 7498c2ecf20Sopenharmony_ci .set_sysclk = tas5086_set_dai_sysclk, 7508c2ecf20Sopenharmony_ci .set_fmt = tas5086_set_dai_fmt, 7518c2ecf20Sopenharmony_ci .mute_stream = tas5086_mute_stream, 7528c2ecf20Sopenharmony_ci}; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver tas5086_dai = { 7558c2ecf20Sopenharmony_ci .name = "tas5086-hifi", 7568c2ecf20Sopenharmony_ci .playback = { 7578c2ecf20Sopenharmony_ci .stream_name = "Playback", 7588c2ecf20Sopenharmony_ci .channels_min = 2, 7598c2ecf20Sopenharmony_ci .channels_max = 6, 7608c2ecf20Sopenharmony_ci .rates = TAS5086_PCM_RATES, 7618c2ecf20Sopenharmony_ci .formats = TAS5086_PCM_FORMATS, 7628c2ecf20Sopenharmony_ci }, 7638c2ecf20Sopenharmony_ci .ops = &tas5086_dai_ops, 7648c2ecf20Sopenharmony_ci}; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 7678c2ecf20Sopenharmony_cistatic int tas5086_soc_suspend(struct snd_soc_component *component) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 7708c2ecf20Sopenharmony_ci int ret; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* Shut down all channels */ 7738c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60); 7748c2ecf20Sopenharmony_ci if (ret < 0) 7758c2ecf20Sopenharmony_ci return ret; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int tas5086_soc_resume(struct snd_soc_component *component) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 7858c2ecf20Sopenharmony_ci int ret; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); 7888c2ecf20Sopenharmony_ci if (ret < 0) 7898c2ecf20Sopenharmony_ci return ret; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci tas5086_reset(priv); 7928c2ecf20Sopenharmony_ci regcache_mark_dirty(priv->regmap); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci ret = tas5086_init(component->dev, priv); 7958c2ecf20Sopenharmony_ci if (ret < 0) 7968c2ecf20Sopenharmony_ci return ret; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci ret = regcache_sync(priv->regmap); 7998c2ecf20Sopenharmony_ci if (ret < 0) 8008c2ecf20Sopenharmony_ci return ret; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci return 0; 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci#else 8058c2ecf20Sopenharmony_ci#define tas5086_soc_suspend NULL 8068c2ecf20Sopenharmony_ci#define tas5086_soc_resume NULL 8078c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 8108c2ecf20Sopenharmony_cistatic const struct of_device_id tas5086_dt_ids[] = { 8118c2ecf20Sopenharmony_ci { .compatible = "ti,tas5086", }, 8128c2ecf20Sopenharmony_ci { } 8138c2ecf20Sopenharmony_ci}; 8148c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tas5086_dt_ids); 8158c2ecf20Sopenharmony_ci#endif 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int tas5086_probe(struct snd_soc_component *component) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 8208c2ecf20Sopenharmony_ci int i, ret; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); 8238c2ecf20Sopenharmony_ci if (ret < 0) { 8248c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to enable regulators: %d\n", ret); 8258c2ecf20Sopenharmony_ci return ret; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci priv->pwm_start_mid_z = 0; 8298c2ecf20Sopenharmony_ci priv->charge_period = 1300000; /* hardware default is 1300 ms */ 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (of_match_device(of_match_ptr(tas5086_dt_ids), component->dev)) { 8328c2ecf20Sopenharmony_ci struct device_node *of_node = component->dev->of_node; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci of_property_read_u32(of_node, "ti,charge-period", 8358c2ecf20Sopenharmony_ci &priv->charge_period); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 8388c2ecf20Sopenharmony_ci char name[25]; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), 8418c2ecf20Sopenharmony_ci "ti,mid-z-channel-%d", i + 1); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (of_get_property(of_node, name, NULL) != NULL) 8448c2ecf20Sopenharmony_ci priv->pwm_start_mid_z |= 1 << i; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci tas5086_reset(priv); 8498c2ecf20Sopenharmony_ci ret = tas5086_init(component->dev, priv); 8508c2ecf20Sopenharmony_ci if (ret < 0) 8518c2ecf20Sopenharmony_ci goto exit_disable_regulators; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* set master volume to 0 dB */ 8548c2ecf20Sopenharmony_ci ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30); 8558c2ecf20Sopenharmony_ci if (ret < 0) 8568c2ecf20Sopenharmony_ci goto exit_disable_regulators; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ciexit_disable_regulators: 8618c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci return ret; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic void tas5086_remove(struct snd_soc_component *component) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct tas5086_private *priv = snd_soc_component_get_drvdata(component); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (gpio_is_valid(priv->gpio_nreset)) 8718c2ecf20Sopenharmony_ci /* Set codec to the reset state */ 8728c2ecf20Sopenharmony_ci gpio_set_value(priv->gpio_nreset, 0); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); 8758c2ecf20Sopenharmony_ci}; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_tas5086 = { 8788c2ecf20Sopenharmony_ci .probe = tas5086_probe, 8798c2ecf20Sopenharmony_ci .remove = tas5086_remove, 8808c2ecf20Sopenharmony_ci .suspend = tas5086_soc_suspend, 8818c2ecf20Sopenharmony_ci .resume = tas5086_soc_resume, 8828c2ecf20Sopenharmony_ci .controls = tas5086_controls, 8838c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(tas5086_controls), 8848c2ecf20Sopenharmony_ci .dapm_widgets = tas5086_dapm_widgets, 8858c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(tas5086_dapm_widgets), 8868c2ecf20Sopenharmony_ci .dapm_routes = tas5086_dapm_routes, 8878c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(tas5086_dapm_routes), 8888c2ecf20Sopenharmony_ci .idle_bias_on = 1, 8898c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 8908c2ecf20Sopenharmony_ci .endianness = 1, 8918c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 8928c2ecf20Sopenharmony_ci}; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic const struct i2c_device_id tas5086_i2c_id[] = { 8958c2ecf20Sopenharmony_ci { "tas5086", 0 }, 8968c2ecf20Sopenharmony_ci { } 8978c2ecf20Sopenharmony_ci}; 8988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tas5086_i2c_id); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic const struct regmap_config tas5086_regmap = { 9018c2ecf20Sopenharmony_ci .reg_bits = 8, 9028c2ecf20Sopenharmony_ci .val_bits = 32, 9038c2ecf20Sopenharmony_ci .max_register = TAS5086_MAX_REGISTER, 9048c2ecf20Sopenharmony_ci .reg_defaults = tas5086_reg_defaults, 9058c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(tas5086_reg_defaults), 9068c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 9078c2ecf20Sopenharmony_ci .volatile_reg = tas5086_volatile_reg, 9088c2ecf20Sopenharmony_ci .writeable_reg = tas5086_writeable_reg, 9098c2ecf20Sopenharmony_ci .readable_reg = tas5086_accessible_reg, 9108c2ecf20Sopenharmony_ci .reg_read = tas5086_reg_read, 9118c2ecf20Sopenharmony_ci .reg_write = tas5086_reg_write, 9128c2ecf20Sopenharmony_ci}; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int tas5086_i2c_probe(struct i2c_client *i2c, 9158c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct tas5086_private *priv; 9188c2ecf20Sopenharmony_ci struct device *dev = &i2c->dev; 9198c2ecf20Sopenharmony_ci int gpio_nreset = -EINVAL; 9208c2ecf20Sopenharmony_ci int i, ret; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 9238c2ecf20Sopenharmony_ci if (!priv) 9248c2ecf20Sopenharmony_ci return -ENOMEM; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(supply_names); i++) 9278c2ecf20Sopenharmony_ci priv->supplies[i].supply = supply_names[i]; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), 9308c2ecf20Sopenharmony_ci priv->supplies); 9318c2ecf20Sopenharmony_ci if (ret < 0) { 9328c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get regulators: %d\n", ret); 9338c2ecf20Sopenharmony_ci return ret; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap); 9378c2ecf20Sopenharmony_ci if (IS_ERR(priv->regmap)) { 9388c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->regmap); 9398c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); 9408c2ecf20Sopenharmony_ci return ret; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci i2c_set_clientdata(i2c, priv); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) { 9468c2ecf20Sopenharmony_ci struct device_node *of_node = dev->of_node; 9478c2ecf20Sopenharmony_ci gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0); 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (gpio_is_valid(gpio_nreset)) 9518c2ecf20Sopenharmony_ci if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset")) 9528c2ecf20Sopenharmony_ci gpio_nreset = -EINVAL; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci priv->gpio_nreset = gpio_nreset; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); 9578c2ecf20Sopenharmony_ci if (ret < 0) { 9588c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable regulators: %d\n", ret); 9598c2ecf20Sopenharmony_ci return ret; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci tas5086_reset(priv); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */ 9658c2ecf20Sopenharmony_ci ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i); 9668c2ecf20Sopenharmony_ci if (ret == 0 && i != 0x3) { 9678c2ecf20Sopenharmony_ci dev_err(dev, 9688c2ecf20Sopenharmony_ci "Failed to identify TAS5086 codec (got %02x)\n", i); 9698c2ecf20Sopenharmony_ci ret = -ENODEV; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* 9738c2ecf20Sopenharmony_ci * The chip has been identified, so we can turn off the power 9748c2ecf20Sopenharmony_ci * again until the dai link is set up. 9758c2ecf20Sopenharmony_ci */ 9768c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(priv->supplies), priv->supplies); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (ret == 0) 9798c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&i2c->dev, 9808c2ecf20Sopenharmony_ci &soc_component_dev_tas5086, 9818c2ecf20Sopenharmony_ci &tas5086_dai, 1); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci return ret; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic int tas5086_i2c_remove(struct i2c_client *i2c) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic struct i2c_driver tas5086_i2c_driver = { 9928c2ecf20Sopenharmony_ci .driver = { 9938c2ecf20Sopenharmony_ci .name = "tas5086", 9948c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(tas5086_dt_ids), 9958c2ecf20Sopenharmony_ci }, 9968c2ecf20Sopenharmony_ci .id_table = tas5086_i2c_id, 9978c2ecf20Sopenharmony_ci .probe = tas5086_i2c_probe, 9988c2ecf20Sopenharmony_ci .remove = tas5086_i2c_remove, 9998c2ecf20Sopenharmony_ci}; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_cimodule_i2c_driver(tas5086_i2c_driver); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Mack <zonque@gmail.com>"); 10048c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver"); 10058c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1006