blob: 4fa4ded30407fe8ce04fc350b8cb1ea3b7324b7a [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
52static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
53{
54 gpio_free(setup->dem0_pin);
55 gpio_free(setup->dem1_pin);
56 gpio_free(setup->pdad_pin);
57 gpio_free(setup->pdda_pin);
58}
59
Mark Brownd7f18492013-07-10 16:48:24 +010060#ifdef CONFIG_PM
61static int pcm3008_soc_suspend(struct snd_soc_codec *codec)
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050062{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +000063 struct pcm3008_setup_data *setup = codec->dev->platform_data;
Mark Brownd7f18492013-07-10 16:48:24 +010064
65 gpio_set_value(setup->pdad_pin, 0);
66 gpio_set_value(setup->pdda_pin, 0);
67
68 return 0;
69}
70
71static int pcm3008_soc_resume(struct snd_soc_codec *codec)
72{
73 struct pcm3008_setup_data *setup = codec->dev->platform_data;
74
75 gpio_set_value(setup->pdad_pin, 1);
76 gpio_set_value(setup->pdda_pin, 1);
77
78 return 0;
79}
80#else
81#define pcm3008_soc_suspend NULL
82#define pcm3008_soc_resume NULL
83#endif
84
85static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
86 .suspend = pcm3008_soc_suspend,
87 .resume = pcm3008_soc_resume,
88};
89
90static int pcm3008_codec_probe(struct platform_device *pdev)
91{
92 struct pcm3008_setup_data *setup = pdev->dev.platform_data;
93 int ret;
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050094
Mark Brown33319a22013-07-10 16:49:16 +010095 if (!setup)
96 return -EINVAL;
97
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -050098 /* DEM1 DEM0 DE-EMPHASIS_MODE
99 * Low Low De-emphasis 44.1 kHz ON
100 * Low High De-emphasis OFF
101 * High Low De-emphasis 48 kHz ON
102 * High High De-emphasis 32 kHz ON
103 */
104
105 /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
106 ret = gpio_request(setup->dem0_pin, "codec_dem0");
107 if (ret == 0)
108 ret = gpio_direction_output(setup->dem0_pin, 1);
109 if (ret != 0)
110 goto gpio_err;
111
112 /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
113 ret = gpio_request(setup->dem1_pin, "codec_dem1");
114 if (ret == 0)
115 ret = gpio_direction_output(setup->dem1_pin, 0);
116 if (ret != 0)
117 goto gpio_err;
118
119 /* Configure PDAD GPIO. */
120 ret = gpio_request(setup->pdad_pin, "codec_pdad");
121 if (ret == 0)
122 ret = gpio_direction_output(setup->pdad_pin, 1);
123 if (ret != 0)
124 goto gpio_err;
125
126 /* Configure PDDA GPIO. */
127 ret = gpio_request(setup->pdda_pin, "codec_pdda");
128 if (ret == 0)
129 ret = gpio_direction_output(setup->pdda_pin, 1);
130 if (ret != 0)
131 goto gpio_err;
132
Mark Brownd7f18492013-07-10 16:48:24 +0100133 return snd_soc_register_codec(&pdev->dev,
134 &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500135
136gpio_err:
137 pcm3008_gpio_free(setup);
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500138 return ret;
139}
140
Bill Pemberton7a79e942012-12-07 09:26:37 -0500141static int pcm3008_codec_remove(struct platform_device *pdev)
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000142{
Mark Brownd7f18492013-07-10 16:48:24 +0100143 struct pcm3008_setup_data *setup = pdev->dev.platform_data;
144
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000145 snd_soc_unregister_codec(&pdev->dev);
Mark Brownd7f18492013-07-10 16:48:24 +0100146
147 pcm3008_gpio_free(setup);
148
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000149 return 0;
150}
151
152MODULE_ALIAS("platform:pcm3008-codec");
153
154static struct platform_driver pcm3008_codec_driver = {
155 .probe = pcm3008_codec_probe,
Bill Pemberton7a79e942012-12-07 09:26:37 -0500156 .remove = pcm3008_codec_remove,
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000157 .driver = {
158 .name = "pcm3008-codec",
159 .owner = THIS_MODULE,
160 },
161};
162
Mark Brown5bbcc3c2011-11-23 22:52:08 +0000163module_platform_driver(pcm3008_codec_driver);
Mark Brown64089b82008-12-08 19:17:58 +0000164
Hugo Villeneuve1c0090c2008-11-19 01:37:31 -0500165MODULE_DESCRIPTION("Soc PCM3008 driver");
166MODULE_AUTHOR("Hugo Villeneuve");
167MODULE_LICENSE("GPL");