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

ak4118.c (11637B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * ak4118.c  --  Asahi Kasei ALSA Soc Audio driver
      4 *
      5 * Copyright 2018 DEVIALET
      6 */
      7
      8#include <linux/i2c.h>
      9#include <linux/gpio/consumer.h>
     10#include <linux/module.h>
     11#include <linux/of_device.h>
     12#include <linux/of_gpio.h>
     13#include <linux/regmap.h>
     14#include <linux/slab.h>
     15
     16#include <sound/asoundef.h>
     17#include <sound/core.h>
     18#include <sound/initval.h>
     19#include <sound/soc.h>
     20
     21#define AK4118_REG_CLK_PWR_CTL		0x00
     22#define AK4118_REG_FORMAT_CTL		0x01
     23#define AK4118_REG_IO_CTL0		0x02
     24#define AK4118_REG_IO_CTL1		0x03
     25#define AK4118_REG_INT0_MASK		0x04
     26#define AK4118_REG_INT1_MASK		0x05
     27#define AK4118_REG_RCV_STATUS0		0x06
     28#define AK4118_REG_RCV_STATUS1		0x07
     29#define AK4118_REG_RXCHAN_STATUS0	0x08
     30#define AK4118_REG_RXCHAN_STATUS1	0x09
     31#define AK4118_REG_RXCHAN_STATUS2	0x0a
     32#define AK4118_REG_RXCHAN_STATUS3	0x0b
     33#define AK4118_REG_RXCHAN_STATUS4	0x0c
     34#define AK4118_REG_TXCHAN_STATUS0	0x0d
     35#define AK4118_REG_TXCHAN_STATUS1	0x0e
     36#define AK4118_REG_TXCHAN_STATUS2	0x0f
     37#define AK4118_REG_TXCHAN_STATUS3	0x10
     38#define AK4118_REG_TXCHAN_STATUS4	0x11
     39#define AK4118_REG_BURST_PREAMB_PC0	0x12
     40#define AK4118_REG_BURST_PREAMB_PC1	0x13
     41#define AK4118_REG_BURST_PREAMB_PD0	0x14
     42#define AK4118_REG_BURST_PREAMB_PD1	0x15
     43#define AK4118_REG_QSUB_CTL		0x16
     44#define AK4118_REG_QSUB_TRACK		0x17
     45#define AK4118_REG_QSUB_INDEX		0x18
     46#define AK4118_REG_QSUB_MIN		0x19
     47#define AK4118_REG_QSUB_SEC		0x1a
     48#define AK4118_REG_QSUB_FRAME		0x1b
     49#define AK4118_REG_QSUB_ZERO		0x1c
     50#define AK4118_REG_QSUB_ABS_MIN		0x1d
     51#define AK4118_REG_QSUB_ABS_SEC		0x1e
     52#define AK4118_REG_QSUB_ABS_FRAME	0x1f
     53#define AK4118_REG_GPE			0x20
     54#define AK4118_REG_GPDR			0x21
     55#define AK4118_REG_GPSCR		0x22
     56#define AK4118_REG_GPLR			0x23
     57#define AK4118_REG_DAT_MASK_DTS		0x24
     58#define AK4118_REG_RX_DETECT		0x25
     59#define AK4118_REG_STC_DAT_DETECT	0x26
     60#define AK4118_REG_RXCHAN_STATUS5	0x27
     61#define AK4118_REG_TXCHAN_STATUS5	0x28
     62#define AK4118_REG_MAX			0x29
     63
     64#define AK4118_REG_FORMAT_CTL_DIF0	(1 << 4)
     65#define AK4118_REG_FORMAT_CTL_DIF1	(1 << 5)
     66#define AK4118_REG_FORMAT_CTL_DIF2	(1 << 6)
     67
     68struct ak4118_priv {
     69	struct regmap *regmap;
     70	struct gpio_desc *reset;
     71	struct gpio_desc *irq;
     72	struct snd_soc_component *component;
     73};
     74
     75static const struct reg_default ak4118_reg_defaults[] = {
     76	{AK4118_REG_CLK_PWR_CTL,	0x43},
     77	{AK4118_REG_FORMAT_CTL,		0x6a},
     78	{AK4118_REG_IO_CTL0,		0x88},
     79	{AK4118_REG_IO_CTL1,		0x48},
     80	{AK4118_REG_INT0_MASK,		0xee},
     81	{AK4118_REG_INT1_MASK,		0xb5},
     82	{AK4118_REG_RCV_STATUS0,	0x00},
     83	{AK4118_REG_RCV_STATUS1,	0x10},
     84	{AK4118_REG_TXCHAN_STATUS0,	0x00},
     85	{AK4118_REG_TXCHAN_STATUS1,	0x00},
     86	{AK4118_REG_TXCHAN_STATUS2,	0x00},
     87	{AK4118_REG_TXCHAN_STATUS3,	0x00},
     88	{AK4118_REG_TXCHAN_STATUS4,	0x00},
     89	{AK4118_REG_GPE,		0x77},
     90	{AK4118_REG_GPDR,		0x00},
     91	{AK4118_REG_GPSCR,		0x00},
     92	{AK4118_REG_GPLR,		0x00},
     93	{AK4118_REG_DAT_MASK_DTS,	0x3f},
     94	{AK4118_REG_RX_DETECT,		0x00},
     95	{AK4118_REG_STC_DAT_DETECT,	0x00},
     96	{AK4118_REG_TXCHAN_STATUS5,	0x00},
     97};
     98
     99static const char * const ak4118_input_select_txt[] = {
    100	"RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
    101};
    102static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0,
    103			    ak4118_input_select_txt);
    104
    105static const struct snd_kcontrol_new ak4118_input_mux_controls =
    106	SOC_DAPM_ENUM("Input Select", ak4118_insel_enum);
    107
    108static const char * const ak4118_iec958_fs_txt[] = {
    109	"44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200",
    110	"8000", "96000", "64000", "176400", "192000",
    111};
    112
    113static const int ak4118_iec958_fs_val[] = {
    114	0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE,
    115};
    116
    117static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1,
    118				  0x4, 0x4, ak4118_iec958_fs_txt,
    119				  ak4118_iec958_fs_val);
    120
    121static struct snd_kcontrol_new ak4118_iec958_controls[] = {
    122	SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0),
    123	SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0),
    124	SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1),
    125	SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0),
    126	SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum),
    127};
    128
    129static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = {
    130	SND_SOC_DAPM_INPUT("INRX0"),
    131	SND_SOC_DAPM_INPUT("INRX1"),
    132	SND_SOC_DAPM_INPUT("INRX2"),
    133	SND_SOC_DAPM_INPUT("INRX3"),
    134	SND_SOC_DAPM_INPUT("INRX4"),
    135	SND_SOC_DAPM_INPUT("INRX5"),
    136	SND_SOC_DAPM_INPUT("INRX6"),
    137	SND_SOC_DAPM_INPUT("INRX7"),
    138	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
    139			 &ak4118_input_mux_controls),
    140};
    141
    142static const struct snd_soc_dapm_route ak4118_dapm_routes[] = {
    143	{"Input Mux", "RX0", "INRX0"},
    144	{"Input Mux", "RX1", "INRX1"},
    145	{"Input Mux", "RX2", "INRX2"},
    146	{"Input Mux", "RX3", "INRX3"},
    147	{"Input Mux", "RX4", "INRX4"},
    148	{"Input Mux", "RX5", "INRX5"},
    149	{"Input Mux", "RX6", "INRX6"},
    150	{"Input Mux", "RX7", "INRX7"},
    151};
    152
    153
    154static int ak4118_set_dai_fmt_provider(struct ak4118_priv *ak4118,
    155				       unsigned int format)
    156{
    157	int dif;
    158
    159	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
    160	case SND_SOC_DAIFMT_I2S:
    161		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2;
    162		break;
    163	case SND_SOC_DAIFMT_RIGHT_J:
    164		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1;
    165		break;
    166	case SND_SOC_DAIFMT_LEFT_J:
    167		dif = AK4118_REG_FORMAT_CTL_DIF2;
    168		break;
    169	default:
    170		return -ENOTSUPP;
    171	}
    172
    173	return dif;
    174}
    175
    176static int ak4118_set_dai_fmt_consumer(struct ak4118_priv *ak4118,
    177				       unsigned int format)
    178{
    179	int dif;
    180
    181	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
    182	case SND_SOC_DAIFMT_I2S:
    183		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 |
    184		      AK4118_REG_FORMAT_CTL_DIF2;
    185		break;
    186	case SND_SOC_DAIFMT_LEFT_J:
    187		dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2;
    188		break;
    189	default:
    190		return -ENOTSUPP;
    191	}
    192
    193	return dif;
    194}
    195
    196static int ak4118_set_dai_fmt(struct snd_soc_dai *dai,
    197			      unsigned int format)
    198{
    199	struct snd_soc_component *component = dai->component;
    200	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
    201	int dif;
    202	int ret = 0;
    203
    204	switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
    205	case SND_SOC_DAIFMT_CBP_CFP:
    206		dif = ak4118_set_dai_fmt_provider(ak4118, format);
    207		break;
    208	case SND_SOC_DAIFMT_CBC_CFC:
    209		dif = ak4118_set_dai_fmt_consumer(ak4118, format);
    210		break;
    211	default:
    212		ret = -ENOTSUPP;
    213		goto exit;
    214	}
    215
    216	/* format not supported */
    217	if (dif < 0) {
    218		ret = dif;
    219		goto exit;
    220	}
    221
    222	ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL,
    223				 AK4118_REG_FORMAT_CTL_DIF0 |
    224				 AK4118_REG_FORMAT_CTL_DIF1 |
    225				 AK4118_REG_FORMAT_CTL_DIF2, dif);
    226	if (ret < 0)
    227		goto exit;
    228
    229exit:
    230	return ret;
    231}
    232
    233static int ak4118_hw_params(struct snd_pcm_substream *substream,
    234			    struct snd_pcm_hw_params *params,
    235			    struct snd_soc_dai *dai)
    236{
    237	return 0;
    238}
    239
    240static const struct snd_soc_dai_ops ak4118_dai_ops = {
    241	.hw_params = ak4118_hw_params,
    242	.set_fmt   = ak4118_set_dai_fmt,
    243};
    244
    245static struct snd_soc_dai_driver ak4118_dai = {
    246	.name = "ak4118-hifi",
    247	.capture = {
    248		.stream_name = "Capture",
    249		.channels_min = 2,
    250		.channels_max = 2,
    251		.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
    252			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
    253			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
    254			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
    255		.formats = SNDRV_PCM_FMTBIT_S16_LE  |
    256			   SNDRV_PCM_FMTBIT_S24_3LE |
    257			   SNDRV_PCM_FMTBIT_S24_LE
    258	},
    259	.ops = &ak4118_dai_ops,
    260};
    261
    262static irqreturn_t ak4118_irq_handler(int irq, void *data)
    263{
    264	struct ak4118_priv *ak4118 = data;
    265	struct snd_soc_component *component = ak4118->component;
    266	struct snd_kcontrol_new *kctl_new;
    267	struct snd_kcontrol *kctl;
    268	struct snd_ctl_elem_id *id;
    269	unsigned int i;
    270
    271	if (!component)
    272		return IRQ_NONE;
    273
    274	for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
    275		kctl_new = &ak4118_iec958_controls[i];
    276		kctl = snd_soc_card_get_kcontrol(component->card,
    277						 kctl_new->name);
    278		if (!kctl)
    279			continue;
    280		id = &kctl->id;
    281		snd_ctl_notify(component->card->snd_card,
    282			       SNDRV_CTL_EVENT_MASK_VALUE, id);
    283	}
    284
    285	return IRQ_HANDLED;
    286}
    287
    288static int ak4118_probe(struct snd_soc_component *component)
    289{
    290	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
    291	int ret = 0;
    292
    293	ak4118->component = component;
    294
    295	/* release reset */
    296	gpiod_set_value(ak4118->reset, 0);
    297
    298	/* unmask all int1 sources */
    299	ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00);
    300	if (ret < 0) {
    301		dev_err(component->dev,
    302			"failed to write regmap 0x%x 0x%x: %d\n",
    303			AK4118_REG_INT1_MASK, 0x00, ret);
    304		return ret;
    305	}
    306
    307	/* rx detect enable on all channels */
    308	ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff);
    309	if (ret < 0) {
    310		dev_err(component->dev,
    311			"failed to write regmap 0x%x 0x%x: %d\n",
    312			AK4118_REG_RX_DETECT, 0xff, ret);
    313		return ret;
    314	}
    315
    316	ret = snd_soc_add_component_controls(component, ak4118_iec958_controls,
    317					 ARRAY_SIZE(ak4118_iec958_controls));
    318	if (ret) {
    319		dev_err(component->dev,
    320			"failed to add component kcontrols: %d\n", ret);
    321		return ret;
    322	}
    323
    324	return 0;
    325}
    326
    327static void ak4118_remove(struct snd_soc_component *component)
    328{
    329	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
    330
    331	/* hold reset */
    332	gpiod_set_value(ak4118->reset, 1);
    333}
    334
    335static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
    336	.probe			= ak4118_probe,
    337	.remove			= ak4118_remove,
    338	.dapm_widgets		= ak4118_dapm_widgets,
    339	.num_dapm_widgets	= ARRAY_SIZE(ak4118_dapm_widgets),
    340	.dapm_routes		= ak4118_dapm_routes,
    341	.num_dapm_routes	= ARRAY_SIZE(ak4118_dapm_routes),
    342	.idle_bias_on		= 1,
    343	.use_pmdown_time	= 1,
    344	.endianness		= 1,
    345	.non_legacy_dai_naming	= 1,
    346};
    347
    348static const struct regmap_config ak4118_regmap = {
    349	.reg_bits = 8,
    350	.val_bits = 8,
    351
    352	.reg_defaults = ak4118_reg_defaults,
    353	.num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults),
    354
    355	.cache_type = REGCACHE_NONE,
    356	.max_register = AK4118_REG_MAX - 1,
    357};
    358
    359static int ak4118_i2c_probe(struct i2c_client *i2c)
    360{
    361	struct ak4118_priv *ak4118;
    362	int ret;
    363
    364	ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv),
    365			      GFP_KERNEL);
    366	if (ak4118 == NULL)
    367		return -ENOMEM;
    368
    369	ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap);
    370	if (IS_ERR(ak4118->regmap))
    371		return PTR_ERR(ak4118->regmap);
    372
    373	i2c_set_clientdata(i2c, ak4118);
    374
    375	ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH);
    376	if (IS_ERR(ak4118->reset))
    377		return dev_err_probe(&i2c->dev, PTR_ERR(ak4118->reset),
    378				     "Failed to get reset\n");
    379
    380	ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN);
    381	if (IS_ERR(ak4118->irq))
    382		return dev_err_probe(&i2c->dev, PTR_ERR(ak4118->irq),
    383				     "Failed to get IRQ\n");
    384
    385	ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq),
    386					NULL, ak4118_irq_handler,
    387					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
    388					"ak4118-irq", ak4118);
    389	if (ret < 0) {
    390		dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret);
    391		return ret;
    392	}
    393
    394	return devm_snd_soc_register_component(&i2c->dev,
    395				&soc_component_drv_ak4118, &ak4118_dai, 1);
    396}
    397
    398#ifdef CONFIG_OF
    399static const struct of_device_id ak4118_of_match[] = {
    400	{ .compatible = "asahi-kasei,ak4118", },
    401	{}
    402};
    403MODULE_DEVICE_TABLE(of, ak4118_of_match);
    404#endif
    405
    406static const struct i2c_device_id ak4118_id_table[] = {
    407	{ "ak4118", 0 },
    408	{}
    409};
    410MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
    411
    412static struct i2c_driver ak4118_i2c_driver = {
    413	.driver  = {
    414		.name = "ak4118",
    415		.of_match_table = of_match_ptr(ak4118_of_match),
    416	},
    417	.id_table = ak4118_id_table,
    418	.probe_new = ak4118_i2c_probe,
    419};
    420
    421module_i2c_driver(ak4118_i2c_driver);
    422
    423MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver");
    424MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>");
    425MODULE_LICENSE("GPL");