Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/boards/cht_bsw_max98090_ti.c
26493 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based
4
* platforms Cherrytrail and Braswell, with max98090 & TI codec.
5
*
6
* Copyright (C) 2015 Intel Corp
7
* Author: Fang, Yang A <[email protected]>
8
* This file is modified from cht_bsw_rt5645.c
9
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10
*
11
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12
*/
13
14
#include <linux/dmi.h>
15
#include <linux/gpio/consumer.h>
16
#include <linux/module.h>
17
#include <linux/platform_device.h>
18
#include <linux/slab.h>
19
#include <linux/acpi.h>
20
#include <linux/clk.h>
21
#include <sound/pcm.h>
22
#include <sound/pcm_params.h>
23
#include <sound/soc.h>
24
#include <sound/soc-acpi.h>
25
#include <sound/jack.h>
26
#include "../../codecs/max98090.h"
27
#include "../atom/sst-atom-controls.h"
28
#include "../../codecs/ts3a227e.h"
29
30
#define CHT_PLAT_CLK_3_HZ 19200000
31
#define CHT_CODEC_DAI "HiFi"
32
33
#define QUIRK_PMC_PLT_CLK_0 0x01
34
35
struct cht_mc_private {
36
struct clk *mclk;
37
struct snd_soc_jack jack;
38
bool ts3a227e_present;
39
int quirks;
40
};
41
42
static int platform_clock_control(struct snd_soc_dapm_widget *w,
43
struct snd_kcontrol *k, int event)
44
{
45
struct snd_soc_dapm_context *dapm = w->dapm;
46
struct snd_soc_card *card = dapm->card;
47
struct snd_soc_dai *codec_dai;
48
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
49
int ret;
50
51
/* See the comment in snd_cht_mc_probe() */
52
if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)
53
return 0;
54
55
codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI);
56
if (!codec_dai) {
57
dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
58
return -EIO;
59
}
60
61
if (SND_SOC_DAPM_EVENT_ON(event)) {
62
ret = clk_prepare_enable(ctx->mclk);
63
if (ret < 0) {
64
dev_err(card->dev,
65
"could not configure MCLK state");
66
return ret;
67
}
68
} else {
69
clk_disable_unprepare(ctx->mclk);
70
}
71
72
return 0;
73
}
74
75
static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
76
SND_SOC_DAPM_HP("Headphone", NULL),
77
SND_SOC_DAPM_MIC("Headset Mic", NULL),
78
SND_SOC_DAPM_MIC("Int Mic", NULL),
79
SND_SOC_DAPM_SPK("Ext Spk", NULL),
80
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
81
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
82
SND_SOC_DAPM_POST_PMD),
83
};
84
85
static const struct snd_soc_dapm_route cht_audio_map[] = {
86
{"IN34", NULL, "Headset Mic"},
87
{"Headset Mic", NULL, "MICBIAS"},
88
{"DMICL", NULL, "Int Mic"},
89
{"Headphone", NULL, "HPL"},
90
{"Headphone", NULL, "HPR"},
91
{"Ext Spk", NULL, "SPKL"},
92
{"Ext Spk", NULL, "SPKR"},
93
{"HiFi Playback", NULL, "ssp2 Tx"},
94
{"ssp2 Tx", NULL, "codec_out0"},
95
{"ssp2 Tx", NULL, "codec_out1"},
96
{"codec_in0", NULL, "ssp2 Rx" },
97
{"codec_in1", NULL, "ssp2 Rx" },
98
{"ssp2 Rx", NULL, "HiFi Capture"},
99
{"Headphone", NULL, "Platform Clock"},
100
{"Headset Mic", NULL, "Platform Clock"},
101
{"Int Mic", NULL, "Platform Clock"},
102
{"Ext Spk", NULL, "Platform Clock"},
103
};
104
105
static const struct snd_kcontrol_new cht_mc_controls[] = {
106
SOC_DAPM_PIN_SWITCH("Headphone"),
107
SOC_DAPM_PIN_SWITCH("Headset Mic"),
108
SOC_DAPM_PIN_SWITCH("Int Mic"),
109
SOC_DAPM_PIN_SWITCH("Ext Spk"),
110
};
111
112
static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
113
struct snd_pcm_hw_params *params)
114
{
115
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
116
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
117
int ret;
118
119
ret = snd_soc_dai_set_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK,
120
CHT_PLAT_CLK_3_HZ, SND_SOC_CLOCK_IN);
121
if (ret < 0) {
122
dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
123
return ret;
124
}
125
126
return 0;
127
}
128
129
static int cht_ti_jack_event(struct notifier_block *nb,
130
unsigned long event, void *data)
131
{
132
struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
133
struct snd_soc_dapm_context *dapm = &jack->card->dapm;
134
135
if (event & SND_JACK_MICROPHONE) {
136
snd_soc_dapm_force_enable_pin(dapm, "SHDN");
137
snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
138
snd_soc_dapm_sync(dapm);
139
} else {
140
snd_soc_dapm_disable_pin(dapm, "MICBIAS");
141
snd_soc_dapm_disable_pin(dapm, "SHDN");
142
snd_soc_dapm_sync(dapm);
143
}
144
145
return 0;
146
}
147
148
static struct notifier_block cht_jack_nb = {
149
.notifier_call = cht_ti_jack_event,
150
};
151
152
static struct snd_soc_jack_pin hs_jack_pins[] = {
153
{
154
.pin = "Headphone",
155
.mask = SND_JACK_HEADPHONE,
156
},
157
{
158
.pin = "Headset Mic",
159
.mask = SND_JACK_MICROPHONE,
160
},
161
};
162
163
static struct snd_soc_jack_gpio hs_jack_gpios[] = {
164
{
165
.name = "hp",
166
.report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
167
.debounce_time = 200,
168
},
169
{
170
.name = "mic",
171
.invert = 1,
172
.report = SND_JACK_MICROPHONE,
173
.debounce_time = 200,
174
},
175
};
176
177
static const struct acpi_gpio_params hp_gpios = { 0, 0, false };
178
static const struct acpi_gpio_params mic_gpios = { 1, 0, false };
179
180
static const struct acpi_gpio_mapping acpi_max98090_gpios[] = {
181
{ "hp-gpios", &hp_gpios, 1 },
182
{ "mic-gpios", &mic_gpios, 1 },
183
{},
184
};
185
186
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
187
{
188
int ret;
189
int jack_type;
190
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
191
struct snd_soc_jack *jack = &ctx->jack;
192
193
if (ctx->ts3a227e_present) {
194
/*
195
* The jack has already been created in the
196
* cht_max98090_headset_init() function.
197
*/
198
snd_soc_jack_notifier_register(jack, &cht_jack_nb);
199
return 0;
200
}
201
202
jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;
203
204
ret = snd_soc_card_jack_new_pins(runtime->card, "Headset Jack",
205
jack_type, jack,
206
hs_jack_pins,
207
ARRAY_SIZE(hs_jack_pins));
208
if (ret) {
209
dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret);
210
return ret;
211
}
212
213
ret = snd_soc_jack_add_gpiods(runtime->card->dev->parent, jack,
214
ARRAY_SIZE(hs_jack_gpios),
215
hs_jack_gpios);
216
if (ret) {
217
/*
218
* flag error but don't bail if jack detect is broken
219
* due to platform issues or bad BIOS/configuration
220
*/
221
dev_err(runtime->dev,
222
"jack detection gpios not added, error %d\n", ret);
223
}
224
225
/* See the comment in snd_cht_mc_probe() */
226
if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)
227
return 0;
228
229
/*
230
* The firmware might enable the clock at
231
* boot (this information may or may not
232
* be reflected in the enable clock register).
233
* To change the rate we must disable the clock
234
* first to cover these cases. Due to common
235
* clock framework restrictions that do not allow
236
* to disable a clock that has not been enabled,
237
* we need to enable the clock first.
238
*/
239
ret = clk_prepare_enable(ctx->mclk);
240
if (!ret)
241
clk_disable_unprepare(ctx->mclk);
242
243
ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
244
245
if (ret)
246
dev_err(runtime->dev, "unable to set MCLK rate\n");
247
248
return ret;
249
}
250
251
static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
252
struct snd_pcm_hw_params *params)
253
{
254
struct snd_interval *rate = hw_param_interval(params,
255
SNDRV_PCM_HW_PARAM_RATE);
256
struct snd_interval *channels = hw_param_interval(params,
257
SNDRV_PCM_HW_PARAM_CHANNELS);
258
int ret = 0;
259
unsigned int fmt = 0;
260
261
ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
262
if (ret < 0) {
263
dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret);
264
return ret;
265
}
266
267
fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP;
268
269
ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), fmt);
270
if (ret < 0) {
271
dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret);
272
return ret;
273
}
274
275
/* The DSP will convert the FE rate to 48k, stereo, 24bits */
276
rate->min = rate->max = 48000;
277
channels->min = channels->max = 2;
278
279
/* set SSP2 to 16-bit */
280
params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
281
return 0;
282
}
283
284
static int cht_aif1_startup(struct snd_pcm_substream *substream)
285
{
286
return snd_pcm_hw_constraint_single(substream->runtime,
287
SNDRV_PCM_HW_PARAM_RATE, 48000);
288
}
289
290
static int cht_max98090_headset_init(struct snd_soc_component *component)
291
{
292
struct snd_soc_card *card = component->card;
293
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
294
struct snd_soc_jack *jack = &ctx->jack;
295
int jack_type;
296
int ret;
297
298
/*
299
* TI supports 4 buttons headset detection
300
* KEY_MEDIA
301
* KEY_VOICECOMMAND
302
* KEY_VOLUMEUP
303
* KEY_VOLUMEDOWN
304
*/
305
jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
306
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
307
SND_JACK_BTN_2 | SND_JACK_BTN_3;
308
309
ret = snd_soc_card_jack_new(card, "Headset Jack", jack_type, jack);
310
if (ret) {
311
dev_err(card->dev, "Headset Jack creation failed %d\n", ret);
312
return ret;
313
}
314
315
return ts3a227e_enable_jack_detect(component, jack);
316
}
317
318
static const struct snd_soc_ops cht_aif1_ops = {
319
.startup = cht_aif1_startup,
320
};
321
322
static const struct snd_soc_ops cht_be_ssp2_ops = {
323
.hw_params = cht_aif1_hw_params,
324
};
325
326
static struct snd_soc_aux_dev cht_max98090_headset_dev = {
327
.dlc = COMP_AUX("i2c-104C227E:00"),
328
.init = cht_max98090_headset_init,
329
};
330
331
SND_SOC_DAILINK_DEF(dummy,
332
DAILINK_COMP_ARRAY(COMP_DUMMY()));
333
334
SND_SOC_DAILINK_DEF(media,
335
DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
336
337
SND_SOC_DAILINK_DEF(deepbuffer,
338
DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
339
340
SND_SOC_DAILINK_DEF(ssp2_port,
341
DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
342
SND_SOC_DAILINK_DEF(ssp2_codec,
343
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-193C9890:00", "HiFi")));
344
345
SND_SOC_DAILINK_DEF(platform,
346
DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
347
348
static struct snd_soc_dai_link cht_dailink[] = {
349
[MERR_DPCM_AUDIO] = {
350
.name = "Audio Port",
351
.stream_name = "Audio",
352
.nonatomic = true,
353
.dynamic = 1,
354
.ops = &cht_aif1_ops,
355
SND_SOC_DAILINK_REG(media, dummy, platform),
356
},
357
[MERR_DPCM_DEEP_BUFFER] = {
358
.name = "Deep-Buffer Audio Port",
359
.stream_name = "Deep-Buffer Audio",
360
.nonatomic = true,
361
.dynamic = 1,
362
.playback_only = 1,
363
.ops = &cht_aif1_ops,
364
SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
365
},
366
/* back ends */
367
{
368
.name = "SSP2-Codec",
369
.id = 0,
370
.no_pcm = 1,
371
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
372
| SND_SOC_DAIFMT_CBC_CFC,
373
.init = cht_codec_init,
374
.be_hw_params_fixup = cht_codec_fixup,
375
.ops = &cht_be_ssp2_ops,
376
SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
377
},
378
};
379
380
/* use space before codec name to simplify card ID, and simplify driver name */
381
#define SOF_CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */
382
#define SOF_DRIVER_NAME "SOF"
383
384
#define CARD_NAME "chtmax98090"
385
#define DRIVER_NAME NULL /* card name will be used for driver name */
386
387
/* SoC card */
388
static struct snd_soc_card snd_soc_card_cht = {
389
.owner = THIS_MODULE,
390
.dai_link = cht_dailink,
391
.num_links = ARRAY_SIZE(cht_dailink),
392
.aux_dev = &cht_max98090_headset_dev,
393
.num_aux_devs = 1,
394
.dapm_widgets = cht_dapm_widgets,
395
.num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
396
.dapm_routes = cht_audio_map,
397
.num_dapm_routes = ARRAY_SIZE(cht_audio_map),
398
.controls = cht_mc_controls,
399
.num_controls = ARRAY_SIZE(cht_mc_controls),
400
};
401
402
static const struct dmi_system_id cht_max98090_quirk_table[] = {
403
{
404
/* Banjo model Chromebook */
405
.matches = {
406
DMI_MATCH(DMI_PRODUCT_NAME, "Banjo"),
407
},
408
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
409
},
410
{
411
/* Candy model Chromebook */
412
.matches = {
413
DMI_MATCH(DMI_PRODUCT_NAME, "Candy"),
414
},
415
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
416
},
417
{
418
/* Clapper model Chromebook */
419
.matches = {
420
DMI_MATCH(DMI_PRODUCT_NAME, "Clapper"),
421
},
422
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
423
},
424
{
425
/* Cyan model Chromebook */
426
.matches = {
427
DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"),
428
},
429
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
430
},
431
{
432
/* Enguarde model Chromebook */
433
.matches = {
434
DMI_MATCH(DMI_PRODUCT_NAME, "Enguarde"),
435
},
436
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
437
},
438
{
439
/* Glimmer model Chromebook */
440
.matches = {
441
DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer"),
442
},
443
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
444
},
445
{
446
/* Gnawty model Chromebook (Acer Chromebook CB3-111) */
447
.matches = {
448
DMI_MATCH(DMI_PRODUCT_NAME, "Gnawty"),
449
},
450
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
451
},
452
{
453
/* Heli model Chromebook */
454
.matches = {
455
DMI_MATCH(DMI_PRODUCT_NAME, "Heli"),
456
},
457
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
458
},
459
{
460
/* Kip model Chromebook */
461
.matches = {
462
DMI_MATCH(DMI_PRODUCT_NAME, "Kip"),
463
},
464
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
465
},
466
{
467
/* Ninja model Chromebook */
468
.matches = {
469
DMI_MATCH(DMI_PRODUCT_NAME, "Ninja"),
470
},
471
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
472
},
473
{
474
/* Orco model Chromebook */
475
.matches = {
476
DMI_MATCH(DMI_PRODUCT_NAME, "Orco"),
477
},
478
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
479
},
480
{
481
/* Quawks model Chromebook */
482
.matches = {
483
DMI_MATCH(DMI_PRODUCT_NAME, "Quawks"),
484
},
485
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
486
},
487
{
488
/* Rambi model Chromebook */
489
.matches = {
490
DMI_MATCH(DMI_PRODUCT_NAME, "Rambi"),
491
},
492
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
493
},
494
{
495
/* Squawks model Chromebook */
496
.matches = {
497
DMI_MATCH(DMI_PRODUCT_NAME, "Squawks"),
498
},
499
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
500
},
501
{
502
/* Sumo model Chromebook */
503
.matches = {
504
DMI_MATCH(DMI_PRODUCT_NAME, "Sumo"),
505
},
506
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
507
},
508
{
509
/* Swanky model Chromebook (Toshiba Chromebook 2) */
510
.matches = {
511
DMI_MATCH(DMI_PRODUCT_NAME, "Swanky"),
512
},
513
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
514
},
515
{
516
/* Winky model Chromebook */
517
.matches = {
518
DMI_MATCH(DMI_PRODUCT_NAME, "Winky"),
519
},
520
.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
521
},
522
{}
523
};
524
525
static int snd_cht_mc_probe(struct platform_device *pdev)
526
{
527
const struct dmi_system_id *dmi_id;
528
struct device *dev = &pdev->dev;
529
int ret_val = 0;
530
struct cht_mc_private *drv;
531
const char *mclk_name;
532
struct snd_soc_acpi_mach *mach;
533
const char *platform_name;
534
bool sof_parent;
535
536
drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
537
if (!drv)
538
return -ENOMEM;
539
540
dmi_id = dmi_first_match(cht_max98090_quirk_table);
541
if (dmi_id)
542
drv->quirks = (unsigned long)dmi_id->driver_data;
543
544
drv->ts3a227e_present = acpi_dev_found("104C227E");
545
if (!drv->ts3a227e_present) {
546
/* no need probe TI jack detection chip */
547
snd_soc_card_cht.aux_dev = NULL;
548
snd_soc_card_cht.num_aux_devs = 0;
549
550
ret_val = devm_acpi_dev_add_driver_gpios(dev->parent,
551
acpi_max98090_gpios);
552
if (ret_val)
553
dev_dbg(dev, "Unable to add GPIO mapping table\n");
554
}
555
556
/* override platform name, if required */
557
snd_soc_card_cht.dev = dev;
558
mach = dev->platform_data;
559
platform_name = mach->mach_params.platform;
560
561
ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht,
562
platform_name);
563
if (ret_val)
564
return ret_val;
565
566
/* register the soc card */
567
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
568
569
if (drv->quirks & QUIRK_PMC_PLT_CLK_0)
570
mclk_name = "pmc_plt_clk_0";
571
else
572
mclk_name = "pmc_plt_clk_3";
573
574
drv->mclk = devm_clk_get(dev, mclk_name);
575
if (IS_ERR(drv->mclk)) {
576
dev_err(dev,
577
"Failed to get MCLK from %s: %ld\n",
578
mclk_name, PTR_ERR(drv->mclk));
579
return PTR_ERR(drv->mclk);
580
}
581
582
/*
583
* Boards which have the MAX98090's clk connected to clk_0 do not seem
584
* to like it if we muck with the clock. If we disable the clock when
585
* it is unused we get "max98090 i2c-193C9890:00: PLL unlocked" errors
586
* and the PLL never seems to lock again.
587
* So for these boards we enable it here once and leave it at that.
588
*/
589
if (drv->quirks & QUIRK_PMC_PLT_CLK_0) {
590
ret_val = clk_prepare_enable(drv->mclk);
591
if (ret_val < 0) {
592
dev_err(dev, "MCLK enable error: %d\n", ret_val);
593
return ret_val;
594
}
595
}
596
597
sof_parent = snd_soc_acpi_sof_parent(dev);
598
599
/* set card and driver name */
600
if (sof_parent) {
601
snd_soc_card_cht.name = SOF_CARD_NAME;
602
snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
603
} else {
604
snd_soc_card_cht.name = CARD_NAME;
605
snd_soc_card_cht.driver_name = DRIVER_NAME;
606
}
607
608
/* set pm ops */
609
if (sof_parent)
610
dev->driver->pm = &snd_soc_pm_ops;
611
612
ret_val = devm_snd_soc_register_card(dev, &snd_soc_card_cht);
613
if (ret_val) {
614
dev_err(dev,
615
"snd_soc_register_card failed %d\n", ret_val);
616
return ret_val;
617
}
618
platform_set_drvdata(pdev, &snd_soc_card_cht);
619
return ret_val;
620
}
621
622
static void snd_cht_mc_remove(struct platform_device *pdev)
623
{
624
struct snd_soc_card *card = platform_get_drvdata(pdev);
625
struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
626
627
if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)
628
clk_disable_unprepare(ctx->mclk);
629
}
630
631
static struct platform_driver snd_cht_mc_driver = {
632
.driver = {
633
.name = "cht-bsw-max98090",
634
},
635
.probe = snd_cht_mc_probe,
636
.remove = snd_cht_mc_remove,
637
};
638
639
module_platform_driver(snd_cht_mc_driver)
640
641
MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
642
MODULE_AUTHOR("Fang, Yang A <[email protected]>");
643
MODULE_LICENSE("GPL v2");
644
MODULE_ALIAS("platform:cht-bsw-max98090");
645
646