Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/img/pistachio-internal-dac.c
26437 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Pistachio internal dac driver
4
*
5
* Copyright (C) 2015 Imagination Technologies Ltd.
6
*
7
* Author: Damien Horsley <[email protected]>
8
*/
9
10
#include <linux/clk.h>
11
#include <linux/delay.h>
12
#include <linux/mfd/syscon.h>
13
#include <linux/module.h>
14
#include <linux/pm_runtime.h>
15
#include <linux/regmap.h>
16
#include <linux/regulator/consumer.h>
17
18
#include <sound/pcm_params.h>
19
#include <sound/soc.h>
20
21
#define PISTACHIO_INTERNAL_DAC_CTRL 0x40
22
#define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK 0x2
23
#define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK 0x1
24
25
#define PISTACHIO_INTERNAL_DAC_SRST 0x44
26
#define PISTACHIO_INTERNAL_DAC_SRST_MASK 0x1
27
28
#define PISTACHIO_INTERNAL_DAC_GTI_CTRL 0x48
29
#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT 0
30
#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK 0xFFF
31
#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK 0x1000
32
#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT 13
33
#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK 0x1FE000
34
35
#define PISTACHIO_INTERNAL_DAC_PWR 0x1
36
#define PISTACHIO_INTERNAL_DAC_PWR_MASK 0x1
37
38
#define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
39
SNDRV_PCM_FMTBIT_S32_LE)
40
41
/* codec private data */
42
struct pistachio_internal_dac {
43
struct regmap *regmap;
44
struct regulator *supply;
45
bool mute;
46
};
47
48
static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = {
49
SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1)
50
};
51
52
static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = {
53
SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
54
SND_SOC_DAPM_OUTPUT("AOUTL"),
55
SND_SOC_DAPM_OUTPUT("AOUTR"),
56
};
57
58
static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = {
59
{ "AOUTL", NULL, "DAC" },
60
{ "AOUTR", NULL, "DAC" },
61
};
62
63
static void pistachio_internal_dac_reg_writel(struct regmap *top_regs,
64
u32 val, u32 reg)
65
{
66
regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
67
PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK,
68
reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT);
69
70
regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
71
PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK,
72
val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT);
73
74
regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
75
PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK,
76
PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK);
77
78
regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
79
PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0);
80
}
81
82
static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac)
83
{
84
regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
85
PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK,
86
PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK);
87
88
pistachio_internal_dac_reg_writel(dac->regmap, 0,
89
PISTACHIO_INTERNAL_DAC_PWR);
90
}
91
92
static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac)
93
{
94
regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
95
PISTACHIO_INTERNAL_DAC_SRST_MASK,
96
PISTACHIO_INTERNAL_DAC_SRST_MASK);
97
98
regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
99
PISTACHIO_INTERNAL_DAC_SRST_MASK, 0);
100
101
pistachio_internal_dac_reg_writel(dac->regmap,
102
PISTACHIO_INTERNAL_DAC_PWR_MASK,
103
PISTACHIO_INTERNAL_DAC_PWR);
104
105
regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
106
PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0);
107
}
108
109
static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = {
110
{
111
.name = "pistachio_internal_dac",
112
.playback = {
113
.stream_name = "Playback",
114
.channels_min = 2,
115
.channels_max = 2,
116
.rates = SNDRV_PCM_RATE_8000_48000,
117
.formats = PISTACHIO_INTERNAL_DAC_FORMATS,
118
}
119
},
120
};
121
122
static int pistachio_internal_dac_codec_probe(struct snd_soc_component *component)
123
{
124
struct pistachio_internal_dac *dac = snd_soc_component_get_drvdata(component);
125
126
snd_soc_component_init_regmap(component, dac->regmap);
127
128
return 0;
129
}
130
131
static const struct snd_soc_component_driver pistachio_internal_dac_driver = {
132
.probe = pistachio_internal_dac_codec_probe,
133
.controls = pistachio_internal_dac_snd_controls,
134
.num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls),
135
.dapm_widgets = pistachio_internal_dac_widgets,
136
.num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets),
137
.dapm_routes = pistachio_internal_dac_routes,
138
.num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes),
139
.use_pmdown_time = 1,
140
.endianness = 1,
141
};
142
143
static int pistachio_internal_dac_probe(struct platform_device *pdev)
144
{
145
struct pistachio_internal_dac *dac;
146
int ret, voltage;
147
struct device *dev = &pdev->dev;
148
u32 reg;
149
150
dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL);
151
152
if (!dac)
153
return -ENOMEM;
154
155
platform_set_drvdata(pdev, dac);
156
157
dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
158
"img,cr-top");
159
if (IS_ERR(dac->regmap))
160
return PTR_ERR(dac->regmap);
161
162
dac->supply = devm_regulator_get(dev, "VDD");
163
if (IS_ERR(dac->supply))
164
return dev_err_probe(dev, PTR_ERR(dac->supply),
165
"failed to acquire supply 'VDD-supply'\n");
166
167
ret = regulator_enable(dac->supply);
168
if (ret) {
169
dev_err(dev, "failed to enable supply: %d\n", ret);
170
return ret;
171
}
172
173
voltage = regulator_get_voltage(dac->supply);
174
175
switch (voltage) {
176
case 1800000:
177
reg = 0;
178
break;
179
case 3300000:
180
reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK;
181
break;
182
default:
183
dev_err(dev, "invalid voltage: %d\n", voltage);
184
ret = -EINVAL;
185
goto err_regulator;
186
}
187
188
regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
189
PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg);
190
191
pistachio_internal_dac_pwr_off(dac);
192
pistachio_internal_dac_pwr_on(dac);
193
194
pm_runtime_set_active(dev);
195
pm_runtime_enable(dev);
196
pm_runtime_idle(dev);
197
198
ret = devm_snd_soc_register_component(dev,
199
&pistachio_internal_dac_driver,
200
pistachio_internal_dac_dais,
201
ARRAY_SIZE(pistachio_internal_dac_dais));
202
if (ret) {
203
dev_err(dev, "failed to register component: %d\n", ret);
204
goto err_pwr;
205
}
206
207
return 0;
208
209
err_pwr:
210
pm_runtime_disable(&pdev->dev);
211
pistachio_internal_dac_pwr_off(dac);
212
err_regulator:
213
regulator_disable(dac->supply);
214
215
return ret;
216
}
217
218
static void pistachio_internal_dac_remove(struct platform_device *pdev)
219
{
220
struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev);
221
222
pm_runtime_disable(&pdev->dev);
223
pistachio_internal_dac_pwr_off(dac);
224
regulator_disable(dac->supply);
225
}
226
227
static int pistachio_internal_dac_rt_resume(struct device *dev)
228
{
229
struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
230
int ret;
231
232
ret = regulator_enable(dac->supply);
233
if (ret) {
234
dev_err(dev, "failed to enable supply: %d\n", ret);
235
return ret;
236
}
237
238
pistachio_internal_dac_pwr_on(dac);
239
240
return 0;
241
}
242
243
static int pistachio_internal_dac_rt_suspend(struct device *dev)
244
{
245
struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
246
247
pistachio_internal_dac_pwr_off(dac);
248
249
regulator_disable(dac->supply);
250
251
return 0;
252
}
253
254
static const struct dev_pm_ops pistachio_internal_dac_pm_ops = {
255
RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend,
256
pistachio_internal_dac_rt_resume, NULL)
257
};
258
259
static const struct of_device_id pistachio_internal_dac_of_match[] = {
260
{ .compatible = "img,pistachio-internal-dac" },
261
{}
262
};
263
MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match);
264
265
static struct platform_driver pistachio_internal_dac_plat_driver = {
266
.driver = {
267
.name = "img-pistachio-internal-dac",
268
.of_match_table = pistachio_internal_dac_of_match,
269
.pm = pm_ptr(&pistachio_internal_dac_pm_ops)
270
},
271
.probe = pistachio_internal_dac_probe,
272
.remove = pistachio_internal_dac_remove
273
};
274
module_platform_driver(pistachio_internal_dac_plat_driver);
275
276
MODULE_DESCRIPTION("Pistachio Internal DAC driver");
277
MODULE_AUTHOR("Damien Horsley <[email protected]>");
278
MODULE_LICENSE("GPL v2");
279
280