1 /*
2  * SoC audio for EDB93xx
3  *
4  * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * This driver support CS4271 codec being master or slave, working
17  * in control port mode, connected either via SPI or I2C.
18  * The data format accepted is I2S or left-justified.
19  * DAPM support not implemented.
20  */
21 
22 #include <linux/platform_device.h>
23 #include <linux/gpio.h>
24 #include <sound/core.h>
25 #include <sound/pcm.h>
26 #include <sound/soc.h>
27 #include <asm/mach-types.h>
28 #include <mach/hardware.h>
29 #include "ep93xx-pcm.h"
30 
31 #define edb93xx_has_audio() (machine_is_edb9301() ||	\
32 			     machine_is_edb9302() ||	\
33 			     machine_is_edb9302a() ||	\
34 			     machine_is_edb9307a() ||	\
35 			     machine_is_edb9315a())
36 
edb93xx_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)37 static int edb93xx_hw_params(struct snd_pcm_substream *substream,
38 			     struct snd_pcm_hw_params *params)
39 {
40 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
41 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
42 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
43 	int err;
44 	unsigned int mclk_rate;
45 	unsigned int rate = params_rate(params);
46 
47 	/*
48 	 * According to CS4271 datasheet we use MCLK/LRCK=256 for
49 	 * rates below 50kHz and 128 for higher sample rates
50 	 */
51 	if (rate < 50000)
52 		mclk_rate = rate * 64 * 4;
53 	else
54 		mclk_rate = rate * 64 * 2;
55 
56 	err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
57 				  SND_SOC_DAIFMT_NB_IF |
58 				  SND_SOC_DAIFMT_CBS_CFS);
59 	if (err)
60 		return err;
61 
62 	err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
63 				  SND_SOC_DAIFMT_NB_IF |
64 				  SND_SOC_DAIFMT_CBS_CFS);
65 	if (err)
66 		return err;
67 
68 	err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate,
69 				     SND_SOC_CLOCK_IN);
70 	if (err)
71 		return err;
72 
73 	return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate,
74 				      SND_SOC_CLOCK_OUT);
75 }
76 
77 static struct snd_soc_ops edb93xx_ops = {
78 	.hw_params	= edb93xx_hw_params,
79 };
80 
81 static struct snd_soc_dai_link edb93xx_dai = {
82 	.name		= "CS4271",
83 	.stream_name	= "CS4271 HiFi",
84 	.platform_name	= "ep93xx-pcm-audio",
85 	.cpu_dai_name	= "ep93xx-i2s",
86 	.codec_name	= "spi0.0",
87 	.codec_dai_name	= "cs4271-hifi",
88 	.ops		= &edb93xx_ops,
89 };
90 
91 static struct snd_soc_card snd_soc_edb93xx = {
92 	.name		= "EDB93XX",
93 	.dai_link	= &edb93xx_dai,
94 	.num_links	= 1,
95 };
96 
97 static struct platform_device *edb93xx_snd_device;
98 
edb93xx_init(void)99 static int __init edb93xx_init(void)
100 {
101 	int ret;
102 
103 	if (!edb93xx_has_audio())
104 		return -ENODEV;
105 
106 	ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97,
107 				 EP93XX_SYSCON_I2SCLKDIV_ORIDE |
108 				 EP93XX_SYSCON_I2SCLKDIV_SPOL);
109 	if (ret)
110 		return ret;
111 
112 	edb93xx_snd_device = platform_device_alloc("soc-audio", -1);
113 	if (!edb93xx_snd_device) {
114 		ret = -ENOMEM;
115 		goto free_i2s;
116 	}
117 
118 	platform_set_drvdata(edb93xx_snd_device, &snd_soc_edb93xx);
119 	ret = platform_device_add(edb93xx_snd_device);
120 	if (ret)
121 		goto device_put;
122 
123 	return 0;
124 
125 device_put:
126 	platform_device_put(edb93xx_snd_device);
127 free_i2s:
128 	ep93xx_i2s_release();
129 	return ret;
130 }
131 module_init(edb93xx_init);
132 
edb93xx_exit(void)133 static void __exit edb93xx_exit(void)
134 {
135 	platform_device_unregister(edb93xx_snd_device);
136 	ep93xx_i2s_release();
137 }
138 module_exit(edb93xx_exit);
139 
140 MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
141 MODULE_DESCRIPTION("ALSA SoC EDB93xx");
142 MODULE_LICENSE("GPL");
143