cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tas5720.c (21532B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * tas5720.c - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier
      4 *
      5 * Copyright (C)2015-2016 Texas Instruments Incorporated -  https://www.ti.com
      6 *
      7 * Author: Andreas Dannenberg <dannenberg@ti.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/errno.h>
     12#include <linux/device.h>
     13#include <linux/i2c.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/regmap.h>
     16#include <linux/slab.h>
     17#include <linux/regulator/consumer.h>
     18#include <linux/delay.h>
     19
     20#include <sound/pcm.h>
     21#include <sound/pcm_params.h>
     22#include <sound/soc.h>
     23#include <sound/soc-dapm.h>
     24#include <sound/tlv.h>
     25
     26#include "tas5720.h"
     27
     28/* Define how often to check (and clear) the fault status register (in ms) */
     29#define TAS5720_FAULT_CHECK_INTERVAL		200
     30
     31enum tas572x_type {
     32	TAS5720,
     33	TAS5722,
     34};
     35
     36static const char * const tas5720_supply_names[] = {
     37	"dvdd",		/* Digital power supply. Connect to 3.3-V supply. */
     38	"pvdd",		/* Class-D amp and analog power supply (connected). */
     39};
     40
     41#define TAS5720_NUM_SUPPLIES	ARRAY_SIZE(tas5720_supply_names)
     42
     43struct tas5720_data {
     44	struct snd_soc_component *component;
     45	struct regmap *regmap;
     46	struct i2c_client *tas5720_client;
     47	enum tas572x_type devtype;
     48	struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES];
     49	struct delayed_work fault_check_work;
     50	unsigned int last_fault;
     51};
     52
     53static int tas5720_hw_params(struct snd_pcm_substream *substream,
     54			     struct snd_pcm_hw_params *params,
     55			     struct snd_soc_dai *dai)
     56{
     57	struct snd_soc_component *component = dai->component;
     58	unsigned int rate = params_rate(params);
     59	bool ssz_ds;
     60	int ret;
     61
     62	switch (rate) {
     63	case 44100:
     64	case 48000:
     65		ssz_ds = false;
     66		break;
     67	case 88200:
     68	case 96000:
     69		ssz_ds = true;
     70		break;
     71	default:
     72		dev_err(component->dev, "unsupported sample rate: %u\n", rate);
     73		return -EINVAL;
     74	}
     75
     76	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
     77				  TAS5720_SSZ_DS, ssz_ds);
     78	if (ret < 0) {
     79		dev_err(component->dev, "error setting sample rate: %d\n", ret);
     80		return ret;
     81	}
     82
     83	return 0;
     84}
     85
     86static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
     87{
     88	struct snd_soc_component *component = dai->component;
     89	u8 serial_format;
     90	int ret;
     91
     92	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
     93		dev_vdbg(component->dev, "DAI Format master is not found\n");
     94		return -EINVAL;
     95	}
     96
     97	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
     98		       SND_SOC_DAIFMT_INV_MASK)) {
     99	case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
    100		/* 1st data bit occur one BCLK cycle after the frame sync */
    101		serial_format = TAS5720_SAIF_I2S;
    102		break;
    103	case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF):
    104		/*
    105		 * Note that although the TAS5720 does not have a dedicated DSP
    106		 * mode it doesn't care about the LRCLK duty cycle during TDM
    107		 * operation. Therefore we can use the device's I2S mode with
    108		 * its delaying of the 1st data bit to receive DSP_A formatted
    109		 * data. See device datasheet for additional details.
    110		 */
    111		serial_format = TAS5720_SAIF_I2S;
    112		break;
    113	case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF):
    114		/*
    115		 * Similar to DSP_A, we can use the fact that the TAS5720 does
    116		 * not care about the LRCLK duty cycle during TDM to receive
    117		 * DSP_B formatted data in LEFTJ mode (no delaying of the 1st
    118		 * data bit).
    119		 */
    120		serial_format = TAS5720_SAIF_LEFTJ;
    121		break;
    122	case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
    123		/* No delay after the frame sync */
    124		serial_format = TAS5720_SAIF_LEFTJ;
    125		break;
    126	default:
    127		dev_vdbg(component->dev, "DAI Format is not found\n");
    128		return -EINVAL;
    129	}
    130
    131	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
    132				  TAS5720_SAIF_FORMAT_MASK,
    133				  serial_format);
    134	if (ret < 0) {
    135		dev_err(component->dev, "error setting SAIF format: %d\n", ret);
    136		return ret;
    137	}
    138
    139	return 0;
    140}
    141
    142static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
    143				    unsigned int tx_mask, unsigned int rx_mask,
    144				    int slots, int slot_width)
    145{
    146	struct snd_soc_component *component = dai->component;
    147	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
    148	unsigned int first_slot;
    149	int ret;
    150
    151	if (!tx_mask) {
    152		dev_err(component->dev, "tx masks must not be 0\n");
    153		return -EINVAL;
    154	}
    155
    156	/*
    157	 * Determine the first slot that is being requested. We will only
    158	 * use the first slot that is found since the TAS5720 is a mono
    159	 * amplifier.
    160	 */
    161	first_slot = __ffs(tx_mask);
    162
    163	if (first_slot > 7) {
    164		dev_err(component->dev, "slot selection out of bounds (%u)\n",
    165			first_slot);
    166		return -EINVAL;
    167	}
    168
    169	/* Enable manual TDM slot selection (instead of I2C ID based) */
    170	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
    171				  TAS5720_TDM_CFG_SRC, TAS5720_TDM_CFG_SRC);
    172	if (ret < 0)
    173		goto error_snd_soc_component_update_bits;
    174
    175	/* Configure the TDM slot to process audio from */
    176	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
    177				  TAS5720_TDM_SLOT_SEL_MASK, first_slot);
    178	if (ret < 0)
    179		goto error_snd_soc_component_update_bits;
    180
    181	/* Configure TDM slot width. This is only applicable to TAS5722. */
    182	switch (tas5720->devtype) {
    183	case TAS5722:
    184		ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
    185						    TAS5722_TDM_SLOT_16B,
    186						    slot_width == 16 ?
    187						    TAS5722_TDM_SLOT_16B : 0);
    188		if (ret < 0)
    189			goto error_snd_soc_component_update_bits;
    190		break;
    191	default:
    192		break;
    193	}
    194
    195	return 0;
    196
    197error_snd_soc_component_update_bits:
    198	dev_err(component->dev, "error configuring TDM mode: %d\n", ret);
    199	return ret;
    200}
    201
    202static int tas5720_mute(struct snd_soc_dai *dai, int mute, int direction)
    203{
    204	struct snd_soc_component *component = dai->component;
    205	int ret;
    206
    207	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
    208				  TAS5720_MUTE, mute ? TAS5720_MUTE : 0);
    209	if (ret < 0) {
    210		dev_err(component->dev, "error (un-)muting device: %d\n", ret);
    211		return ret;
    212	}
    213
    214	return 0;
    215}
    216
    217static void tas5720_fault_check_work(struct work_struct *work)
    218{
    219	struct tas5720_data *tas5720 = container_of(work, struct tas5720_data,
    220			fault_check_work.work);
    221	struct device *dev = tas5720->component->dev;
    222	unsigned int curr_fault;
    223	int ret;
    224
    225	ret = regmap_read(tas5720->regmap, TAS5720_FAULT_REG, &curr_fault);
    226	if (ret < 0) {
    227		dev_err(dev, "failed to read FAULT register: %d\n", ret);
    228		goto out;
    229	}
    230
    231	/* Check/handle all errors except SAIF clock errors */
    232	curr_fault &= TAS5720_OCE | TAS5720_DCE | TAS5720_OTE;
    233
    234	/*
    235	 * Only flag errors once for a given occurrence. This is needed as
    236	 * the TAS5720 will take time clearing the fault condition internally
    237	 * during which we don't want to bombard the system with the same
    238	 * error message over and over.
    239	 */
    240	if ((curr_fault & TAS5720_OCE) && !(tas5720->last_fault & TAS5720_OCE))
    241		dev_crit(dev, "experienced an over current hardware fault\n");
    242
    243	if ((curr_fault & TAS5720_DCE) && !(tas5720->last_fault & TAS5720_DCE))
    244		dev_crit(dev, "experienced a DC detection fault\n");
    245
    246	if ((curr_fault & TAS5720_OTE) && !(tas5720->last_fault & TAS5720_OTE))
    247		dev_crit(dev, "experienced an over temperature fault\n");
    248
    249	/* Store current fault value so we can detect any changes next time */
    250	tas5720->last_fault = curr_fault;
    251
    252	if (!curr_fault)
    253		goto out;
    254
    255	/*
    256	 * Periodically toggle SDZ (shutdown bit) H->L->H to clear any latching
    257	 * faults as long as a fault condition persists. Always going through
    258	 * the full sequence no matter the first return value to minimizes
    259	 * chances for the device to end up in shutdown mode.
    260	 */
    261	ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG,
    262				TAS5720_SDZ, 0);
    263	if (ret < 0)
    264		dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret);
    265
    266	ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG,
    267				TAS5720_SDZ, TAS5720_SDZ);
    268	if (ret < 0)
    269		dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret);
    270
    271out:
    272	/* Schedule the next fault check at the specified interval */
    273	schedule_delayed_work(&tas5720->fault_check_work,
    274			      msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL));
    275}
    276
    277static int tas5720_codec_probe(struct snd_soc_component *component)
    278{
    279	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
    280	unsigned int device_id, expected_device_id;
    281	int ret;
    282
    283	tas5720->component = component;
    284
    285	ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies),
    286				    tas5720->supplies);
    287	if (ret != 0) {
    288		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
    289		return ret;
    290	}
    291
    292	/*
    293	 * Take a liberal approach to checking the device ID to allow the
    294	 * driver to be used even if the device ID does not match, however
    295	 * issue a warning if there is a mismatch.
    296	 */
    297	ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id);
    298	if (ret < 0) {
    299		dev_err(component->dev, "failed to read device ID register: %d\n",
    300			ret);
    301		goto probe_fail;
    302	}
    303
    304	switch (tas5720->devtype) {
    305	case TAS5720:
    306		expected_device_id = TAS5720_DEVICE_ID;
    307		break;
    308	case TAS5722:
    309		expected_device_id = TAS5722_DEVICE_ID;
    310		break;
    311	default:
    312		dev_err(component->dev, "unexpected private driver data\n");
    313		return -EINVAL;
    314	}
    315
    316	if (device_id != expected_device_id)
    317		dev_warn(component->dev, "wrong device ID. expected: %u read: %u\n",
    318			 expected_device_id, device_id);
    319
    320	/* Set device to mute */
    321	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
    322				  TAS5720_MUTE, TAS5720_MUTE);
    323	if (ret < 0)
    324		goto error_snd_soc_component_update_bits;
    325
    326	/*
    327	 * Enter shutdown mode - our default when not playing audio - to
    328	 * minimize current consumption. On the TAS5720 there is no real down
    329	 * side doing so as all device registers are preserved and the wakeup
    330	 * of the codec is rather quick which we do using a dapm widget.
    331	 */
    332	ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
    333				  TAS5720_SDZ, 0);
    334	if (ret < 0)
    335		goto error_snd_soc_component_update_bits;
    336
    337	INIT_DELAYED_WORK(&tas5720->fault_check_work, tas5720_fault_check_work);
    338
    339	return 0;
    340
    341error_snd_soc_component_update_bits:
    342	dev_err(component->dev, "error configuring device registers: %d\n", ret);
    343
    344probe_fail:
    345	regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
    346			       tas5720->supplies);
    347	return ret;
    348}
    349
    350static void tas5720_codec_remove(struct snd_soc_component *component)
    351{
    352	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
    353	int ret;
    354
    355	cancel_delayed_work_sync(&tas5720->fault_check_work);
    356
    357	ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
    358				     tas5720->supplies);
    359	if (ret < 0)
    360		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
    361};
    362
    363static int tas5720_dac_event(struct snd_soc_dapm_widget *w,
    364			     struct snd_kcontrol *kcontrol, int event)
    365{
    366	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
    367	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
    368	int ret;
    369
    370	if (event & SND_SOC_DAPM_POST_PMU) {
    371		/* Take TAS5720 out of shutdown mode */
    372		ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
    373					  TAS5720_SDZ, TAS5720_SDZ);
    374		if (ret < 0) {
    375			dev_err(component->dev, "error waking component: %d\n", ret);
    376			return ret;
    377		}
    378
    379		/*
    380		 * Observe codec shutdown-to-active time. The datasheet only
    381		 * lists a nominal value however just use-it as-is without
    382		 * additional padding to minimize the delay introduced in
    383		 * starting to play audio (actually there is other setup done
    384		 * by the ASoC framework that will provide additional delays,
    385		 * so we should always be safe).
    386		 */
    387		msleep(25);
    388
    389		/* Turn on TAS5720 periodic fault checking/handling */
    390		tas5720->last_fault = 0;
    391		schedule_delayed_work(&tas5720->fault_check_work,
    392				msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL));
    393	} else if (event & SND_SOC_DAPM_PRE_PMD) {
    394		/* Disable TAS5720 periodic fault checking/handling */
    395		cancel_delayed_work_sync(&tas5720->fault_check_work);
    396
    397		/* Place TAS5720 in shutdown mode to minimize current draw */
    398		ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
    399					  TAS5720_SDZ, 0);
    400		if (ret < 0) {
    401			dev_err(component->dev, "error shutting down component: %d\n",
    402				ret);
    403			return ret;
    404		}
    405	}
    406
    407	return 0;
    408}
    409
    410#ifdef CONFIG_PM
    411static int tas5720_suspend(struct snd_soc_component *component)
    412{
    413	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
    414	int ret;
    415
    416	regcache_cache_only(tas5720->regmap, true);
    417	regcache_mark_dirty(tas5720->regmap);
    418
    419	ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
    420				     tas5720->supplies);
    421	if (ret < 0)
    422		dev_err(component->dev, "failed to disable supplies: %d\n", ret);
    423
    424	return ret;
    425}
    426
    427static int tas5720_resume(struct snd_soc_component *component)
    428{
    429	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
    430	int ret;
    431
    432	ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies),
    433				    tas5720->supplies);
    434	if (ret < 0) {
    435		dev_err(component->dev, "failed to enable supplies: %d\n", ret);
    436		return ret;
    437	}
    438
    439	regcache_cache_only(tas5720->regmap, false);
    440
    441	ret = regcache_sync(tas5720->regmap);
    442	if (ret < 0) {
    443		dev_err(component->dev, "failed to sync regcache: %d\n", ret);
    444		return ret;
    445	}
    446
    447	return 0;
    448}
    449#else
    450#define tas5720_suspend NULL
    451#define tas5720_resume NULL
    452#endif
    453
    454static bool tas5720_is_volatile_reg(struct device *dev, unsigned int reg)
    455{
    456	switch (reg) {
    457	case TAS5720_DEVICE_ID_REG:
    458	case TAS5720_FAULT_REG:
    459		return true;
    460	default:
    461		return false;
    462	}
    463}
    464
    465static const struct regmap_config tas5720_regmap_config = {
    466	.reg_bits = 8,
    467	.val_bits = 8,
    468
    469	.max_register = TAS5720_MAX_REG,
    470	.cache_type = REGCACHE_RBTREE,
    471	.volatile_reg = tas5720_is_volatile_reg,
    472};
    473
    474static const struct regmap_config tas5722_regmap_config = {
    475	.reg_bits = 8,
    476	.val_bits = 8,
    477
    478	.max_register = TAS5722_MAX_REG,
    479	.cache_type = REGCACHE_RBTREE,
    480	.volatile_reg = tas5720_is_volatile_reg,
    481};
    482
    483/*
    484 * DAC analog gain. There are four discrete values to select from, ranging
    485 * from 19.2 dB to 26.3dB.
    486 */
    487static const DECLARE_TLV_DB_RANGE(dac_analog_tlv,
    488	0x0, 0x0, TLV_DB_SCALE_ITEM(1920, 0, 0),
    489	0x1, 0x1, TLV_DB_SCALE_ITEM(2070, 0, 0),
    490	0x2, 0x2, TLV_DB_SCALE_ITEM(2350, 0, 0),
    491	0x3, 0x3, TLV_DB_SCALE_ITEM(2630, 0, 0),
    492);
    493
    494/*
    495 * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps
    496 * depending on the device. Note that setting the gain below -100 dB
    497 * (register value <0x7) is effectively a MUTE as per device datasheet.
    498 *
    499 * Note that for the TAS5722 the digital volume controls are actually split
    500 * over two registers, so we need custom getters/setters for access.
    501 */
    502static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0);
    503static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0);
    504
    505static int tas5722_volume_get(struct snd_kcontrol *kcontrol,
    506			      struct snd_ctl_elem_value *ucontrol)
    507{
    508	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    509	unsigned int val;
    510
    511	val = snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG);
    512	ucontrol->value.integer.value[0] = val << 1;
    513
    514	val = snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG);
    515	ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB;
    516
    517	return 0;
    518}
    519
    520static int tas5722_volume_set(struct snd_kcontrol *kcontrol,
    521			      struct snd_ctl_elem_value *ucontrol)
    522{
    523	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
    524	unsigned int sel = ucontrol->value.integer.value[0];
    525
    526	snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1);
    527	snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
    528				      TAS5722_VOL_CONTROL_LSB, sel);
    529
    530	return 0;
    531}
    532
    533static const struct snd_kcontrol_new tas5720_snd_controls[] = {
    534	SOC_SINGLE_TLV("Speaker Driver Playback Volume",
    535		       TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, tas5720_dac_tlv),
    536	SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
    537		       TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
    538};
    539
    540static const struct snd_kcontrol_new tas5722_snd_controls[] = {
    541	SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume",
    542			   0, 0, 511, 0,
    543			   tas5722_volume_get, tas5722_volume_set,
    544			   tas5722_dac_tlv),
    545	SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
    546		       TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
    547};
    548
    549static const struct snd_soc_dapm_widget tas5720_dapm_widgets[] = {
    550	SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
    551	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas5720_dac_event,
    552			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
    553	SND_SOC_DAPM_OUTPUT("OUT")
    554};
    555
    556static const struct snd_soc_dapm_route tas5720_audio_map[] = {
    557	{ "DAC", NULL, "DAC IN" },
    558	{ "OUT", NULL, "DAC" },
    559};
    560
    561static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
    562	.probe			= tas5720_codec_probe,
    563	.remove			= tas5720_codec_remove,
    564	.suspend		= tas5720_suspend,
    565	.resume			= tas5720_resume,
    566	.controls		= tas5720_snd_controls,
    567	.num_controls		= ARRAY_SIZE(tas5720_snd_controls),
    568	.dapm_widgets		= tas5720_dapm_widgets,
    569	.num_dapm_widgets	= ARRAY_SIZE(tas5720_dapm_widgets),
    570	.dapm_routes		= tas5720_audio_map,
    571	.num_dapm_routes	= ARRAY_SIZE(tas5720_audio_map),
    572	.idle_bias_on		= 1,
    573	.use_pmdown_time	= 1,
    574	.endianness		= 1,
    575	.non_legacy_dai_naming	= 1,
    576};
    577
    578static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
    579	.probe = tas5720_codec_probe,
    580	.remove = tas5720_codec_remove,
    581	.suspend = tas5720_suspend,
    582	.resume = tas5720_resume,
    583	.controls = tas5722_snd_controls,
    584	.num_controls = ARRAY_SIZE(tas5722_snd_controls),
    585	.dapm_widgets = tas5720_dapm_widgets,
    586	.num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets),
    587	.dapm_routes = tas5720_audio_map,
    588	.num_dapm_routes = ARRAY_SIZE(tas5720_audio_map),
    589	.idle_bias_on		= 1,
    590	.use_pmdown_time	= 1,
    591	.endianness		= 1,
    592	.non_legacy_dai_naming	= 1,
    593};
    594
    595/* PCM rates supported by the TAS5720 driver */
    596#define TAS5720_RATES	(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
    597			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
    598
    599/* Formats supported by TAS5720 driver */
    600#define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\
    601			 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
    602
    603static const struct snd_soc_dai_ops tas5720_speaker_dai_ops = {
    604	.hw_params	= tas5720_hw_params,
    605	.set_fmt	= tas5720_set_dai_fmt,
    606	.set_tdm_slot	= tas5720_set_dai_tdm_slot,
    607	.mute_stream	= tas5720_mute,
    608	.no_capture_mute = 1,
    609};
    610
    611/*
    612 * TAS5720 DAI structure
    613 *
    614 * Note that were are advertising .playback.channels_max = 2 despite this being
    615 * a mono amplifier. The reason for that is that some serial ports such as TI's
    616 * McASP module have a minimum number of channels (2) that they can output.
    617 * Advertising more channels than we have will allow us to interface with such
    618 * a serial port without really any negative side effects as the TAS5720 will
    619 * simply ignore any extra channel(s) asides from the one channel that is
    620 * configured to be played back.
    621 */
    622static struct snd_soc_dai_driver tas5720_dai[] = {
    623	{
    624		.name = "tas5720-amplifier",
    625		.playback = {
    626			.stream_name = "Playback",
    627			.channels_min = 1,
    628			.channels_max = 2,
    629			.rates = TAS5720_RATES,
    630			.formats = TAS5720_FORMATS,
    631		},
    632		.ops = &tas5720_speaker_dai_ops,
    633	},
    634};
    635
    636static const struct i2c_device_id tas5720_id[] = {
    637	{ "tas5720", TAS5720 },
    638	{ "tas5722", TAS5722 },
    639	{ }
    640};
    641MODULE_DEVICE_TABLE(i2c, tas5720_id);
    642
    643static int tas5720_probe(struct i2c_client *client)
    644{
    645	struct device *dev = &client->dev;
    646	struct tas5720_data *data;
    647	const struct regmap_config *regmap_config;
    648	const struct i2c_device_id *id;
    649	int ret;
    650	int i;
    651
    652	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
    653	if (!data)
    654		return -ENOMEM;
    655
    656	id = i2c_match_id(tas5720_id, client);
    657	data->tas5720_client = client;
    658	data->devtype = id->driver_data;
    659
    660	switch (id->driver_data) {
    661	case TAS5720:
    662		regmap_config = &tas5720_regmap_config;
    663		break;
    664	case TAS5722:
    665		regmap_config = &tas5722_regmap_config;
    666		break;
    667	default:
    668		dev_err(dev, "unexpected private driver data\n");
    669		return -EINVAL;
    670	}
    671	data->regmap = devm_regmap_init_i2c(client, regmap_config);
    672	if (IS_ERR(data->regmap)) {
    673		ret = PTR_ERR(data->regmap);
    674		dev_err(dev, "failed to allocate register map: %d\n", ret);
    675		return ret;
    676	}
    677
    678	for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
    679		data->supplies[i].supply = tas5720_supply_names[i];
    680
    681	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
    682				      data->supplies);
    683	if (ret != 0) {
    684		dev_err(dev, "failed to request supplies: %d\n", ret);
    685		return ret;
    686	}
    687
    688	dev_set_drvdata(dev, data);
    689
    690	switch (id->driver_data) {
    691	case TAS5720:
    692		ret = devm_snd_soc_register_component(&client->dev,
    693					&soc_component_dev_tas5720,
    694					tas5720_dai,
    695					ARRAY_SIZE(tas5720_dai));
    696		break;
    697	case TAS5722:
    698		ret = devm_snd_soc_register_component(&client->dev,
    699					&soc_component_dev_tas5722,
    700					tas5720_dai,
    701					ARRAY_SIZE(tas5720_dai));
    702		break;
    703	default:
    704		dev_err(dev, "unexpected private driver data\n");
    705		return -EINVAL;
    706	}
    707	if (ret < 0) {
    708		dev_err(dev, "failed to register component: %d\n", ret);
    709		return ret;
    710	}
    711
    712	return 0;
    713}
    714
    715#if IS_ENABLED(CONFIG_OF)
    716static const struct of_device_id tas5720_of_match[] = {
    717	{ .compatible = "ti,tas5720", },
    718	{ .compatible = "ti,tas5722", },
    719	{ },
    720};
    721MODULE_DEVICE_TABLE(of, tas5720_of_match);
    722#endif
    723
    724static struct i2c_driver tas5720_i2c_driver = {
    725	.driver = {
    726		.name = "tas5720",
    727		.of_match_table = of_match_ptr(tas5720_of_match),
    728	},
    729	.probe_new = tas5720_probe,
    730	.id_table = tas5720_id,
    731};
    732
    733module_i2c_driver(tas5720_i2c_driver);
    734
    735MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
    736MODULE_DESCRIPTION("TAS5720 Audio amplifier driver");
    737MODULE_LICENSE("GPL");