1/*
2 * SoC audio for BCM94717BU Board
3 *
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: bcm94717bu.c,v 1.1 2009/10/30 20:41:44 Exp $
19 */
20
21
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/timer.h>
25#include <linux/interrupt.h>
26#include <linux/platform_device.h>
27#include <sound/driver.h>
28#include <sound/core.h>
29#include <sound/pcm.h>
30#include <sound/soc.h>
31#include <sound/soc-dapm.h>
32#include <linux/i2c-gpio.h>
33
34#include <typedefs.h>
35#include <bcmdevs.h>
36#include <pcicfg.h>
37#include <hndsoc.h>
38#include <osl.h>
39#include <bcmutils.h>
40#include <siutils.h>
41#include <sbhnddma.h>
42#include <hnddma.h>
43#include <i2s_core.h>
44
45
46#include "../codecs/wm8750.h"
47#include "bcm947xx-pcm.h"
48#include "bcm947xx-i2s.h"
49
50#define BCM947XX_BU_DEBUG 0
51#if BCM947XX_BU_DEBUG
52#define DBG(x...) printk(KERN_ERR x)
53#else
54#define DBG(x...)
55#endif
56
57
58 /* MCLK in Hz - to bcm94717 & Wolfson 8750 */
59#define BCM94717BU_MCLK_FREQ 12288000
60
61
62static int bcm94717bu_startup(struct snd_pcm_substream *substream)
63{
64	//struct snd_soc_pcm_runtime *rtd = substream->private_data;
65	//struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
66	//struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
67	int ret = 0;
68
69	//DBG("%s:\n", __FUNCTION__);
70
71	return ret;
72}
73
74static void bcm94717bu_shutdown(struct snd_pcm_substream *substream)
75{
76	//DBG("%s\n", __FUNCTION__);
77	return;
78}
79
80static int bcm94717bu_hw_params(struct snd_pcm_substream *substream,
81	struct snd_pcm_hw_params *params)
82{
83	struct snd_soc_pcm_runtime *rtd = substream->private_data;
84	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
85	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
86	unsigned int fmt;
87
88	int ret = 0;
89
90	fmt = SND_SOC_DAIFMT_I2S |		/* I2S mode audio */
91	        SND_SOC_DAIFMT_NB_NF |		/* BCLK not inverted and normal LRCLK polarity */
92	        SND_SOC_DAIFMT_CBS_CFS;		/* BCM947xx is I2S Master / codec is slave */
93
94	/* set codec DAI configuration */
95	ret = codec_dai->dai_ops.set_fmt(codec_dai, fmt);
96	if (ret < 0)
97		return ret;
98
99	/* set cpu DAI configuration */
100	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, fmt);
101	if (ret < 0)
102		return ret;
103
104	/* set the codec system clock for DAC and ADC */
105	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, BCM94717BU_MCLK_FREQ,
106		SND_SOC_CLOCK_IN);
107	if (ret < 0)
108		return ret;
109
110	/* set the I2S system clock as input (unused) */
111	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, BCM947XX_I2S_SYSCLK, BCM94717BU_MCLK_FREQ,
112		SND_SOC_CLOCK_IN);
113
114	if (ret < 0)
115		return ret;
116
117	return 0;
118}
119
120static struct snd_soc_ops bcm94717bu_ops = {
121	.startup = bcm94717bu_startup,
122	.hw_params = bcm94717bu_hw_params,
123	.shutdown = bcm94717bu_shutdown,
124};
125
126/*
127 * Logic for a wm8750
128 */
129static int bcm94717bu_wm8750_init(struct snd_soc_codec *codec)
130{
131	DBG("%s\n", __FUNCTION__);
132
133	snd_soc_dapm_sync_endpoints(codec);
134
135	return 0;
136}
137
138/* bcm94717bu digital audio interface glue - connects codec <--> CPU */
139static struct snd_soc_dai_link bcm94717bu_dai = {
140	.name = "WM8750",
141	.stream_name = "WM8750",
142	.cpu_dai = &bcm947xx_i2s_dai,
143	.codec_dai = &wm8750_dai,
144	.init = bcm94717bu_wm8750_init,
145	.ops = &bcm94717bu_ops,
146};
147
148/* bcm94717bu audio machine driver */
149static struct snd_soc_machine snd_soc_machine_bcm94717bu = {
150	.name = "Bcm94717bu",
151	.dai_link = &bcm94717bu_dai,
152	.num_links = 1,
153};
154
155/* bcm94717bu audio private data */
156static struct wm8750_setup_data bcm94717bu_wm8750_setup = {
157	.i2c_address = 0x1a, /* 2wire / I2C interface */
158};
159
160/* bcm94717bu audio subsystem */
161static struct snd_soc_device bcm94717bu_snd_devdata = {
162	.machine = &snd_soc_machine_bcm94717bu,
163	.platform = &bcm947xx_soc_platform,
164	.codec_dev = &soc_codec_dev_wm8750,
165	.codec_data = &bcm94717bu_wm8750_setup,
166};
167
168static struct platform_device *bcm94717bu_snd_device;
169
170static int machine_is_bcm94717bu(void)
171{
172	DBG("%s\n", __FUNCTION__);
173	return 1;
174}
175
176
177
178static struct i2c_gpio_platform_data i2c_gpio_data = {
179	.sda_pin	= 1,
180	.scl_pin	= 4,
181};
182
183static struct platform_device i2c_gpio_device = {
184	.name		= "i2c-gpio",
185	.id		= 0,
186	.dev		= {
187		.platform_data	= &i2c_gpio_data,
188	},
189};
190
191
192static int __init bcm94717bu_init(void)
193{
194	int ret;
195
196	DBG("%s\n", __FUNCTION__);
197
198	if (!machine_is_bcm94717bu())
199		return -ENODEV;
200
201	ret = platform_device_register(&i2c_gpio_device);
202	if (ret) {
203		platform_device_put(&i2c_gpio_device);
204		return ret;
205	}
206
207	bcm94717bu_snd_device = platform_device_alloc("soc-audio", -1);
208	if (!bcm94717bu_snd_device)
209		return -ENOMEM;
210
211	platform_set_drvdata(bcm94717bu_snd_device, &bcm94717bu_snd_devdata);
212	bcm94717bu_snd_devdata.dev = &bcm94717bu_snd_device->dev;
213	ret = platform_device_add(bcm94717bu_snd_device);
214
215	if (ret) {
216		platform_device_put(bcm94717bu_snd_device);
217	}
218
219	return ret;
220}
221
222static void __exit bcm94717bu_exit(void)
223{
224	platform_device_unregister(bcm94717bu_snd_device);
225}
226
227module_init(bcm94717bu_init);
228module_exit(bcm94717bu_exit);
229
230/* Module information */
231MODULE_DESCRIPTION("ALSA SoC BCM94717BU");
232MODULE_LICENSE("GPL");
233