blob: b883f99d6f9f18f09621b38d9b006c7b2bcc64b1 [file] [log] [blame]
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -05001/*
2 * ALSA Soc PCM3008 codec support
3 *
4 * Author: Hugo Villeneuve
5 * Copyright (C) 2008 Lyrtech inc
6 *
7 * Based on AC97 Soc codec, original copyright follow:
8 * Copyright 2005 Wolfson Microelectronics PLC.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 * Generic PCM3008 support.
16 */
17
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/device.h>
21#include <linux/gpio.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040023#include <linux/module.h>
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050024#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/initval.h>
27#include <sound/soc.h>
28
29#include "pcm3008.h"
30
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050031#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
32 SNDRV_PCM_RATE_48000)
33
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +000034static struct snd_soc_dai_driver pcm3008_dai = {
35 .name = "pcm3008-hifi",
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050036 .playback = {
37 .stream_name = "PCM3008 Playback",
38 .channels_min = 1,
39 .channels_max = 2,
40 .rates = PCM3008_RATES,
41 .formats = SNDRV_PCM_FMTBIT_S16_LE,
42 },
43 .capture = {
44 .stream_name = "PCM3008 Capture",
45 .channels_min = 1,
46 .channels_max = 2,
47 .rates = PCM3008_RATES,
48 .formats = SNDRV_PCM_FMTBIT_S16_LE,
49 },
50};
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050051
Mark Brownd7f18492013-07-10 16:48:24 +010052#ifdef CONFIG_PM
53static int pcm3008_soc_suspend(struct snd_soc_codec *codec)
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050054{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +000055 struct pcm3008_setup_data *setup = codec->dev->platform_data;
Mark Brownd7f18492013-07-10 16:48:24 +010056
57 gpio_set_value(setup->pdad_pin, 0);
58 gpio_set_value(setup->pdda_pin, 0);
59
60 return 0;
61}
62
63static int pcm3008_soc_resume(struct snd_soc_codec *codec)
64{
65 struct pcm3008_setup_data *setup = codec->dev->platform_data;
66
67 gpio_set_value(setup->pdad_pin, 1);
68 gpio_set_value(setup->pdda_pin, 1);
69
70 return 0;
71}
72#else
73#define pcm3008_soc_suspend NULL
74#define pcm3008_soc_resume NULL
75#endif
76
77static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
78 .suspend = pcm3008_soc_suspend,
79 .resume = pcm3008_soc_resume,
80};
81
82static int pcm3008_codec_probe(struct platform_device *pdev)
83{
84 struct pcm3008_setup_data *setup = pdev->dev.platform_data;
85 int ret;
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050086
Mark Brown33319a22013-07-10 16:49:16 +010087 if (!setup)
88 return -EINVAL;
89
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050090 /* DEM1 DEM0 DE-EMPHASIS_MODE
91 * Low Low De-emphasis 44.1 kHz ON
92 * Low High De-emphasis OFF
93 * High Low De-emphasis 48 kHz ON
94 * High High De-emphasis 32 kHz ON
95 */
96
97 /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
Mark Brownd57a79a2013-07-10 16:53:55 +010098 ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin,
99 GPIOF_OUT_INIT_HIGH, "codec_dem0");
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500100 if (ret != 0)
Mark Brownd57a79a2013-07-10 16:53:55 +0100101 return ret;
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500102
103 /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
Mark Brownd57a79a2013-07-10 16:53:55 +0100104 ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin,
105 GPIOF_OUT_INIT_LOW, "codec_dem1");
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500106 if (ret != 0)
Mark Brownd57a79a2013-07-10 16:53:55 +0100107 return ret;
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500108
109 /* Configure PDAD GPIO. */
Mark Brownd57a79a2013-07-10 16:53:55 +0100110 ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin,
111 GPIOF_OUT_INIT_HIGH, "codec_pdad");
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500112 if (ret != 0)
Mark Brownd57a79a2013-07-10 16:53:55 +0100113 return ret;
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500114
115 /* Configure PDDA GPIO. */
Mark Brownd57a79a2013-07-10 16:53:55 +0100116 ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin,
117 GPIOF_OUT_INIT_HIGH, "codec_pdda");
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500118 if (ret != 0)
Mark Brownd57a79a2013-07-10 16:53:55 +0100119 return ret;
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500120
Mark Brownd7f18492013-07-10 16:48:24 +0100121 return snd_soc_register_codec(&pdev->dev,
122 &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500123}
124
Bill Pemberton7a79e942012-12-07 09:26:37 -0500125static int pcm3008_codec_remove(struct platform_device *pdev)
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000126{
127 snd_soc_unregister_codec(&pdev->dev);
Mark Brownd7f18492013-07-10 16:48:24 +0100128
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000129 return 0;
130}
131
132MODULE_ALIAS("platform:pcm3008-codec");
133
134static struct platform_driver pcm3008_codec_driver = {
135 .probe = pcm3008_codec_probe,
Bill Pemberton7a79e942012-12-07 09:26:37 -0500136 .remove = pcm3008_codec_remove,
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000137 .driver = {
138 .name = "pcm3008-codec",
139 .owner = THIS_MODULE,
140 },
141};
142
Mark Brown5bbcc3c2011-11-23 22:52:08 +0000143module_platform_driver(pcm3008_codec_driver);
Mark Brown64089b82008-12-08 19:17:58 +0000144
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500145MODULE_DESCRIPTION("Soc PCM3008 driver");
146MODULE_AUTHOR("Hugo Villeneuve");
147MODULE_LICENSE("GPL");