xref: /openbmc/linux/sound/soc/codecs/tas571x.c (revision 4b9e385b)
13fd6e7d9SKevin Cernekee /*
23fd6e7d9SKevin Cernekee  * TAS571x amplifier audio driver
33fd6e7d9SKevin Cernekee  *
43fd6e7d9SKevin Cernekee  * Copyright (C) 2015 Google, Inc.
53fd6e7d9SKevin Cernekee  * Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
63fd6e7d9SKevin Cernekee  *
723a282c4SPetr Kulhavy  * TAS5721 support:
823a282c4SPetr Kulhavy  * Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
923a282c4SPetr Kulhavy  *
103fd6e7d9SKevin Cernekee  * This program is free software; you can redistribute it and/or modify
113fd6e7d9SKevin Cernekee  * it under the terms of the GNU General Public License as published by
123fd6e7d9SKevin Cernekee  * the Free Software Foundation; either version 2 of the License, or
133fd6e7d9SKevin Cernekee  * (at your option) any later version.
143fd6e7d9SKevin Cernekee  */
153fd6e7d9SKevin Cernekee 
163fd6e7d9SKevin Cernekee #include <linux/clk.h>
173fd6e7d9SKevin Cernekee #include <linux/delay.h>
183fd6e7d9SKevin Cernekee #include <linux/device.h>
193fd6e7d9SKevin Cernekee #include <linux/gpio/consumer.h>
203fd6e7d9SKevin Cernekee #include <linux/i2c.h>
213fd6e7d9SKevin Cernekee #include <linux/init.h>
223fd6e7d9SKevin Cernekee #include <linux/kernel.h>
233fd6e7d9SKevin Cernekee #include <linux/module.h>
243fd6e7d9SKevin Cernekee #include <linux/of_device.h>
253fd6e7d9SKevin Cernekee #include <linux/regmap.h>
263fd6e7d9SKevin Cernekee #include <linux/regulator/consumer.h>
273fd6e7d9SKevin Cernekee #include <linux/stddef.h>
283fd6e7d9SKevin Cernekee #include <sound/pcm_params.h>
293fd6e7d9SKevin Cernekee #include <sound/soc.h>
303fd6e7d9SKevin Cernekee #include <sound/tlv.h>
314b9e385bSPetr Kulhavy #include <asm/unaligned.h>
323fd6e7d9SKevin Cernekee 
333fd6e7d9SKevin Cernekee #include "tas571x.h"
343fd6e7d9SKevin Cernekee 
353fd6e7d9SKevin Cernekee #define TAS571X_MAX_SUPPLIES		6
363fd6e7d9SKevin Cernekee 
373fd6e7d9SKevin Cernekee struct tas571x_chip {
383fd6e7d9SKevin Cernekee 	const char			*const *supply_names;
393fd6e7d9SKevin Cernekee 	int				num_supply_names;
403fd6e7d9SKevin Cernekee 	const struct snd_kcontrol_new	*controls;
413fd6e7d9SKevin Cernekee 	int				num_controls;
423fd6e7d9SKevin Cernekee 	const struct regmap_config	*regmap_config;
433fd6e7d9SKevin Cernekee 	int				vol_reg_size;
443fd6e7d9SKevin Cernekee };
453fd6e7d9SKevin Cernekee 
463fd6e7d9SKevin Cernekee struct tas571x_private {
473fd6e7d9SKevin Cernekee 	const struct tas571x_chip	*chip;
483fd6e7d9SKevin Cernekee 	struct regmap			*regmap;
493fd6e7d9SKevin Cernekee 	struct regulator_bulk_data	supplies[TAS571X_MAX_SUPPLIES];
503fd6e7d9SKevin Cernekee 	struct clk			*mclk;
513fd6e7d9SKevin Cernekee 	unsigned int			format;
523fd6e7d9SKevin Cernekee 	struct gpio_desc		*reset_gpio;
533fd6e7d9SKevin Cernekee 	struct gpio_desc		*pdn_gpio;
543fd6e7d9SKevin Cernekee 	struct snd_soc_codec_driver	codec_driver;
553fd6e7d9SKevin Cernekee };
563fd6e7d9SKevin Cernekee 
573fd6e7d9SKevin Cernekee static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
583fd6e7d9SKevin Cernekee {
593fd6e7d9SKevin Cernekee 	switch (reg) {
603fd6e7d9SKevin Cernekee 	case TAS571X_MVOL_REG:
613fd6e7d9SKevin Cernekee 	case TAS571X_CH1_VOL_REG:
623fd6e7d9SKevin Cernekee 	case TAS571X_CH2_VOL_REG:
633fd6e7d9SKevin Cernekee 		return priv->chip->vol_reg_size;
64a593ed09SPetr Kulhavy 	case TAS571X_INPUT_MUX_REG:
65a593ed09SPetr Kulhavy 	case TAS571X_CH4_SRC_SELECT_REG:
66a593ed09SPetr Kulhavy 	case TAS571X_PWM_MUX_REG:
67a593ed09SPetr Kulhavy 		return 4;
683fd6e7d9SKevin Cernekee 	default:
693fd6e7d9SKevin Cernekee 		return 1;
703fd6e7d9SKevin Cernekee 	}
713fd6e7d9SKevin Cernekee }
723fd6e7d9SKevin Cernekee 
733fd6e7d9SKevin Cernekee static int tas571x_reg_write(void *context, unsigned int reg,
743fd6e7d9SKevin Cernekee 			     unsigned int value)
753fd6e7d9SKevin Cernekee {
763fd6e7d9SKevin Cernekee 	struct i2c_client *client = context;
773fd6e7d9SKevin Cernekee 	struct tas571x_private *priv = i2c_get_clientdata(client);
783fd6e7d9SKevin Cernekee 	unsigned int i, size;
793fd6e7d9SKevin Cernekee 	uint8_t buf[5];
803fd6e7d9SKevin Cernekee 	int ret;
813fd6e7d9SKevin Cernekee 
823fd6e7d9SKevin Cernekee 	size = tas571x_register_size(priv, reg);
833fd6e7d9SKevin Cernekee 	buf[0] = reg;
843fd6e7d9SKevin Cernekee 
853fd6e7d9SKevin Cernekee 	for (i = size; i >= 1; --i) {
863fd6e7d9SKevin Cernekee 		buf[i] = value;
873fd6e7d9SKevin Cernekee 		value >>= 8;
883fd6e7d9SKevin Cernekee 	}
893fd6e7d9SKevin Cernekee 
903fd6e7d9SKevin Cernekee 	ret = i2c_master_send(client, buf, size + 1);
913fd6e7d9SKevin Cernekee 	if (ret == size + 1)
923fd6e7d9SKevin Cernekee 		return 0;
933fd6e7d9SKevin Cernekee 	else if (ret < 0)
943fd6e7d9SKevin Cernekee 		return ret;
953fd6e7d9SKevin Cernekee 	else
963fd6e7d9SKevin Cernekee 		return -EIO;
973fd6e7d9SKevin Cernekee }
983fd6e7d9SKevin Cernekee 
993fd6e7d9SKevin Cernekee static int tas571x_reg_read(void *context, unsigned int reg,
1003fd6e7d9SKevin Cernekee 			    unsigned int *value)
1013fd6e7d9SKevin Cernekee {
1023fd6e7d9SKevin Cernekee 	struct i2c_client *client = context;
1033fd6e7d9SKevin Cernekee 	struct tas571x_private *priv = i2c_get_clientdata(client);
1043fd6e7d9SKevin Cernekee 	uint8_t send_buf, recv_buf[4];
1053fd6e7d9SKevin Cernekee 	struct i2c_msg msgs[2];
1063fd6e7d9SKevin Cernekee 	unsigned int size;
1073fd6e7d9SKevin Cernekee 	unsigned int i;
1083fd6e7d9SKevin Cernekee 	int ret;
1093fd6e7d9SKevin Cernekee 
1103fd6e7d9SKevin Cernekee 	size = tas571x_register_size(priv, reg);
1113fd6e7d9SKevin Cernekee 	send_buf = reg;
1123fd6e7d9SKevin Cernekee 
1133fd6e7d9SKevin Cernekee 	msgs[0].addr = client->addr;
1143fd6e7d9SKevin Cernekee 	msgs[0].len = sizeof(send_buf);
1153fd6e7d9SKevin Cernekee 	msgs[0].buf = &send_buf;
1163fd6e7d9SKevin Cernekee 	msgs[0].flags = 0;
1173fd6e7d9SKevin Cernekee 
1183fd6e7d9SKevin Cernekee 	msgs[1].addr = client->addr;
1193fd6e7d9SKevin Cernekee 	msgs[1].len = size;
1203fd6e7d9SKevin Cernekee 	msgs[1].buf = recv_buf;
1213fd6e7d9SKevin Cernekee 	msgs[1].flags = I2C_M_RD;
1223fd6e7d9SKevin Cernekee 
1233fd6e7d9SKevin Cernekee 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
1243fd6e7d9SKevin Cernekee 	if (ret < 0)
1253fd6e7d9SKevin Cernekee 		return ret;
1263fd6e7d9SKevin Cernekee 	else if (ret != ARRAY_SIZE(msgs))
1273fd6e7d9SKevin Cernekee 		return -EIO;
1283fd6e7d9SKevin Cernekee 
1293fd6e7d9SKevin Cernekee 	*value = 0;
1303fd6e7d9SKevin Cernekee 
1313fd6e7d9SKevin Cernekee 	for (i = 0; i < size; i++) {
1323fd6e7d9SKevin Cernekee 		*value <<= 8;
1333fd6e7d9SKevin Cernekee 		*value |= recv_buf[i];
1343fd6e7d9SKevin Cernekee 	}
1353fd6e7d9SKevin Cernekee 
1363fd6e7d9SKevin Cernekee 	return 0;
1373fd6e7d9SKevin Cernekee }
1383fd6e7d9SKevin Cernekee 
1394b9e385bSPetr Kulhavy /*
1404b9e385bSPetr Kulhavy  * register write for 8- and 20-byte registers
1414b9e385bSPetr Kulhavy  */
1424b9e385bSPetr Kulhavy static int tas571x_reg_write_multiword(struct i2c_client *client,
1434b9e385bSPetr Kulhavy 		unsigned int reg, const long values[], size_t len)
1444b9e385bSPetr Kulhavy {
1454b9e385bSPetr Kulhavy 	size_t i;
1464b9e385bSPetr Kulhavy 	uint8_t *buf, *p;
1474b9e385bSPetr Kulhavy 	int ret;
1484b9e385bSPetr Kulhavy 	size_t send_size = 1 + len * sizeof(uint32_t);
1494b9e385bSPetr Kulhavy 
1504b9e385bSPetr Kulhavy 	buf = kzalloc(send_size, GFP_KERNEL | GFP_DMA);
1514b9e385bSPetr Kulhavy 	if (!buf)
1524b9e385bSPetr Kulhavy 		return -ENOMEM;
1534b9e385bSPetr Kulhavy 	buf[0] = reg;
1544b9e385bSPetr Kulhavy 
1554b9e385bSPetr Kulhavy 	for (i = 0, p = buf + 1; i < len; i++, p += sizeof(uint32_t))
1564b9e385bSPetr Kulhavy 		put_unaligned_be32(values[i], p);
1574b9e385bSPetr Kulhavy 
1584b9e385bSPetr Kulhavy 	ret = i2c_master_send(client, buf, send_size);
1594b9e385bSPetr Kulhavy 
1604b9e385bSPetr Kulhavy 	kfree(buf);
1614b9e385bSPetr Kulhavy 
1624b9e385bSPetr Kulhavy 	if (ret == send_size)
1634b9e385bSPetr Kulhavy 		return 0;
1644b9e385bSPetr Kulhavy 	else if (ret < 0)
1654b9e385bSPetr Kulhavy 		return ret;
1664b9e385bSPetr Kulhavy 	else
1674b9e385bSPetr Kulhavy 		return -EIO;
1684b9e385bSPetr Kulhavy }
1694b9e385bSPetr Kulhavy 
1704b9e385bSPetr Kulhavy /*
1714b9e385bSPetr Kulhavy  * register read for 8- and 20-byte registers
1724b9e385bSPetr Kulhavy  */
1734b9e385bSPetr Kulhavy static int tas571x_reg_read_multiword(struct i2c_client *client,
1744b9e385bSPetr Kulhavy 		unsigned int reg, long values[], size_t len)
1754b9e385bSPetr Kulhavy {
1764b9e385bSPetr Kulhavy 	unsigned int i;
1774b9e385bSPetr Kulhavy 	uint8_t send_buf;
1784b9e385bSPetr Kulhavy 	uint8_t *recv_buf, *p;
1794b9e385bSPetr Kulhavy 	struct i2c_msg msgs[2];
1804b9e385bSPetr Kulhavy 	unsigned int recv_size = len * sizeof(uint32_t);
1814b9e385bSPetr Kulhavy 	int ret;
1824b9e385bSPetr Kulhavy 
1834b9e385bSPetr Kulhavy 	recv_buf = kzalloc(recv_size, GFP_KERNEL | GFP_DMA);
1844b9e385bSPetr Kulhavy 	if (!recv_buf)
1854b9e385bSPetr Kulhavy 		return -ENOMEM;
1864b9e385bSPetr Kulhavy 
1874b9e385bSPetr Kulhavy 	send_buf = reg;
1884b9e385bSPetr Kulhavy 
1894b9e385bSPetr Kulhavy 	msgs[0].addr = client->addr;
1904b9e385bSPetr Kulhavy 	msgs[0].len = sizeof(send_buf);
1914b9e385bSPetr Kulhavy 	msgs[0].buf = &send_buf;
1924b9e385bSPetr Kulhavy 	msgs[0].flags = 0;
1934b9e385bSPetr Kulhavy 
1944b9e385bSPetr Kulhavy 	msgs[1].addr = client->addr;
1954b9e385bSPetr Kulhavy 	msgs[1].len = recv_size;
1964b9e385bSPetr Kulhavy 	msgs[1].buf = recv_buf;
1974b9e385bSPetr Kulhavy 	msgs[1].flags = I2C_M_RD;
1984b9e385bSPetr Kulhavy 
1994b9e385bSPetr Kulhavy 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
2004b9e385bSPetr Kulhavy 	if (ret < 0)
2014b9e385bSPetr Kulhavy 		goto err_ret;
2024b9e385bSPetr Kulhavy 	else if (ret != ARRAY_SIZE(msgs)) {
2034b9e385bSPetr Kulhavy 		ret = -EIO;
2044b9e385bSPetr Kulhavy 		goto err_ret;
2054b9e385bSPetr Kulhavy 	}
2064b9e385bSPetr Kulhavy 
2074b9e385bSPetr Kulhavy 	for (i = 0, p = recv_buf; i < len; i++, p += sizeof(uint32_t))
2084b9e385bSPetr Kulhavy 		values[i] = get_unaligned_be32(p);
2094b9e385bSPetr Kulhavy 
2104b9e385bSPetr Kulhavy err_ret:
2114b9e385bSPetr Kulhavy 	kfree(recv_buf);
2124b9e385bSPetr Kulhavy 	return ret;
2134b9e385bSPetr Kulhavy }
2144b9e385bSPetr Kulhavy 
2154b9e385bSPetr Kulhavy /*
2164b9e385bSPetr Kulhavy  * Integer array controls for setting biquad, mixer, DRC coefficients.
2174b9e385bSPetr Kulhavy  * According to the datasheet each coefficient is effectively 26bits,
2184b9e385bSPetr Kulhavy  * i.e. stored as 32bits, where bits [31:26] are ignored.
2194b9e385bSPetr Kulhavy  * TI's TAS57xx Graphical Development Environment tool however produces
2204b9e385bSPetr Kulhavy  * coefficients with more than 26 bits. For this reason we allow values
2214b9e385bSPetr Kulhavy  * in the full 32-bits reange.
2224b9e385bSPetr Kulhavy  * The coefficients are ordered as given in the TAS571x data sheet:
2234b9e385bSPetr Kulhavy  * b0, b1, b2, a1, a2
2244b9e385bSPetr Kulhavy  */
2254b9e385bSPetr Kulhavy 
2264b9e385bSPetr Kulhavy static int tas571x_coefficient_info(struct snd_kcontrol *kcontrol,
2274b9e385bSPetr Kulhavy 				   struct snd_ctl_elem_info *uinfo)
2284b9e385bSPetr Kulhavy {
2294b9e385bSPetr Kulhavy 	int numcoef = kcontrol->private_value >> 16;
2304b9e385bSPetr Kulhavy 
2314b9e385bSPetr Kulhavy 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2324b9e385bSPetr Kulhavy 	uinfo->count = numcoef;
2334b9e385bSPetr Kulhavy 	uinfo->value.integer.min = 0;
2344b9e385bSPetr Kulhavy 	uinfo->value.integer.max = 0xffffffff;
2354b9e385bSPetr Kulhavy 	return 0;
2364b9e385bSPetr Kulhavy }
2374b9e385bSPetr Kulhavy 
2384b9e385bSPetr Kulhavy static int tas571x_coefficient_get(struct snd_kcontrol *kcontrol,
2394b9e385bSPetr Kulhavy 				  struct snd_ctl_elem_value *ucontrol)
2404b9e385bSPetr Kulhavy {
2414b9e385bSPetr Kulhavy 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2424b9e385bSPetr Kulhavy 	struct i2c_client *i2c = to_i2c_client(codec->dev);
2434b9e385bSPetr Kulhavy 	int numcoef = kcontrol->private_value >> 16;
2444b9e385bSPetr Kulhavy 	int index = kcontrol->private_value & 0xffff;
2454b9e385bSPetr Kulhavy 
2464b9e385bSPetr Kulhavy 	return tas571x_reg_read_multiword(i2c, index,
2474b9e385bSPetr Kulhavy 		ucontrol->value.integer.value, numcoef);
2484b9e385bSPetr Kulhavy }
2494b9e385bSPetr Kulhavy 
2504b9e385bSPetr Kulhavy static int tas571x_coefficient_put(struct snd_kcontrol *kcontrol,
2514b9e385bSPetr Kulhavy 				  struct snd_ctl_elem_value *ucontrol)
2524b9e385bSPetr Kulhavy {
2534b9e385bSPetr Kulhavy 	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2544b9e385bSPetr Kulhavy 	struct i2c_client *i2c = to_i2c_client(codec->dev);
2554b9e385bSPetr Kulhavy 	int numcoef = kcontrol->private_value >> 16;
2564b9e385bSPetr Kulhavy 	int index = kcontrol->private_value & 0xffff;
2574b9e385bSPetr Kulhavy 
2584b9e385bSPetr Kulhavy 	return tas571x_reg_write_multiword(i2c, index,
2594b9e385bSPetr Kulhavy 		ucontrol->value.integer.value, numcoef);
2604b9e385bSPetr Kulhavy }
2614b9e385bSPetr Kulhavy 
2623fd6e7d9SKevin Cernekee static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
2633fd6e7d9SKevin Cernekee {
2643fd6e7d9SKevin Cernekee 	struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
2653fd6e7d9SKevin Cernekee 
2663fd6e7d9SKevin Cernekee 	priv->format = format;
2673fd6e7d9SKevin Cernekee 
2683fd6e7d9SKevin Cernekee 	return 0;
2693fd6e7d9SKevin Cernekee }
2703fd6e7d9SKevin Cernekee 
2713fd6e7d9SKevin Cernekee static int tas571x_hw_params(struct snd_pcm_substream *substream,
2723fd6e7d9SKevin Cernekee 			     struct snd_pcm_hw_params *params,
2733fd6e7d9SKevin Cernekee 			     struct snd_soc_dai *dai)
2743fd6e7d9SKevin Cernekee {
2753fd6e7d9SKevin Cernekee 	struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
2763fd6e7d9SKevin Cernekee 	u32 val;
2773fd6e7d9SKevin Cernekee 
2783fd6e7d9SKevin Cernekee 	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
2793fd6e7d9SKevin Cernekee 	case SND_SOC_DAIFMT_RIGHT_J:
2803fd6e7d9SKevin Cernekee 		val = 0x00;
2813fd6e7d9SKevin Cernekee 		break;
2823fd6e7d9SKevin Cernekee 	case SND_SOC_DAIFMT_I2S:
2833fd6e7d9SKevin Cernekee 		val = 0x03;
2843fd6e7d9SKevin Cernekee 		break;
2853fd6e7d9SKevin Cernekee 	case SND_SOC_DAIFMT_LEFT_J:
2863fd6e7d9SKevin Cernekee 		val = 0x06;
2873fd6e7d9SKevin Cernekee 		break;
2883fd6e7d9SKevin Cernekee 	default:
2893fd6e7d9SKevin Cernekee 		return -EINVAL;
2903fd6e7d9SKevin Cernekee 	}
2913fd6e7d9SKevin Cernekee 
2923fd6e7d9SKevin Cernekee 	if (params_width(params) >= 24)
2933fd6e7d9SKevin Cernekee 		val += 2;
2943fd6e7d9SKevin Cernekee 	else if (params_width(params) >= 20)
2953fd6e7d9SKevin Cernekee 		val += 1;
2963fd6e7d9SKevin Cernekee 
2973fd6e7d9SKevin Cernekee 	return regmap_update_bits(priv->regmap, TAS571X_SDI_REG,
2983fd6e7d9SKevin Cernekee 				  TAS571X_SDI_FMT_MASK, val);
2993fd6e7d9SKevin Cernekee }
3003fd6e7d9SKevin Cernekee 
30104004850SPetr Kulhavy static int tas571x_mute(struct snd_soc_dai *dai, int mute)
30204004850SPetr Kulhavy {
30304004850SPetr Kulhavy 	struct snd_soc_codec *codec = dai->codec;
30404004850SPetr Kulhavy 	u8 sysctl2;
30504004850SPetr Kulhavy 	int ret;
30604004850SPetr Kulhavy 
30704004850SPetr Kulhavy 	sysctl2 = mute ? TAS571X_SYS_CTRL_2_SDN_MASK : 0;
30804004850SPetr Kulhavy 
30904004850SPetr Kulhavy 	ret = snd_soc_update_bits(codec,
31004004850SPetr Kulhavy 			    TAS571X_SYS_CTRL_2_REG,
31104004850SPetr Kulhavy 		     TAS571X_SYS_CTRL_2_SDN_MASK,
31204004850SPetr Kulhavy 		     sysctl2);
31304004850SPetr Kulhavy 	usleep_range(1000, 2000);
31404004850SPetr Kulhavy 
31504004850SPetr Kulhavy 	return ret;
31604004850SPetr Kulhavy }
31704004850SPetr Kulhavy 
3183fd6e7d9SKevin Cernekee static int tas571x_set_bias_level(struct snd_soc_codec *codec,
3193fd6e7d9SKevin Cernekee 				  enum snd_soc_bias_level level)
3203fd6e7d9SKevin Cernekee {
3213fd6e7d9SKevin Cernekee 	struct tas571x_private *priv = snd_soc_codec_get_drvdata(codec);
3223fd6e7d9SKevin Cernekee 	int ret;
3233fd6e7d9SKevin Cernekee 
3243fd6e7d9SKevin Cernekee 	switch (level) {
3253fd6e7d9SKevin Cernekee 	case SND_SOC_BIAS_ON:
3263fd6e7d9SKevin Cernekee 		break;
3273fd6e7d9SKevin Cernekee 	case SND_SOC_BIAS_PREPARE:
3283fd6e7d9SKevin Cernekee 		break;
3293fd6e7d9SKevin Cernekee 	case SND_SOC_BIAS_STANDBY:
3308f218fa9SLars-Peter Clausen 		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
3313fd6e7d9SKevin Cernekee 			if (!IS_ERR(priv->mclk)) {
3323fd6e7d9SKevin Cernekee 				ret = clk_prepare_enable(priv->mclk);
3333fd6e7d9SKevin Cernekee 				if (ret) {
3343fd6e7d9SKevin Cernekee 					dev_err(codec->dev,
3353fd6e7d9SKevin Cernekee 						"Failed to enable master clock: %d\n",
3363fd6e7d9SKevin Cernekee 						ret);
3373fd6e7d9SKevin Cernekee 					return ret;
3383fd6e7d9SKevin Cernekee 				}
3393fd6e7d9SKevin Cernekee 			}
3403fd6e7d9SKevin Cernekee 
3413fd6e7d9SKevin Cernekee 			gpiod_set_value(priv->pdn_gpio, 0);
3423fd6e7d9SKevin Cernekee 			usleep_range(5000, 6000);
3433fd6e7d9SKevin Cernekee 
3443fd6e7d9SKevin Cernekee 			regcache_cache_only(priv->regmap, false);
3453fd6e7d9SKevin Cernekee 			ret = regcache_sync(priv->regmap);
3463fd6e7d9SKevin Cernekee 			if (ret)
3473fd6e7d9SKevin Cernekee 				return ret;
3483fd6e7d9SKevin Cernekee 		}
3493fd6e7d9SKevin Cernekee 		break;
3503fd6e7d9SKevin Cernekee 	case SND_SOC_BIAS_OFF:
3513fd6e7d9SKevin Cernekee 		regcache_cache_only(priv->regmap, true);
3523fd6e7d9SKevin Cernekee 		gpiod_set_value(priv->pdn_gpio, 1);
3533fd6e7d9SKevin Cernekee 
3543fd6e7d9SKevin Cernekee 		if (!IS_ERR(priv->mclk))
3553fd6e7d9SKevin Cernekee 			clk_disable_unprepare(priv->mclk);
3563fd6e7d9SKevin Cernekee 		break;
3573fd6e7d9SKevin Cernekee 	}
3583fd6e7d9SKevin Cernekee 
3593fd6e7d9SKevin Cernekee 	return 0;
3603fd6e7d9SKevin Cernekee }
3613fd6e7d9SKevin Cernekee 
3623fd6e7d9SKevin Cernekee static const struct snd_soc_dai_ops tas571x_dai_ops = {
3633fd6e7d9SKevin Cernekee 	.set_fmt	= tas571x_set_dai_fmt,
3643fd6e7d9SKevin Cernekee 	.hw_params	= tas571x_hw_params,
36504004850SPetr Kulhavy 	.digital_mute	= tas571x_mute,
3663fd6e7d9SKevin Cernekee };
3673fd6e7d9SKevin Cernekee 
3684b9e385bSPetr Kulhavy 
3694b9e385bSPetr Kulhavy #define BIQUAD_COEFS(xname, reg) \
3704b9e385bSPetr Kulhavy {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
3714b9e385bSPetr Kulhavy 	.info = tas571x_coefficient_info, \
3724b9e385bSPetr Kulhavy 	.get = tas571x_coefficient_get,\
3734b9e385bSPetr Kulhavy 	.put = tas571x_coefficient_put, \
3744b9e385bSPetr Kulhavy 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
3754b9e385bSPetr Kulhavy 	.private_value = reg | (5 << 16) }
3764b9e385bSPetr Kulhavy 
3773fd6e7d9SKevin Cernekee static const char *const tas5711_supply_names[] = {
3783fd6e7d9SKevin Cernekee 	"AVDD",
3793fd6e7d9SKevin Cernekee 	"DVDD",
3803fd6e7d9SKevin Cernekee 	"PVDD_A",
3813fd6e7d9SKevin Cernekee 	"PVDD_B",
3823fd6e7d9SKevin Cernekee 	"PVDD_C",
3833fd6e7d9SKevin Cernekee 	"PVDD_D",
3843fd6e7d9SKevin Cernekee };
3853fd6e7d9SKevin Cernekee 
3863fd6e7d9SKevin Cernekee static const DECLARE_TLV_DB_SCALE(tas5711_volume_tlv, -10350, 50, 1);
3873fd6e7d9SKevin Cernekee 
3883fd6e7d9SKevin Cernekee static const struct snd_kcontrol_new tas5711_controls[] = {
3893fd6e7d9SKevin Cernekee 	SOC_SINGLE_TLV("Master Volume",
3903fd6e7d9SKevin Cernekee 		       TAS571X_MVOL_REG,
3913fd6e7d9SKevin Cernekee 		       0, 0xff, 1, tas5711_volume_tlv),
3923fd6e7d9SKevin Cernekee 	SOC_DOUBLE_R_TLV("Speaker Volume",
3933fd6e7d9SKevin Cernekee 			 TAS571X_CH1_VOL_REG,
3943fd6e7d9SKevin Cernekee 			 TAS571X_CH2_VOL_REG,
3953fd6e7d9SKevin Cernekee 			 0, 0xff, 1, tas5711_volume_tlv),
3963fd6e7d9SKevin Cernekee 	SOC_DOUBLE("Speaker Switch",
3973fd6e7d9SKevin Cernekee 		   TAS571X_SOFT_MUTE_REG,
3983fd6e7d9SKevin Cernekee 		   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
3993fd6e7d9SKevin Cernekee 		   1, 1),
4003fd6e7d9SKevin Cernekee };
4013fd6e7d9SKevin Cernekee 
402a593ed09SPetr Kulhavy static const struct regmap_range tas571x_readonly_regs_range[] = {
403a593ed09SPetr Kulhavy 	regmap_reg_range(TAS571X_CLK_CTRL_REG,  TAS571X_DEV_ID_REG),
404a593ed09SPetr Kulhavy };
405a593ed09SPetr Kulhavy 
406a593ed09SPetr Kulhavy static const struct regmap_range tas571x_volatile_regs_range[] = {
407a593ed09SPetr Kulhavy 	regmap_reg_range(TAS571X_CLK_CTRL_REG,  TAS571X_ERR_STATUS_REG),
408a593ed09SPetr Kulhavy 	regmap_reg_range(TAS571X_OSC_TRIM_REG,  TAS571X_OSC_TRIM_REG),
409a593ed09SPetr Kulhavy };
410a593ed09SPetr Kulhavy 
411a593ed09SPetr Kulhavy static const struct regmap_access_table tas571x_write_regs = {
412a593ed09SPetr Kulhavy 	.no_ranges =	tas571x_readonly_regs_range,
413a593ed09SPetr Kulhavy 	.n_no_ranges =	ARRAY_SIZE(tas571x_readonly_regs_range),
414a593ed09SPetr Kulhavy };
415a593ed09SPetr Kulhavy 
416a593ed09SPetr Kulhavy static const struct regmap_access_table tas571x_volatile_regs = {
417a593ed09SPetr Kulhavy 	.yes_ranges =	tas571x_volatile_regs_range,
418a593ed09SPetr Kulhavy 	.n_yes_ranges =	ARRAY_SIZE(tas571x_volatile_regs_range),
419a593ed09SPetr Kulhavy 
420a593ed09SPetr Kulhavy };
421a593ed09SPetr Kulhavy 
4223fd6e7d9SKevin Cernekee static const struct reg_default tas5711_reg_defaults[] = {
4233fd6e7d9SKevin Cernekee 	{ 0x04, 0x05 },
4243fd6e7d9SKevin Cernekee 	{ 0x05, 0x40 },
4253fd6e7d9SKevin Cernekee 	{ 0x06, 0x00 },
4263fd6e7d9SKevin Cernekee 	{ 0x07, 0xff },
4273fd6e7d9SKevin Cernekee 	{ 0x08, 0x30 },
4283fd6e7d9SKevin Cernekee 	{ 0x09, 0x30 },
4293fd6e7d9SKevin Cernekee 	{ 0x1b, 0x82 },
4303fd6e7d9SKevin Cernekee };
4313fd6e7d9SKevin Cernekee 
4323fd6e7d9SKevin Cernekee static const struct regmap_config tas5711_regmap_config = {
4333fd6e7d9SKevin Cernekee 	.reg_bits			= 8,
4343fd6e7d9SKevin Cernekee 	.val_bits			= 32,
4353fd6e7d9SKevin Cernekee 	.max_register			= 0xff,
4363fd6e7d9SKevin Cernekee 	.reg_read			= tas571x_reg_read,
4373fd6e7d9SKevin Cernekee 	.reg_write			= tas571x_reg_write,
4383fd6e7d9SKevin Cernekee 	.reg_defaults			= tas5711_reg_defaults,
4393fd6e7d9SKevin Cernekee 	.num_reg_defaults		= ARRAY_SIZE(tas5711_reg_defaults),
4403fd6e7d9SKevin Cernekee 	.cache_type			= REGCACHE_RBTREE,
441a593ed09SPetr Kulhavy 	.wr_table			= &tas571x_write_regs,
442a593ed09SPetr Kulhavy 	.volatile_table			= &tas571x_volatile_regs,
4433fd6e7d9SKevin Cernekee };
4443fd6e7d9SKevin Cernekee 
4453fd6e7d9SKevin Cernekee static const struct tas571x_chip tas5711_chip = {
4463fd6e7d9SKevin Cernekee 	.supply_names			= tas5711_supply_names,
4473fd6e7d9SKevin Cernekee 	.num_supply_names		= ARRAY_SIZE(tas5711_supply_names),
4483fd6e7d9SKevin Cernekee 	.controls			= tas5711_controls,
4493fd6e7d9SKevin Cernekee 	.num_controls			= ARRAY_SIZE(tas5711_controls),
4503fd6e7d9SKevin Cernekee 	.regmap_config			= &tas5711_regmap_config,
4513fd6e7d9SKevin Cernekee 	.vol_reg_size			= 1,
4523fd6e7d9SKevin Cernekee };
4533fd6e7d9SKevin Cernekee 
4543fd6e7d9SKevin Cernekee static const char *const tas5717_supply_names[] = {
4553fd6e7d9SKevin Cernekee 	"AVDD",
4563fd6e7d9SKevin Cernekee 	"DVDD",
4573fd6e7d9SKevin Cernekee 	"HPVDD",
4583fd6e7d9SKevin Cernekee 	"PVDD_AB",
4593fd6e7d9SKevin Cernekee 	"PVDD_CD",
4603fd6e7d9SKevin Cernekee };
4613fd6e7d9SKevin Cernekee 
4623fd6e7d9SKevin Cernekee static const DECLARE_TLV_DB_SCALE(tas5717_volume_tlv, -10375, 25, 0);
4633fd6e7d9SKevin Cernekee 
4643fd6e7d9SKevin Cernekee static const struct snd_kcontrol_new tas5717_controls[] = {
4653fd6e7d9SKevin Cernekee 	/* MVOL LSB is ignored - see comments in tas571x_i2c_probe() */
4663fd6e7d9SKevin Cernekee 	SOC_SINGLE_TLV("Master Volume",
4673fd6e7d9SKevin Cernekee 		       TAS571X_MVOL_REG, 1, 0x1ff, 1,
4683fd6e7d9SKevin Cernekee 		       tas5717_volume_tlv),
4693fd6e7d9SKevin Cernekee 	SOC_DOUBLE_R_TLV("Speaker Volume",
4703fd6e7d9SKevin Cernekee 			 TAS571X_CH1_VOL_REG, TAS571X_CH2_VOL_REG,
4713fd6e7d9SKevin Cernekee 			 1, 0x1ff, 1, tas5717_volume_tlv),
4723fd6e7d9SKevin Cernekee 	SOC_DOUBLE("Speaker Switch",
4733fd6e7d9SKevin Cernekee 		   TAS571X_SOFT_MUTE_REG,
4743fd6e7d9SKevin Cernekee 		   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
4753fd6e7d9SKevin Cernekee 		   1, 1),
4764b9e385bSPetr Kulhavy 
4774b9e385bSPetr Kulhavy 	/*
4784b9e385bSPetr Kulhavy 	 * The biquads are named according to the register names.
4794b9e385bSPetr Kulhavy 	 * Please note that TI's TAS57xx Graphical Development Environment
4804b9e385bSPetr Kulhavy 	 * tool names them different.
4814b9e385bSPetr Kulhavy 	 */
4824b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 0", TAS5717_CH1_BQ0_REG),
4834b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 1", TAS5717_CH1_BQ1_REG),
4844b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 2", TAS5717_CH1_BQ2_REG),
4854b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 3", TAS5717_CH1_BQ3_REG),
4864b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 4", TAS5717_CH1_BQ4_REG),
4874b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 5", TAS5717_CH1_BQ5_REG),
4884b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 6", TAS5717_CH1_BQ6_REG),
4894b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 7", TAS5717_CH1_BQ7_REG),
4904b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 8", TAS5717_CH1_BQ8_REG),
4914b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 9", TAS5717_CH1_BQ9_REG),
4924b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 10", TAS5717_CH1_BQ10_REG),
4934b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH1 - Biquad 11", TAS5717_CH1_BQ11_REG),
4944b9e385bSPetr Kulhavy 
4954b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 0", TAS5717_CH2_BQ0_REG),
4964b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 1", TAS5717_CH2_BQ1_REG),
4974b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 2", TAS5717_CH2_BQ2_REG),
4984b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 3", TAS5717_CH2_BQ3_REG),
4994b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 4", TAS5717_CH2_BQ4_REG),
5004b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 5", TAS5717_CH2_BQ5_REG),
5014b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 6", TAS5717_CH2_BQ6_REG),
5024b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 7", TAS5717_CH2_BQ7_REG),
5034b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 8", TAS5717_CH2_BQ8_REG),
5044b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 9", TAS5717_CH2_BQ9_REG),
5054b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 10", TAS5717_CH2_BQ10_REG),
5064b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH2 - Biquad 11", TAS5717_CH2_BQ11_REG),
5074b9e385bSPetr Kulhavy 
5084b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH3 - Biquad 0", TAS5717_CH3_BQ0_REG),
5094b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH3 - Biquad 1", TAS5717_CH3_BQ1_REG),
5104b9e385bSPetr Kulhavy 
5114b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH4 - Biquad 0", TAS5717_CH4_BQ0_REG),
5124b9e385bSPetr Kulhavy 	BIQUAD_COEFS("CH4 - Biquad 1", TAS5717_CH4_BQ1_REG),
5133fd6e7d9SKevin Cernekee };
5143fd6e7d9SKevin Cernekee 
5153fd6e7d9SKevin Cernekee static const struct reg_default tas5717_reg_defaults[] = {
5163fd6e7d9SKevin Cernekee 	{ 0x04, 0x05 },
5173fd6e7d9SKevin Cernekee 	{ 0x05, 0x40 },
5183fd6e7d9SKevin Cernekee 	{ 0x06, 0x00 },
5193fd6e7d9SKevin Cernekee 	{ 0x07, 0x03ff },
5203fd6e7d9SKevin Cernekee 	{ 0x08, 0x00c0 },
5213fd6e7d9SKevin Cernekee 	{ 0x09, 0x00c0 },
5223fd6e7d9SKevin Cernekee 	{ 0x1b, 0x82 },
5233fd6e7d9SKevin Cernekee };
5243fd6e7d9SKevin Cernekee 
5253fd6e7d9SKevin Cernekee static const struct regmap_config tas5717_regmap_config = {
5263fd6e7d9SKevin Cernekee 	.reg_bits			= 8,
5273fd6e7d9SKevin Cernekee 	.val_bits			= 32,
5283fd6e7d9SKevin Cernekee 	.max_register			= 0xff,
5293fd6e7d9SKevin Cernekee 	.reg_read			= tas571x_reg_read,
5303fd6e7d9SKevin Cernekee 	.reg_write			= tas571x_reg_write,
5313fd6e7d9SKevin Cernekee 	.reg_defaults			= tas5717_reg_defaults,
5323fd6e7d9SKevin Cernekee 	.num_reg_defaults		= ARRAY_SIZE(tas5717_reg_defaults),
5333fd6e7d9SKevin Cernekee 	.cache_type			= REGCACHE_RBTREE,
534a593ed09SPetr Kulhavy 	.wr_table			= &tas571x_write_regs,
535a593ed09SPetr Kulhavy 	.volatile_table			= &tas571x_volatile_regs,
5363fd6e7d9SKevin Cernekee };
5373fd6e7d9SKevin Cernekee 
5383fd6e7d9SKevin Cernekee /* This entry is reused for tas5719 as the software interface is identical. */
5393fd6e7d9SKevin Cernekee static const struct tas571x_chip tas5717_chip = {
5403fd6e7d9SKevin Cernekee 	.supply_names			= tas5717_supply_names,
5413fd6e7d9SKevin Cernekee 	.num_supply_names		= ARRAY_SIZE(tas5717_supply_names),
5423fd6e7d9SKevin Cernekee 	.controls			= tas5717_controls,
5433fd6e7d9SKevin Cernekee 	.num_controls			= ARRAY_SIZE(tas5717_controls),
5443fd6e7d9SKevin Cernekee 	.regmap_config			= &tas5717_regmap_config,
5453fd6e7d9SKevin Cernekee 	.vol_reg_size			= 2,
5463fd6e7d9SKevin Cernekee };
5473fd6e7d9SKevin Cernekee 
54823a282c4SPetr Kulhavy static const char *const tas5721_supply_names[] = {
54923a282c4SPetr Kulhavy 	"AVDD",
55023a282c4SPetr Kulhavy 	"DVDD",
55123a282c4SPetr Kulhavy 	"DRVDD",
55223a282c4SPetr Kulhavy 	"PVDD",
55323a282c4SPetr Kulhavy };
55423a282c4SPetr Kulhavy 
55523a282c4SPetr Kulhavy static const struct snd_kcontrol_new tas5721_controls[] = {
55623a282c4SPetr Kulhavy 	SOC_SINGLE_TLV("Master Volume",
55723a282c4SPetr Kulhavy 		       TAS571X_MVOL_REG,
55823a282c4SPetr Kulhavy 		       0, 0xff, 1, tas5711_volume_tlv),
55923a282c4SPetr Kulhavy 	SOC_DOUBLE_R_TLV("Speaker Volume",
56023a282c4SPetr Kulhavy 			 TAS571X_CH1_VOL_REG,
56123a282c4SPetr Kulhavy 			 TAS571X_CH2_VOL_REG,
56223a282c4SPetr Kulhavy 			 0, 0xff, 1, tas5711_volume_tlv),
56323a282c4SPetr Kulhavy 	SOC_DOUBLE("Speaker Switch",
56423a282c4SPetr Kulhavy 		   TAS571X_SOFT_MUTE_REG,
56523a282c4SPetr Kulhavy 		   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
56623a282c4SPetr Kulhavy 		   1, 1),
56723a282c4SPetr Kulhavy };
56823a282c4SPetr Kulhavy 
56923a282c4SPetr Kulhavy static const struct reg_default tas5721_reg_defaults[] = {
57023a282c4SPetr Kulhavy 	{TAS571X_CLK_CTRL_REG,		0x6c},
57123a282c4SPetr Kulhavy 	{TAS571X_DEV_ID_REG,		0x00},
57223a282c4SPetr Kulhavy 	{TAS571X_ERR_STATUS_REG,	0x00},
57323a282c4SPetr Kulhavy 	{TAS571X_SYS_CTRL_1_REG,	0xa0},
57423a282c4SPetr Kulhavy 	{TAS571X_SDI_REG,		0x05},
57523a282c4SPetr Kulhavy 	{TAS571X_SYS_CTRL_2_REG,	0x40},
57623a282c4SPetr Kulhavy 	{TAS571X_SOFT_MUTE_REG,		0x00},
57723a282c4SPetr Kulhavy 	{TAS571X_MVOL_REG,		0xff},
57823a282c4SPetr Kulhavy 	{TAS571X_CH1_VOL_REG,		0x30},
57923a282c4SPetr Kulhavy 	{TAS571X_CH2_VOL_REG,		0x30},
58023a282c4SPetr Kulhavy 	{TAS571X_CH3_VOL_REG,		0x30},
58123a282c4SPetr Kulhavy 	{TAS571X_VOL_CFG_REG,		0x91},
58223a282c4SPetr Kulhavy 	{TAS571X_MODULATION_LIMIT_REG,	0x02},
58323a282c4SPetr Kulhavy 	{TAS571X_IC_DELAY_CH1_REG,	0xac},
58423a282c4SPetr Kulhavy 	{TAS571X_IC_DELAY_CH2_REG,	0x54},
58523a282c4SPetr Kulhavy 	{TAS571X_IC_DELAY_CH3_REG,	0xac},
58623a282c4SPetr Kulhavy 	{TAS571X_IC_DELAY_CH4_REG,	0x54},
58723a282c4SPetr Kulhavy 	{TAS571X_PWM_CH_SDN_GROUP_REG,	0x30},
58823a282c4SPetr Kulhavy 	{TAS571X_START_STOP_PERIOD_REG,	0x0f},
58923a282c4SPetr Kulhavy 	{TAS571X_OSC_TRIM_REG,		0x82},
59023a282c4SPetr Kulhavy 	{TAS571X_BKND_ERR_REG,		0x02},
59123a282c4SPetr Kulhavy 	{TAS571X_INPUT_MUX_REG,		0x17772},
59223a282c4SPetr Kulhavy 	{TAS571X_CH4_SRC_SELECT_REG,	0x4303},
59323a282c4SPetr Kulhavy 	{TAS571X_PWM_MUX_REG,		0x1021345},
59423a282c4SPetr Kulhavy };
59523a282c4SPetr Kulhavy 
59623a282c4SPetr Kulhavy static const struct regmap_config tas5721_regmap_config = {
59723a282c4SPetr Kulhavy 	.reg_bits			= 8,
59823a282c4SPetr Kulhavy 	.val_bits			= 32,
59923a282c4SPetr Kulhavy 	.max_register			= 0xff,
60023a282c4SPetr Kulhavy 	.reg_read			= tas571x_reg_read,
60123a282c4SPetr Kulhavy 	.reg_write			= tas571x_reg_write,
60223a282c4SPetr Kulhavy 	.reg_defaults			= tas5721_reg_defaults,
60323a282c4SPetr Kulhavy 	.num_reg_defaults		= ARRAY_SIZE(tas5721_reg_defaults),
60423a282c4SPetr Kulhavy 	.cache_type			= REGCACHE_RBTREE,
60523a282c4SPetr Kulhavy 	.wr_table			= &tas571x_write_regs,
60623a282c4SPetr Kulhavy 	.volatile_table			= &tas571x_volatile_regs,
60723a282c4SPetr Kulhavy };
60823a282c4SPetr Kulhavy 
60923a282c4SPetr Kulhavy 
61023a282c4SPetr Kulhavy static const struct tas571x_chip tas5721_chip = {
61123a282c4SPetr Kulhavy 	.supply_names			= tas5721_supply_names,
61223a282c4SPetr Kulhavy 	.num_supply_names		= ARRAY_SIZE(tas5721_supply_names),
61323a282c4SPetr Kulhavy 	.controls			= tas5711_controls,
61423a282c4SPetr Kulhavy 	.num_controls			= ARRAY_SIZE(tas5711_controls),
61523a282c4SPetr Kulhavy 	.regmap_config			= &tas5721_regmap_config,
61623a282c4SPetr Kulhavy 	.vol_reg_size			= 1,
61723a282c4SPetr Kulhavy };
61823a282c4SPetr Kulhavy 
6193fd6e7d9SKevin Cernekee static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = {
6203fd6e7d9SKevin Cernekee 	SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
6213fd6e7d9SKevin Cernekee 	SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
6223fd6e7d9SKevin Cernekee 
6233fd6e7d9SKevin Cernekee 	SND_SOC_DAPM_OUTPUT("OUT_A"),
6243fd6e7d9SKevin Cernekee 	SND_SOC_DAPM_OUTPUT("OUT_B"),
6253fd6e7d9SKevin Cernekee 	SND_SOC_DAPM_OUTPUT("OUT_C"),
6263fd6e7d9SKevin Cernekee 	SND_SOC_DAPM_OUTPUT("OUT_D"),
6273fd6e7d9SKevin Cernekee };
6283fd6e7d9SKevin Cernekee 
6293fd6e7d9SKevin Cernekee static const struct snd_soc_dapm_route tas571x_dapm_routes[] = {
6303fd6e7d9SKevin Cernekee 	{ "DACL",  NULL, "Playback" },
6313fd6e7d9SKevin Cernekee 	{ "DACR",  NULL, "Playback" },
6323fd6e7d9SKevin Cernekee 
6333fd6e7d9SKevin Cernekee 	{ "OUT_A", NULL, "DACL" },
6343fd6e7d9SKevin Cernekee 	{ "OUT_B", NULL, "DACL" },
6353fd6e7d9SKevin Cernekee 	{ "OUT_C", NULL, "DACR" },
6363fd6e7d9SKevin Cernekee 	{ "OUT_D", NULL, "DACR" },
6373fd6e7d9SKevin Cernekee };
6383fd6e7d9SKevin Cernekee 
6393fd6e7d9SKevin Cernekee static const struct snd_soc_codec_driver tas571x_codec = {
6403fd6e7d9SKevin Cernekee 	.set_bias_level = tas571x_set_bias_level,
6413fd6e7d9SKevin Cernekee 	.idle_bias_off = true,
6423fd6e7d9SKevin Cernekee 
6433fd6e7d9SKevin Cernekee 	.dapm_widgets = tas571x_dapm_widgets,
6443fd6e7d9SKevin Cernekee 	.num_dapm_widgets = ARRAY_SIZE(tas571x_dapm_widgets),
6453fd6e7d9SKevin Cernekee 	.dapm_routes = tas571x_dapm_routes,
6463fd6e7d9SKevin Cernekee 	.num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes),
6473fd6e7d9SKevin Cernekee };
6483fd6e7d9SKevin Cernekee 
6493fd6e7d9SKevin Cernekee static struct snd_soc_dai_driver tas571x_dai = {
6503fd6e7d9SKevin Cernekee 	.name = "tas571x-hifi",
6513fd6e7d9SKevin Cernekee 	.playback = {
6523fd6e7d9SKevin Cernekee 		.stream_name = "Playback",
6533fd6e7d9SKevin Cernekee 		.channels_min = 2,
6543fd6e7d9SKevin Cernekee 		.channels_max = 2,
6553fd6e7d9SKevin Cernekee 		.rates = SNDRV_PCM_RATE_8000_48000,
6563fd6e7d9SKevin Cernekee 		.formats = SNDRV_PCM_FMTBIT_S32_LE |
6573fd6e7d9SKevin Cernekee 			   SNDRV_PCM_FMTBIT_S24_LE |
6583fd6e7d9SKevin Cernekee 			   SNDRV_PCM_FMTBIT_S16_LE,
6593fd6e7d9SKevin Cernekee 	},
6603fd6e7d9SKevin Cernekee 	.ops = &tas571x_dai_ops,
6613fd6e7d9SKevin Cernekee };
6623fd6e7d9SKevin Cernekee 
6633fd6e7d9SKevin Cernekee static const struct of_device_id tas571x_of_match[];
6643fd6e7d9SKevin Cernekee 
6653fd6e7d9SKevin Cernekee static int tas571x_i2c_probe(struct i2c_client *client,
6663fd6e7d9SKevin Cernekee 			     const struct i2c_device_id *id)
6673fd6e7d9SKevin Cernekee {
6683fd6e7d9SKevin Cernekee 	struct tas571x_private *priv;
6693fd6e7d9SKevin Cernekee 	struct device *dev = &client->dev;
67097fceb4dSKevin Cernekee 	const struct of_device_id *of_id;
6713fd6e7d9SKevin Cernekee 	int i, ret;
6723fd6e7d9SKevin Cernekee 
6733fd6e7d9SKevin Cernekee 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
6743fd6e7d9SKevin Cernekee 	if (!priv)
6753fd6e7d9SKevin Cernekee 		return -ENOMEM;
6763fd6e7d9SKevin Cernekee 	i2c_set_clientdata(client, priv);
6773fd6e7d9SKevin Cernekee 
6783fd6e7d9SKevin Cernekee 	of_id = of_match_device(tas571x_of_match, dev);
679630e413dSPetr Kulhavy 	if (of_id)
68097fceb4dSKevin Cernekee 		priv->chip = of_id->data;
681630e413dSPetr Kulhavy 	else
682630e413dSPetr Kulhavy 		priv->chip = (void *) id->driver_data;
6833fd6e7d9SKevin Cernekee 
6843fd6e7d9SKevin Cernekee 	priv->mclk = devm_clk_get(dev, "mclk");
6853fd6e7d9SKevin Cernekee 	if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) {
6863fd6e7d9SKevin Cernekee 		dev_err(dev, "Failed to request mclk: %ld\n",
6873fd6e7d9SKevin Cernekee 			PTR_ERR(priv->mclk));
6883fd6e7d9SKevin Cernekee 		return PTR_ERR(priv->mclk);
6893fd6e7d9SKevin Cernekee 	}
6903fd6e7d9SKevin Cernekee 
6913fd6e7d9SKevin Cernekee 	BUG_ON(priv->chip->num_supply_names > TAS571X_MAX_SUPPLIES);
6923fd6e7d9SKevin Cernekee 	for (i = 0; i < priv->chip->num_supply_names; i++)
6933fd6e7d9SKevin Cernekee 		priv->supplies[i].supply = priv->chip->supply_names[i];
6943fd6e7d9SKevin Cernekee 
6953fd6e7d9SKevin Cernekee 	ret = devm_regulator_bulk_get(dev, priv->chip->num_supply_names,
6963fd6e7d9SKevin Cernekee 				      priv->supplies);
6973fd6e7d9SKevin Cernekee 	if (ret) {
6983fd6e7d9SKevin Cernekee 		dev_err(dev, "Failed to get supplies: %d\n", ret);
6993fd6e7d9SKevin Cernekee 		return ret;
7003fd6e7d9SKevin Cernekee 	}
7013fd6e7d9SKevin Cernekee 	ret = regulator_bulk_enable(priv->chip->num_supply_names,
7023fd6e7d9SKevin Cernekee 				    priv->supplies);
7033fd6e7d9SKevin Cernekee 	if (ret) {
7043fd6e7d9SKevin Cernekee 		dev_err(dev, "Failed to enable supplies: %d\n", ret);
7053fd6e7d9SKevin Cernekee 		return ret;
7063fd6e7d9SKevin Cernekee 	}
7073fd6e7d9SKevin Cernekee 
7083fd6e7d9SKevin Cernekee 	priv->regmap = devm_regmap_init(dev, NULL, client,
7093fd6e7d9SKevin Cernekee 					priv->chip->regmap_config);
7103fd6e7d9SKevin Cernekee 	if (IS_ERR(priv->regmap))
7113fd6e7d9SKevin Cernekee 		return PTR_ERR(priv->regmap);
7123fd6e7d9SKevin Cernekee 
7133fd6e7d9SKevin Cernekee 	priv->pdn_gpio = devm_gpiod_get_optional(dev, "pdn", GPIOD_OUT_LOW);
7143fd6e7d9SKevin Cernekee 	if (IS_ERR(priv->pdn_gpio)) {
7153fd6e7d9SKevin Cernekee 		dev_err(dev, "error requesting pdn_gpio: %ld\n",
7163fd6e7d9SKevin Cernekee 			PTR_ERR(priv->pdn_gpio));
7173fd6e7d9SKevin Cernekee 		return PTR_ERR(priv->pdn_gpio);
7183fd6e7d9SKevin Cernekee 	}
7193fd6e7d9SKevin Cernekee 
7203fd6e7d9SKevin Cernekee 	priv->reset_gpio = devm_gpiod_get_optional(dev, "reset",
7213fd6e7d9SKevin Cernekee 						   GPIOD_OUT_HIGH);
7223fd6e7d9SKevin Cernekee 	if (IS_ERR(priv->reset_gpio)) {
7233fd6e7d9SKevin Cernekee 		dev_err(dev, "error requesting reset_gpio: %ld\n",
7243fd6e7d9SKevin Cernekee 			PTR_ERR(priv->reset_gpio));
7253fd6e7d9SKevin Cernekee 		return PTR_ERR(priv->reset_gpio);
7263fd6e7d9SKevin Cernekee 	} else if (priv->reset_gpio) {
7273fd6e7d9SKevin Cernekee 		/* pulse the active low reset line for ~100us */
7283fd6e7d9SKevin Cernekee 		usleep_range(100, 200);
7293fd6e7d9SKevin Cernekee 		gpiod_set_value(priv->reset_gpio, 0);
7303fd6e7d9SKevin Cernekee 		usleep_range(12000, 20000);
7313fd6e7d9SKevin Cernekee 	}
7323fd6e7d9SKevin Cernekee 
7333fd6e7d9SKevin Cernekee 	ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0);
7343fd6e7d9SKevin Cernekee 	if (ret)
7353fd6e7d9SKevin Cernekee 		return ret;
7363fd6e7d9SKevin Cernekee 
7373fd6e7d9SKevin Cernekee 
7383fd6e7d9SKevin Cernekee 	memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver));
7393fd6e7d9SKevin Cernekee 	priv->codec_driver.controls = priv->chip->controls;
7403fd6e7d9SKevin Cernekee 	priv->codec_driver.num_controls = priv->chip->num_controls;
7413fd6e7d9SKevin Cernekee 
7423fd6e7d9SKevin Cernekee 	if (priv->chip->vol_reg_size == 2) {
7433fd6e7d9SKevin Cernekee 		/*
7443fd6e7d9SKevin Cernekee 		 * The master volume defaults to 0x3ff (mute), but we ignore
7453fd6e7d9SKevin Cernekee 		 * (zero) the LSB because the hardware step size is 0.125 dB
7463fd6e7d9SKevin Cernekee 		 * and TLV_DB_SCALE_ITEM has a resolution of 0.01 dB.
7473fd6e7d9SKevin Cernekee 		 */
7483fd6e7d9SKevin Cernekee 		ret = regmap_update_bits(priv->regmap, TAS571X_MVOL_REG, 1, 0);
7493fd6e7d9SKevin Cernekee 		if (ret)
7503fd6e7d9SKevin Cernekee 			return ret;
7513fd6e7d9SKevin Cernekee 	}
7523fd6e7d9SKevin Cernekee 
7533fd6e7d9SKevin Cernekee 	regcache_cache_only(priv->regmap, true);
7543fd6e7d9SKevin Cernekee 	gpiod_set_value(priv->pdn_gpio, 1);
7553fd6e7d9SKevin Cernekee 
7563fd6e7d9SKevin Cernekee 	return snd_soc_register_codec(&client->dev, &priv->codec_driver,
7573fd6e7d9SKevin Cernekee 				      &tas571x_dai, 1);
7583fd6e7d9SKevin Cernekee }
7593fd6e7d9SKevin Cernekee 
7603fd6e7d9SKevin Cernekee static int tas571x_i2c_remove(struct i2c_client *client)
7613fd6e7d9SKevin Cernekee {
7623fd6e7d9SKevin Cernekee 	struct tas571x_private *priv = i2c_get_clientdata(client);
7633fd6e7d9SKevin Cernekee 
7643fd6e7d9SKevin Cernekee 	snd_soc_unregister_codec(&client->dev);
7653fd6e7d9SKevin Cernekee 	regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies);
7663fd6e7d9SKevin Cernekee 
7673fd6e7d9SKevin Cernekee 	return 0;
7683fd6e7d9SKevin Cernekee }
7693fd6e7d9SKevin Cernekee 
7703fd6e7d9SKevin Cernekee static const struct of_device_id tas571x_of_match[] = {
7713fd6e7d9SKevin Cernekee 	{ .compatible = "ti,tas5711", .data = &tas5711_chip, },
7723fd6e7d9SKevin Cernekee 	{ .compatible = "ti,tas5717", .data = &tas5717_chip, },
7733fd6e7d9SKevin Cernekee 	{ .compatible = "ti,tas5719", .data = &tas5717_chip, },
77423a282c4SPetr Kulhavy 	{ .compatible = "ti,tas5721", .data = &tas5721_chip, },
7753fd6e7d9SKevin Cernekee 	{ }
7763fd6e7d9SKevin Cernekee };
7773fd6e7d9SKevin Cernekee MODULE_DEVICE_TABLE(of, tas571x_of_match);
7783fd6e7d9SKevin Cernekee 
7793fd6e7d9SKevin Cernekee static const struct i2c_device_id tas571x_i2c_id[] = {
780630e413dSPetr Kulhavy 	{ "tas5711", (kernel_ulong_t) &tas5711_chip },
781630e413dSPetr Kulhavy 	{ "tas5717", (kernel_ulong_t) &tas5717_chip },
782630e413dSPetr Kulhavy 	{ "tas5719", (kernel_ulong_t) &tas5717_chip },
78323a282c4SPetr Kulhavy 	{ "tas5721", (kernel_ulong_t) &tas5721_chip },
7843fd6e7d9SKevin Cernekee 	{ }
7853fd6e7d9SKevin Cernekee };
7863fd6e7d9SKevin Cernekee MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id);
7873fd6e7d9SKevin Cernekee 
7883fd6e7d9SKevin Cernekee static struct i2c_driver tas571x_i2c_driver = {
7893fd6e7d9SKevin Cernekee 	.driver = {
7903fd6e7d9SKevin Cernekee 		.name = "tas571x",
7913fd6e7d9SKevin Cernekee 		.of_match_table = of_match_ptr(tas571x_of_match),
7923fd6e7d9SKevin Cernekee 	},
7933fd6e7d9SKevin Cernekee 	.probe = tas571x_i2c_probe,
7943fd6e7d9SKevin Cernekee 	.remove = tas571x_i2c_remove,
7953fd6e7d9SKevin Cernekee 	.id_table = tas571x_i2c_id,
7963fd6e7d9SKevin Cernekee };
7973fd6e7d9SKevin Cernekee module_i2c_driver(tas571x_i2c_driver);
7983fd6e7d9SKevin Cernekee 
7993fd6e7d9SKevin Cernekee MODULE_DESCRIPTION("ASoC TAS571x driver");
8003fd6e7d9SKevin Cernekee MODULE_AUTHOR("Kevin Cernekee <cernekee@chromium.org>");
8013fd6e7d9SKevin Cernekee MODULE_LICENSE("GPL");
802