summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/adau7002.c
blob: 401bafabc8eb4bf1b555e463d25d305bbafac1a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-License-Identifier: GPL-2.0-only
/*
 * ADAU7002 Stereo PDM-to-I2S/TDM converter driver
 *
 * Copyright 2014-2016 Analog Devices
 *  Author: Lars-Peter Clausen <lars@metafoo.de>
 */

#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>

#include <sound/soc.h>

struct adau7002_priv {
	int wakeup_delay;
};

static int adau7002_aif_event(struct snd_soc_dapm_widget *w,
			      struct snd_kcontrol *kcontrol, int event)
{
	struct snd_soc_component *component =
			snd_soc_dapm_to_component(w->dapm);
	struct adau7002_priv *adau7002 =
			snd_soc_component_get_drvdata(component);

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		if (adau7002->wakeup_delay)
			msleep(adau7002->wakeup_delay);
		break;
	}

	return 0;
}

static int adau7002_component_probe(struct snd_soc_component *component)
{
	struct adau7002_priv *adau7002;

	adau7002 = devm_kzalloc(component->dev, sizeof(*adau7002),
				GFP_KERNEL);
	if (!adau7002)
		return -ENOMEM;

	device_property_read_u32(component->dev, "wakeup-delay-ms",
				 &adau7002->wakeup_delay);

	snd_soc_component_set_drvdata(component, adau7002);

	return 0;
}

static const struct snd_soc_dapm_widget adau7002_widgets[] = {
	SND_SOC_DAPM_AIF_OUT_E("ADAU AIF", "Capture", 0,
			       SND_SOC_NOPM, 0, 0, adau7002_aif_event,
			       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
	SND_SOC_DAPM_INPUT("PDM_DAT"),
	SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0),
};

static const struct snd_soc_dapm_route adau7002_routes[] = {
	{ "ADAU AIF", NULL, "PDM_DAT"},
	{ "Capture", NULL, "PDM_DAT" },
	{ "Capture", NULL, "IOVDD" },
};

static struct snd_soc_dai_driver adau7002_dai = {
	.name = "adau7002-hifi",
	.capture = {
		.stream_name = "Capture",
		.channels_min = 2,
		.channels_max = 2,
		.rates = SNDRV_PCM_RATE_8000_96000,
		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |
			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |
			SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
		.sig_bits = 20,
	},
};

static const struct snd_soc_component_driver adau7002_component_driver = {
	.probe			= adau7002_component_probe,
	.dapm_widgets		= adau7002_widgets,
	.num_dapm_widgets	= ARRAY_SIZE(adau7002_widgets),
	.dapm_routes		= adau7002_routes,
	.num_dapm_routes	= ARRAY_SIZE(adau7002_routes),
	.idle_bias_on		= 1,
	.use_pmdown_time	= 1,
	.endianness		= 1,
};

static int adau7002_probe(struct platform_device *pdev)
{
	return devm_snd_soc_register_component(&pdev->dev,
			&adau7002_component_driver,
			&adau7002_dai, 1);
}

static int adau7002_remove(struct platform_device *pdev)
{
	return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id adau7002_dt_ids[] = {
	{ .compatible = "adi,adau7002", },
	{ }
};
MODULE_DEVICE_TABLE(of, adau7002_dt_ids);
#endif

#ifdef CONFIG_ACPI
static const struct acpi_device_id adau7002_acpi_match[] = {
	{ "ADAU7002", 0 },
	{},
};
MODULE_DEVICE_TABLE(acpi, adau7002_acpi_match);
#endif

static struct platform_driver adau7002_driver = {
	.driver = {
		.name = "adau7002",
		.of_match_table	= of_match_ptr(adau7002_dt_ids),
		.acpi_match_table = ACPI_PTR(adau7002_acpi_match),
	},
	.probe = adau7002_probe,
	.remove = adau7002_remove,
};
module_platform_driver(adau7002_driver);

MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("ADAU7002 Stereo PDM-to-I2S/TDM Converter driver");
MODULE_LICENSE("GPL v2");