Root/target/linux/ixp4xx/patches-3.3/175-avila_hss_audio_support.patch

1--- a/sound/soc/Kconfig
2+++ b/sound/soc/Kconfig
3@@ -45,6 +45,7 @@ source "sound/soc/s6000/Kconfig"
4 source "sound/soc/sh/Kconfig"
5 source "sound/soc/tegra/Kconfig"
6 source "sound/soc/txx9/Kconfig"
7+source "sound/soc/gw-avila/Kconfig"
8 
9 # Supported codecs
10 source "sound/soc/codecs/Kconfig"
11--- a/sound/soc/Makefile
12+++ b/sound/soc/Makefile
13@@ -22,3 +22,4 @@ obj-$(CONFIG_SND_SOC) += s6000/
14 obj-$(CONFIG_SND_SOC) += sh/
15 obj-$(CONFIG_SND_SOC) += tegra/
16 obj-$(CONFIG_SND_SOC) += txx9/
17+obj-$(CONFIG_SND_SOC) += gw-avila/
18--- /dev/null
19+++ b/sound/soc/gw-avila/Kconfig
20@@ -0,0 +1,17 @@
21+config SND_GW_AVILA_SOC_PCM
22+ tristate
23+
24+config SND_GW_AVILA_SOC_HSS
25+ tristate
26+
27+config SND_GW_AVILA_SOC
28+ tristate "SoC Audio for the Gateworks AVILA Family"
29+ depends on ARCH_IXP4XX && SND_SOC
30+ select SND_GW_AVILA_SOC_PCM
31+ select SND_GW_AVILA_SOC_HSS
32+ select SND_SOC_TLV320AIC3X
33+ help
34+ Say Y or M if you want to add support for codecs attached to
35+ the Gateworks HSS interface. You will also need
36+ to select the audio interfaces to support below.
37+
38--- /dev/null
39+++ b/sound/soc/gw-avila/Makefile
40@@ -0,0 +1,8 @@
41+# Gateworks Avila HSS Platform Support
42+snd-soc-gw-avila-objs := gw-avila.o ixp4xx_hss.o
43+snd-soc-gw-avila-pcm-objs := gw-avila-pcm.o
44+snd-soc-gw-avila-hss-objs := gw-avila-hss.o
45+
46+obj-$(CONFIG_SND_GW_AVILA_SOC) += snd-soc-gw-avila.o
47+obj-$(CONFIG_SND_GW_AVILA_SOC_PCM) += snd-soc-gw-avila-pcm.o
48+obj-$(CONFIG_SND_GW_AVILA_SOC_HSS) += snd-soc-gw-avila-hss.o
49--- /dev/null
50+++ b/sound/soc/gw-avila/gw-avila-hss.c
51@@ -0,0 +1,98 @@
52+/*
53+ * gw-avila-hss.c -- HSS Audio Support for Gateworks Avila
54+ *
55+ * Author: Chris Lang <clang@gateworks.com>
56+ *
57+ * This program is free software; you can redistribute it and/or modify
58+ * it under the terms of the GNU General Public License version 2 as
59+ * published by the Free Software Foundation.
60+ */
61+
62+#include <linux/init.h>
63+#include <linux/module.h>
64+#include <linux/platform_device.h>
65+#include <linux/interrupt.h>
66+#include <linux/wait.h>
67+#include <linux/delay.h>
68+
69+#include <sound/core.h>
70+#include <sound/pcm.h>
71+#include <sound/ac97_codec.h>
72+#include <sound/initval.h>
73+#include <sound/soc.h>
74+
75+#include <asm/irq.h>
76+#include <linux/mutex.h>
77+#include <linux/gpio.h>
78+
79+#include "ixp4xx_hss.h"
80+#include "gw-avila-hss.h"
81+
82+#define gw_avila_hss_suspend NULL
83+#define gw_avila_hss_resume NULL
84+
85+struct snd_soc_dai_driver gw_avila_hss_dai = {
86+ .playback = {
87+ .channels_min = 2,
88+ .channels_max = 2,
89+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
90+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
91+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
92+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
93+ SNDRV_PCM_RATE_KNOT),
94+ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
95+ .capture = {
96+ .channels_min = 2,
97+ .channels_max = 2,
98+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
99+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
100+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
101+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
102+ SNDRV_PCM_RATE_KNOT),
103+ .formats = SNDRV_PCM_FMTBIT_S16_LE, },
104+};
105+
106+static int gw_avila_hss_probe(struct platform_device *pdev)
107+{
108+ int port = (pdev->id < 2) ? 0 : 1;
109+ int channel = (pdev->id % 2);
110+
111+ hss_handle[pdev->id] = hss_init(port, channel);
112+ if (!hss_handle[pdev->id]) {
113+ return -ENODEV;
114+ }
115+
116+ return snd_soc_register_dai(&pdev->dev, &gw_avila_hss_dai);
117+}
118+
119+static int gw_avila_hss_remove(struct platform_device *pdev)
120+{
121+ snd_soc_unregister_dai(&pdev->dev);
122+
123+ return 0;
124+}
125+
126+static struct platform_driver gw_avila_hss_driver = {
127+ .probe = gw_avila_hss_probe,
128+ .remove = gw_avila_hss_remove,
129+ .driver = {
130+ .name = "gw_avila_hss",
131+ .owner = THIS_MODULE,
132+ }
133+};
134+
135+static int __init gw_avila_hss_init(void)
136+{
137+ return platform_driver_register(&gw_avila_hss_driver);
138+}
139+module_init(gw_avila_hss_init);
140+
141+static void __exit gw_avila_hss_exit(void)
142+{
143+ platform_driver_unregister(&gw_avila_hss_driver);
144+}
145+module_exit(gw_avila_hss_exit);
146+
147+MODULE_AUTHOR("Chris Lang");
148+MODULE_DESCRIPTION("HSS Audio Driver for Gateworks Avila");
149+MODULE_LICENSE("GPL");
150--- /dev/null
151+++ b/sound/soc/gw-avila/gw-avila-hss.h
152@@ -0,0 +1,12 @@
153+/*
154+ * Author: Chris Lang <clang@gateworks.com>
155+ *
156+ * This program is free software; you can redistribute it and/or modify
157+ * it under the terms of the GNU General Public License version 2 as
158+ * published by the Free Software Foundation.
159+ */
160+
161+#ifndef _GW_AVILA_HSS_H
162+#define _GW_AVILA_HSS_H
163+
164+#endif
165--- /dev/null
166+++ b/sound/soc/gw-avila/gw-avila-pcm.c
167@@ -0,0 +1,327 @@
168+/*
169+ * ALSA PCM interface for the TI DAVINCI processor
170+ *
171+ * Author: Chris Lang, <clang@gateworks.com>
172+ * Copyright: (C) 2009 Gateworks Corporation
173+ *
174+ * Based On: davinci-evm.c, Author: Vladimir Barinov, <vbarinov@ru.mvista.com>
175+ *
176+ * This program is free software; you can redistribute it and/or modify
177+ * it under the terms of the GNU General Public License version 2 as
178+ * published by the Free Software Foundation.
179+ */
180+
181+#include <linux/module.h>
182+#include <linux/init.h>
183+#include <linux/platform_device.h>
184+#include <linux/slab.h>
185+#include <linux/dma-mapping.h>
186+
187+#include <sound/core.h>
188+#include <sound/pcm.h>
189+#include <sound/pcm_params.h>
190+#include <sound/soc.h>
191+
192+#include <asm/dma.h>
193+
194+#include "gw-avila-pcm.h"
195+#include "gw-avila-hss.h"
196+#include "ixp4xx_hss.h"
197+
198+#define GW_AVILA_PCM_DEBUG 0
199+#if GW_AVILA_PCM_DEBUG
200+#define DPRINTK(x...) printk(KERN_DEBUG x)
201+#else
202+#define DPRINTK(x...)
203+#endif
204+
205+static struct snd_pcm_hardware gw_avila_pcm_hardware = {
206+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
207+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
208+/* SNDRV_PCM_INFO_PAUSE),*/
209+ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
210+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
211+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
212+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
213+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
214+ SNDRV_PCM_RATE_KNOT),
215+ .rate_min = 8000,
216+ .rate_max = 8000,
217+ .channels_min = 2,
218+ .channels_max = 2,
219+ .buffer_bytes_max = 64 * 1024, // All of the lines below may need to be changed
220+ .period_bytes_min = 128,
221+ .period_bytes_max = 4 * 1024,
222+ .periods_min = 16,
223+ .periods_max = 32,
224+ .fifo_size = 0,
225+};
226+
227+struct gw_avila_runtime_data {
228+ spinlock_t lock;
229+ int period; /* current DMA period */
230+ int master_lch; /* Master DMA channel */
231+ int slave_lch; /* Slave DMA channel */
232+ struct gw_avila_pcm_dma_params *params; /* DMA params */
233+};
234+
235+static void gw_avila_dma_irq(void *data)
236+{
237+ struct snd_pcm_substream *substream = data;
238+ snd_pcm_period_elapsed(substream);
239+}
240+
241+static int gw_avila_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
242+{
243+ struct snd_pcm_runtime *runtime = substream->runtime;
244+ struct hss_device *hdev = runtime->private_data;
245+ int ret = 0;
246+
247+ switch (cmd) {
248+ case SNDRV_PCM_TRIGGER_START:
249+ case SNDRV_PCM_TRIGGER_RESUME:
250+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
251+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
252+ hss_tx_start(hdev);
253+ else
254+ hss_rx_start(hdev);
255+ break;
256+ case SNDRV_PCM_TRIGGER_STOP:
257+ case SNDRV_PCM_TRIGGER_SUSPEND:
258+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
259+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
260+ hss_tx_stop(hdev);
261+ else
262+ hss_rx_stop(hdev);
263+ break;
264+ default:
265+ ret = -EINVAL;
266+ break;
267+ }
268+ return ret;
269+}
270+
271+static int gw_avila_pcm_prepare(struct snd_pcm_substream *substream)
272+{
273+ struct snd_pcm_runtime *runtime = substream->runtime;
274+ struct hss_device *hdev = runtime->private_data;
275+
276+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
277+ hss_set_tx_callback(hdev, gw_avila_dma_irq, substream);
278+ hss_config_tx_dma(hdev, runtime->dma_area, runtime->buffer_size, runtime->period_size);
279+ } else {
280+ hss_set_rx_callback(hdev, gw_avila_dma_irq, substream);
281+ hss_config_rx_dma(hdev, runtime->dma_area, runtime->buffer_size, runtime->period_size);
282+ }
283+
284+ return 0;
285+}
286+
287+static snd_pcm_uframes_t
288+gw_avila_pcm_pointer(struct snd_pcm_substream *substream)
289+{
290+ struct snd_pcm_runtime *runtime = substream->runtime;
291+ struct hss_device *hdev = runtime->private_data;
292+
293+ unsigned int curr = 0;
294+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
295+ curr = hss_curr_offset_tx(hdev);
296+ else
297+ curr = hss_curr_offset_rx(hdev);
298+ return curr;
299+}
300+
301+static int gw_avila_pcm_open(struct snd_pcm_substream *substream)
302+{
303+ struct snd_pcm_runtime *runtime = substream->runtime;
304+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
305+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
306+
307+ snd_soc_set_runtime_hwparams(substream, &gw_avila_pcm_hardware);
308+
309+ if (hss_handle[cpu_dai->id] != NULL)
310+ runtime->private_data = hss_handle[cpu_dai->id];
311+ else {
312+ pr_err("hss_handle is NULL\n");
313+ return -1;
314+ }
315+
316+ hss_chan_open(hss_handle[cpu_dai->id]);
317+
318+ return 0;
319+}
320+
321+static int gw_avila_pcm_close(struct snd_pcm_substream *substream)
322+{
323+ struct snd_pcm_runtime *runtime = substream->runtime;
324+ struct hss_device *hdev = runtime->private_data;
325+
326+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
327+ memset(hdev->tx_buf, 0, runtime->buffer_size);
328+ } else
329+ memset(hdev->rx_buf, 0, runtime->buffer_size);
330+
331+ hss_chan_close(hdev);
332+
333+ return 0;
334+}
335+
336+static int gw_avila_pcm_hw_params(struct snd_pcm_substream *substream,
337+ struct snd_pcm_hw_params *hw_params)
338+{
339+ return snd_pcm_lib_malloc_pages(substream,
340+ params_buffer_bytes(hw_params));
341+}
342+
343+static int gw_avila_pcm_hw_free(struct snd_pcm_substream *substream)
344+{
345+ struct snd_pcm_runtime *runtime = substream->runtime;
346+
347+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
348+ memset(runtime->dma_area, 0, runtime->buffer_size);
349+
350+ return snd_pcm_lib_free_pages(substream);
351+}
352+
353+static int gw_avila_pcm_mmap(struct snd_pcm_substream *substream,
354+ struct vm_area_struct *vma)
355+{
356+ struct snd_pcm_runtime *runtime = substream->runtime;
357+
358+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
359+ runtime->dma_area,
360+ runtime->dma_addr,
361+ runtime->dma_bytes);
362+}
363+
364+struct snd_pcm_ops gw_avila_pcm_ops = {
365+ .open = gw_avila_pcm_open,
366+ .close = gw_avila_pcm_close,
367+ .ioctl = snd_pcm_lib_ioctl,
368+ .hw_params = gw_avila_pcm_hw_params,
369+ .hw_free = gw_avila_pcm_hw_free,
370+ .prepare = gw_avila_pcm_prepare,
371+ .trigger = gw_avila_pcm_trigger,
372+ .pointer = gw_avila_pcm_pointer,
373+ .mmap = gw_avila_pcm_mmap,
374+};
375+
376+static int gw_avila_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
377+{
378+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
379+ struct snd_dma_buffer *buf = &substream->dma_buffer;
380+ size_t size = gw_avila_pcm_hardware.buffer_bytes_max;
381+
382+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
383+ buf->dev.dev = pcm->card->dev;
384+ buf->private_data = NULL;
385+
386+ buf->area = dma_alloc_coherent(pcm->card->dev, size,
387+ &buf->addr, GFP_KERNEL);
388+
389+ if (!buf->area) {
390+ return -ENOMEM;
391+ }
392+
393+ memset(buf->area, 0xff, size);
394+
395+ DPRINTK("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
396+ (void *) buf->area, (void *) buf->addr, size);
397+
398+ buf->bytes = size;
399+
400+ return 0;
401+}
402+
403+static void gw_avila_pcm_free(struct snd_pcm *pcm)
404+{
405+ struct snd_pcm_substream *substream;
406+ struct snd_dma_buffer *buf;
407+ int stream;
408+
409+ for (stream = 0; stream < 2; stream++) {
410+ substream = pcm->streams[stream].substream;
411+ if (!substream)
412+ continue;
413+
414+ buf = &substream->dma_buffer;
415+ if (!buf->area)
416+ continue;
417+
418+ dma_free_coherent(NULL, buf->bytes, buf->area, 0);
419+ buf->area = NULL;
420+ }
421+}
422+
423+static u64 gw_avila_pcm_dmamask = 0xFFFFFFFF;
424+
425+static int gw_avila_pcm_new(struct snd_soc_pcm_runtime *rtd)
426+{
427+ struct snd_card *card = rtd->card->snd_card;
428+ struct snd_pcm *pcm = rtd->pcm;
429+ struct snd_soc_dai *dai = rtd->codec_dai;
430+ int ret;
431+
432+ if (!card->dev->dma_mask)
433+ card->dev->dma_mask = &gw_avila_pcm_dmamask;
434+ if (!card->dev->coherent_dma_mask)
435+ card->dev->coherent_dma_mask = 0xFFFFFFFF;
436+
437+ if (dai->driver->playback.channels_min) {
438+ ret = gw_avila_pcm_preallocate_dma_buffer(pcm,
439+ SNDRV_PCM_STREAM_PLAYBACK);
440+ if (ret)
441+ return ret;
442+ }
443+
444+ if (dai->driver->capture.channels_min) {
445+ ret = gw_avila_pcm_preallocate_dma_buffer(pcm,
446+ SNDRV_PCM_STREAM_CAPTURE);
447+ if (ret)
448+ return ret;
449+ }
450+
451+ return 0;
452+}
453+
454+struct snd_soc_platform_driver gw_avila_soc_platform = {
455+ .ops = &gw_avila_pcm_ops,
456+ .pcm_new = gw_avila_pcm_new,
457+ .pcm_free = gw_avila_pcm_free,
458+};
459+
460+static int __devinit gw_avila_pcm_platform_probe(struct platform_device *pdev)
461+{
462+ return snd_soc_register_platform(&pdev->dev, &gw_avila_soc_platform);
463+}
464+
465+static int __devexit gw_avila_pcm_platform_remove(struct platform_device *pdev)
466+{
467+ snd_soc_unregister_platform(&pdev->dev);
468+ return 0;
469+}
470+
471+static struct platform_driver gw_avila_pcm_driver = {
472+ .driver = {
473+ .name = "gw_avila-audio",
474+ .owner = THIS_MODULE,
475+ },
476+ .probe = gw_avila_pcm_platform_probe,
477+ .remove = __devexit_p(gw_avila_pcm_platform_remove),
478+};
479+
480+static int __init gw_avila_soc_platform_init(void)
481+{
482+ return platform_driver_register(&gw_avila_pcm_driver);
483+}
484+module_init(gw_avila_soc_platform_init);
485+
486+static void __exit gw_avila_soc_platform_exit(void)
487+{
488+ platform_driver_unregister(&gw_avila_pcm_driver);
489+}
490+module_exit(gw_avila_soc_platform_exit);
491+
492+MODULE_AUTHOR("Chris Lang");
493+MODULE_DESCRIPTION("Gateworks Avila PCM DMA module");
494+MODULE_LICENSE("GPL");
495--- /dev/null
496+++ b/sound/soc/gw-avila/gw-avila-pcm.h
497@@ -0,0 +1,32 @@
498+/*
499+ * ALSA PCM interface for the Gateworks Avila platform
500+ *
501+ * Author: Chris Lang, <clang@gateworks.com>
502+ * Copyright: (C) 2009 Gateworks Corporation
503+ *
504+ * Based On: davinci-evm.c, Author: Vladimir Barinov, <vbarinov@ru.mvista.com>
505+ *
506+ * This program is free software; you can redistribute it and/or modify
507+ * it under the terms of the GNU General Public License version 2 as
508+ * published by the Free Software Foundation.
509+ */
510+
511+#ifndef _GW_AVILA_PCM_H
512+#define _GW_AVILA_PCM_H
513+
514+#if 0
515+struct gw_avila_pcm_dma_params {
516+ char *name; /* stream identifier */
517+ int channel; /* sync dma channel ID */
518+ dma_addr_t dma_addr; /* device physical address for DMA */
519+ unsigned int data_type; /* xfer data type */
520+};
521+
522+struct gw_avila_snd_platform_data {
523+ int tx_dma_ch; // XXX Do we need this?
524+ int rx_dma_ch; // XXX Do we need this
525+};
526+extern struct snd_soc_platform gw_avila_soc_platform[];
527+#endif
528+
529+#endif
530--- /dev/null
531+++ b/sound/soc/gw-avila/gw-avila.c
532@@ -0,0 +1,244 @@
533+/*
534+ * File: sound/soc/gw-avila/gw_avila.c
535+ * Author: Chris Lang <clang@gateworks.com>
536+ *
537+ * Created: Tue June 06 2008
538+ * Description: Board driver for Gateworks Avila
539+ *
540+ * Modified:
541+ * Copyright 2009 Gateworks Corporation
542+ *
543+ * Bugs: What Bugs?
544+ *
545+ * This program is free software; you can redistribute it and/or modify
546+ * it under the terms of the GNU General Public License as published by
547+ * the Free Software Foundation; either version 2 of the License, or
548+ * (at your option) any later version.
549+ *
550+ * This program is distributed in the hope that it will be useful,
551+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
552+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
553+ * GNU General Public License for more details.
554+ *
555+ * You should have received a copy of the GNU General Public License
556+ * along with this program; if not, see the file COPYING, or write
557+ * to the Free Software Foundation, Inc.,
558+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
559+ */
560+
561+#include <linux/module.h>
562+#include <linux/moduleparam.h>
563+#include <linux/device.h>
564+#include <asm/dma.h>
565+#include <linux/platform_device.h>
566+#include <sound/core.h>
567+#include <sound/pcm.h>
568+#include <sound/soc.h>
569+#include <linux/slab.h>
570+#include <linux/gpio.h>
571+
572+#include "ixp4xx_hss.h"
573+#include "gw-avila-hss.h"
574+#include "gw-avila-pcm.h"
575+
576+#define CODEC_FREQ 33333000
577+
578+static int gw_avila_board_startup(struct snd_pcm_substream *substream)
579+{
580+ pr_debug("%s enter\n", __func__);
581+ return 0;
582+}
583+
584+static int gw_avila_hw_params(struct snd_pcm_substream *substream,
585+ struct snd_pcm_hw_params *params)
586+{
587+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
588+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
589+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
590+
591+ int ret = 0;
592+
593+ /* set codec DAI configuration */
594+ if (cpu_dai->id % 2) {
595+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS);
596+ snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 1, 32);
597+ } else {
598+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM);
599+ snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 0, 32);
600+ }
601+
602+ if (ret < 0)
603+ return ret;
604+
605+ /* set the codec system clock */
606+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_FREQ, SND_SOC_CLOCK_OUT);
607+ if (ret < 0)
608+ return ret;
609+
610+ return 0;
611+}
612+
613+static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
614+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
615+ SND_SOC_DAPM_LINE("Line Out", NULL),
616+ SND_SOC_DAPM_LINE("Line In", NULL),
617+};
618+
619+static const struct snd_soc_dapm_route audio_map[] = {
620+ {"Headphone Jack", NULL, "HPLOUT"},
621+ {"Headphone Jack", NULL, "HPROUT"},
622+
623+ /* Line Out connected to LLOUT, RLOUT */
624+ {"Line Out", NULL, "LLOUT"},
625+ {"Line Out", NULL, "RLOUT"},
626+
627+ /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
628+ {"LINE1L", NULL, "Line In"},
629+ {"LINE1R", NULL, "Line In"},
630+};
631+
632+/* Logic for a aic3x as connected on a davinci-evm */
633+static int avila_aic3x_init(struct snd_soc_pcm_runtime *rtd)
634+{
635+ struct snd_soc_codec *codec = rtd->codec;
636+ struct snd_soc_dapm_context *dapm = &codec->dapm;
637+
638+ /* Add davinci-evm specific widgets */
639+ snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
640+ ARRAY_SIZE(aic3x_dapm_widgets));
641+
642+ /* Set up davinci-evm specific audio path audio_map */
643+ snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
644+
645+ /* not connected */
646+ snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
647+ //snd_soc_dapm_disable_pin(dapm, "HPLCOM");
648+ //snd_soc_dapm_disable_pin(dapm, "HPRCOM");
649+ snd_soc_dapm_disable_pin(dapm, "MIC3L");
650+ snd_soc_dapm_disable_pin(dapm, "MIC3R");
651+ snd_soc_dapm_disable_pin(dapm, "LINE2L");
652+ snd_soc_dapm_disable_pin(dapm, "LINE2R");
653+
654+ /* always connected */
655+ snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
656+ snd_soc_dapm_enable_pin(dapm, "Line Out");
657+ snd_soc_dapm_enable_pin(dapm, "Line In");
658+
659+ snd_soc_dapm_sync(dapm);
660+
661+ return 0;
662+}
663+
664+static struct snd_soc_ops gw_avila_board_ops = {
665+ .startup = gw_avila_board_startup,
666+ .hw_params = gw_avila_hw_params,
667+};
668+
669+static struct snd_soc_dai_link gw_avila_board_dai[] = {
670+ {
671+ .name = "HSS-0",
672+ .stream_name = "HSS-0",
673+ .cpu_dai_name = "gw_avila_hss.0",
674+ .codec_dai_name = "tlv320aic3x-hifi",
675+ .codec_name = "tlv320aic3x-codec.0-001b",
676+ .platform_name = "gw_avila-audio.0",
677+ .init = avila_aic3x_init,
678+ .ops = &gw_avila_board_ops,
679+ },{
680+ .name = "HSS-1",
681+ .stream_name = "HSS-1",
682+ .cpu_dai_name = "gw_avila_hss.1",
683+ .codec_dai_name = "tlv320aic3x-hifi",
684+ .codec_name = "tlv320aic3x-codec.0-001a",
685+ .platform_name = "gw_avila-audio.1",
686+ .init = avila_aic3x_init,
687+ .ops = &gw_avila_board_ops,
688+ },{
689+ .name = "HSS-2",
690+ .stream_name = "HSS-2",
691+ .cpu_dai_name = "gw_avila_hss.2",
692+ .codec_dai_name = "tlv320aic3x-hifi",
693+ .codec_name = "tlv320aic3x-codec.0-0019",
694+ .platform_name = "gw_avila-audio.2",
695+ .init = avila_aic3x_init,
696+ .ops = &gw_avila_board_ops,
697+ },{
698+ .name = "HSS-3",
699+ .stream_name = "HSS-3",
700+ .cpu_dai_name = "gw_avila_hss.3",
701+ .codec_dai_name = "tlv320aic3x-hifi",
702+ .codec_name = "tlv320aic3x-codec.0-0018",
703+ .platform_name = "gw_avila-audio.3",
704+ .init = avila_aic3x_init,
705+ .ops = &gw_avila_board_ops,
706+ },
707+};
708+
709+static struct snd_soc_card gw_avila_board[] = {
710+ {
711+ .name = "gw_avila-board.0",
712+ .owner = THIS_MODULE,
713+ .dai_link = &gw_avila_board_dai[0],
714+ .num_links = 1,
715+ },{
716+ .name = "gw_avila-board.1",
717+ .owner = THIS_MODULE,
718+ .dai_link = &gw_avila_board_dai[1],
719+ .num_links = 1,
720+ },{
721+ .name = "gw_avila-board.2",
722+ .owner = THIS_MODULE,
723+ .dai_link = &gw_avila_board_dai[2],
724+ .num_links = 1,
725+ },{
726+ .name = "gw_avila-board.3",
727+ .owner = THIS_MODULE,
728+ .dai_link = &gw_avila_board_dai[3],
729+ .num_links = 1,
730+ }
731+};
732+
733+static struct platform_device *gw_avila_board_snd_device[4];
734+
735+static int __init gw_avila_board_init(void)
736+{
737+ int ret;
738+ struct port *port;
739+ int i;
740+
741+ if ((hss_port[0] = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL)
742+ return -ENOMEM;
743+
744+ if ((hss_port[1] = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL)
745+ return -ENOMEM;
746+
747+ for (i = 0; i < 4; i++) {
748+ gw_avila_board_snd_device[i] = platform_device_alloc("soc-audio", i);
749+ if (!gw_avila_board_snd_device[i]) {
750+ return -ENOMEM;
751+ }
752+
753+ platform_set_drvdata(gw_avila_board_snd_device[i], &gw_avila_board[i]);
754+ ret = platform_device_add(gw_avila_board_snd_device[i]);
755+
756+ if (ret) {
757+ platform_device_put(gw_avila_board_snd_device[i]);
758+ }
759+ }
760+ return ret;
761+}
762+
763+static void __exit gw_avila_board_exit(void)
764+{
765+ int i;
766+ for (i = 0; i < 4; i++)
767+ platform_device_unregister(gw_avila_board_snd_device[i]);
768+}
769+
770+module_init(gw_avila_board_init);
771+module_exit(gw_avila_board_exit);
772+
773+/* Module information */
774+MODULE_AUTHOR("Chris Lang");
775+MODULE_DESCRIPTION("ALSA SoC HSS Audio gw_avila board");
776+MODULE_LICENSE("GPL");
777--- /dev/null
778+++ b/sound/soc/gw-avila/ixp4xx_hss.c
779@@ -0,0 +1,902 @@
780+/*
781+ * Intel IXP4xx HSS (synchronous serial port) driver for Linux
782+ *
783+ * Copyright (C) 2009 Chris Lang <clang@gateworks.com>
784+ *
785+ * This program is free software; you can redistribute it and/or modify it
786+ * under the terms of version 2 of the GNU General Public License
787+ * as published by the Free Software Foundation.
788+ */
789+
790+#include <linux/module.h>
791+#include <linux/bitops.h>
792+#include <linux/cdev.h>
793+#include <linux/dma-mapping.h>
794+#include <linux/dmapool.h>
795+#include <linux/fs.h>
796+#include <linux/io.h>
797+#include <linux/kernel.h>
798+#include <linux/platform_device.h>
799+#include <linux/poll.h>
800+#include <linux/slab.h>
801+#include <linux/delay.h>
802+
803+#include <mach/npe.h>
804+#include <mach/qmgr.h>
805+
806+#include "ixp4xx_hss.h"
807+
808+/*****************************************************************************
809+ * global variables
810+ ****************************************************************************/
811+
812+void hss_chan_read(unsigned long data);
813+static char lock_init = 0;
814+static spinlock_t npe_lock;
815+static struct npe *npe;
816+
817+static const struct {
818+ int tx, txdone, rx, rxfree, chan;
819+}queue_ids[2] = {{HSS0_PKT_TX0_QUEUE, HSS0_PKT_TXDONE_QUEUE, HSS0_PKT_RX_QUEUE,
820+ HSS0_PKT_RXFREE0_QUEUE, HSS0_CHL_RXTRIG_QUEUE},
821+ {HSS1_PKT_TX0_QUEUE, HSS1_PKT_TXDONE_QUEUE, HSS1_PKT_RX_QUEUE,
822+ HSS1_PKT_RXFREE0_QUEUE, HSS1_CHL_RXTRIG_QUEUE},
823+};
824+
825+struct port *hss_port[2];
826+struct hss_device *hss_handle[32];
827+EXPORT_SYMBOL(hss_handle);
828+
829+/*****************************************************************************
830+ * utility functions
831+ ****************************************************************************/
832+
833+#ifndef __ARMEB__
834+static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
835+{
836+ int i;
837+ for (i = 0; i < cnt; i++)
838+ dest[i] = swab32(src[i]);
839+}
840+#endif
841+
842+static inline unsigned int sub_offset(unsigned int a, unsigned int b,
843+ unsigned int modulo)
844+{
845+ return (modulo /* make sure the result >= 0 */ + a - b) % modulo;
846+}
847+
848+/*****************************************************************************
849+ * HSS access
850+ ****************************************************************************/
851+
852+static void hss_config_load(struct port *port)
853+{
854+ struct msg msg;
855+
856+ do {
857+ memset(&msg, 0, sizeof(msg));
858+ msg.cmd = PORT_CONFIG_LOAD;
859+ msg.hss_port = port->id;
860+ if (npe_send_message(npe, &msg, "HSS_LOAD_CONFIG"))
861+ break;
862+ if (npe_recv_message(npe, &msg, "HSS_LOAD_CONFIG"))
863+ break;
864+
865+ /* HSS_LOAD_CONFIG for port #1 returns port_id = #4 */
866+ if (msg.cmd != PORT_CONFIG_LOAD || msg.data32)
867+ break;
868+
869+ /* HDLC may stop working without this */
870+ npe_recv_message(npe, &msg, "FLUSH_IT");
871+ return;
872+ } while (0);
873+
874+ printk(KERN_CRIT "HSS-%i: unable to reload HSS configuration\n",
875+ port->id);
876+ BUG();
877+}
878+
879+static void hss_config_set_pcr(struct port *port)
880+{
881+ struct msg msg;
882+
883+ do {
884+ memset(&msg, 0, sizeof(msg));
885+ msg.cmd = PORT_CONFIG_WRITE;
886+ msg.hss_port = port->id;
887+ msg.index = HSS_CONFIG_TX_PCR;
888+#if 0
889+ msg.data32 = PCR_FRM_SYNC_RISINGEDGE | PCR_MSB_ENDIAN |
890+ PCR_TX_DATA_ENABLE | PCR_TX_UNASS_HIGH_IMP | PCR_TX_V56K_HIGH_IMP | PCR_TX_FB_HIGH_IMP;
891+#else
892+ msg.data32 = PCR_FRM_SYNC_RISINGEDGE | PCR_MSB_ENDIAN |
893+ PCR_TX_DATA_ENABLE | PCR_TX_FB_HIGH_IMP | PCR_DCLK_EDGE_RISING;
894+#endif
895+ if (port->frame_size % 8 == 0)
896+ msg.data32 |= PCR_SOF_NO_FBIT;
897+
898+ if (npe_send_message(npe, &msg, "HSS_SET_TX_PCR"))
899+ break;
900+
901+ msg.index = HSS_CONFIG_RX_PCR;
902+ msg.data32 &= ~ (PCR_DCLK_EDGE_RISING | PCR_FCLK_EDGE_RISING | PCR_TX_DATA_ENABLE);
903+
904+ if (npe_send_message(npe, &msg, "HSS_SET_RX_PCR"))
905+ break;
906+ return;
907+ } while (0);
908+
909+ printk(KERN_CRIT "HSS-%i: unable to set HSS PCR registers\n", port->id);
910+ BUG();
911+}
912+
913+static void hss_config_set_core(struct port *port)
914+{
915+ struct msg msg;
916+
917+ memset(&msg, 0, sizeof(msg));
918+ msg.cmd = PORT_CONFIG_WRITE;
919+ msg.hss_port = port->id;
920+ msg.index = HSS_CONFIG_CORE_CR;
921+#if 0
922+ msg.data32 = 0 | CCR_LOOPBACK |
923+ (port->id ? CCR_SECOND_HSS : 0);
924+#else
925+ msg.data32 = 0 |
926+ (port->id ? CCR_SECOND_HSS : 0);
927+#endif
928+ if (npe_send_message(npe, &msg, "HSS_SET_CORE_CR")) {
929+ printk(KERN_CRIT "HSS-%i: unable to set HSS core control"
930+ " register\n", port->id);
931+ BUG();
932+ }
933+}
934+
935+static void hss_config_set_line(struct port *port)
936+{
937+ struct msg msg;
938+
939+ hss_config_set_pcr(port);
940+ hss_config_set_core(port);
941+
942+ memset(&msg, 0, sizeof(msg));
943+ msg.cmd = PORT_CONFIG_WRITE;
944+ msg.hss_port = port->id;
945+ msg.index = HSS_CONFIG_CLOCK_CR;
946+ msg.data32 = CLK42X_SPEED_8192KHZ /* FIXME */;
947+ if (npe_send_message(npe, &msg, "HSS_SET_CLOCK_CR")) {
948+ printk(KERN_CRIT "HSS-%i: unable to set HSS clock control"
949+ " register\n", port->id);
950+ BUG();
951+ }
952+}
953+
954+static void hss_config_set_rx_frame(struct port *port)
955+{
956+ struct msg msg;
957+
958+ memset(&msg, 0, sizeof(msg));
959+ msg.cmd = PORT_CONFIG_WRITE;
960+ msg.hss_port = port->id;
961+ msg.index = HSS_CONFIG_RX_FCR;
962+ msg.data16a = port->frame_sync_offset;
963+ msg.data16b = port->frame_size - 1;
964+ if (npe_send_message(npe, &msg, "HSS_SET_RX_FCR")) {
965+ printk(KERN_CRIT "HSS-%i: unable to set HSS RX frame size"
966+ " and offset\n", port->id);
967+ BUG();
968+ }
969+}
970+
971+static void hss_config_set_frame(struct port *port)
972+{
973+ struct msg msg;
974+
975+ memset(&msg, 0, sizeof(msg));
976+ msg.cmd = PORT_CONFIG_WRITE;
977+ msg.hss_port = port->id;
978+ msg.index = HSS_CONFIG_TX_FCR;
979+ msg.data16a = TX_FRAME_SYNC_OFFSET;
980+ msg.data16b = port->frame_size - 1;
981+ if (npe_send_message(npe, &msg, "HSS_SET_TX_FCR")) {
982+ printk(KERN_CRIT "HSS-%i: unable to set HSS TX frame size"
983+ " and offset\n", port->id);
984+ BUG();
985+ }
986+ hss_config_set_rx_frame(port);
987+}
988+
989+static void hss_config_set_lut(struct port *port)
990+{
991+ struct msg msg;
992+ int chan_count = 32;
993+
994+ memset(&msg, 0, sizeof(msg));
995+ msg.cmd = PORT_CONFIG_WRITE;
996+ msg.hss_port = port->id;
997+
998+ msg.index = HSS_CONFIG_TX_LUT;
999+ msg.data32 = 0xffffffff;
1000+ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
1001+ msg.index += 4;
1002+ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
1003+ msg.data32 = 0x0;
1004+ msg.index += 4;
1005+ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
1006+ msg.index += 4;
1007+ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
1008+ msg.index += 4;
1009+ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
1010+ msg.index += 4;
1011+ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
1012+ msg.index += 4;
1013+ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
1014+ msg.index += 4;
1015+ npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
1016+
1017+ msg.index = HSS_CONFIG_RX_LUT;
1018+ msg.data32 = 0xffffffff;
1019+ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
1020+ msg.index += 4;
1021+ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
1022+ msg.data32 = 0x0;
1023+ msg.index += 4;
1024+ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
1025+ msg.index += 4;
1026+ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
1027+ msg.index += 4;
1028+ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
1029+ msg.index += 4;
1030+ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
1031+ msg.index += 4;
1032+ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
1033+ msg.index += 4;
1034+ npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
1035+
1036+ hss_config_set_frame(port);
1037+
1038+ memset(&msg, 0, sizeof(msg));
1039+ msg.cmd = CHAN_NUM_CHANS_WRITE;
1040+ msg.hss_port = port->id;
1041+ msg.data8a = chan_count;
1042+ if (npe_send_message(npe, &msg, "CHAN_NUM_CHANS_WRITE")) {
1043+ printk(KERN_CRIT "HSS-%i: unable to set HSS channel count\n",
1044+ port->id);
1045+ BUG();
1046+ }
1047+}
1048+
1049+static u32 hss_config_get_status(struct port *port)
1050+{
1051+ struct msg msg;
1052+
1053+ do {
1054+ memset(&msg, 0, sizeof(msg));
1055+ msg.cmd = PORT_ERROR_READ;
1056+ msg.hss_port = port->id;
1057+ if (npe_send_message(npe, &msg, "PORT_ERROR_READ"))
1058+ break;
1059+ if (npe_recv_message(npe, &msg, "PORT_ERROR_READ"))
1060+ break;
1061+
1062+ return msg.data32;
1063+ } while (0);
1064+
1065+ printk(KERN_CRIT "HSS-%i: unable to read HSS status\n", port->id);
1066+ BUG();
1067+}
1068+
1069+static void hss_config_start_chan(struct port *port)
1070+{
1071+ struct msg msg;
1072+
1073+ port->chan_last_tx = 0;
1074+ port->chan_last_rx = 0;
1075+
1076+ do {
1077+ memset(&msg, 0, sizeof(msg));
1078+ msg.cmd = CHAN_RX_BUF_ADDR_WRITE;
1079+ msg.hss_port = port->id;
1080+ msg.data32 = port->chan_rx_buf_phys;
1081+ if (npe_send_message(npe, &msg, "CHAN_RX_BUF_ADDR_WRITE"))
1082+ break;
1083+
1084+ memset(&msg, 0, sizeof(msg));
1085+ msg.cmd = CHAN_TX_BUF_ADDR_WRITE;
1086+ msg.hss_port = port->id;
1087+ msg.data32 = port->chan_tx_pointers_phys;
1088+ if (npe_send_message(npe, &msg, "CHAN_TX_BUF_ADDR_WRITE"))
1089+ break;
1090+
1091+ memset(&msg, 0, sizeof(msg));
1092+ msg.cmd = CHAN_FLOW_ENABLE;
1093+ msg.hss_port = port->id;
1094+ if (npe_send_message(npe, &msg, "CHAN_FLOW_ENABLE"))
1095+ break;
1096+ port->chan_started = 1;
1097+ return;
1098+ } while (0);
1099+
1100+ printk(KERN_CRIT "HSS-%i: unable to start channelized flow\n",
1101+ port->id);
1102+ BUG();
1103+}
1104+
1105+static void hss_config_stop_chan(struct port *port)
1106+{
1107+ struct msg msg;
1108+
1109+ if (!port->chan_started)
1110+ return;
1111+
1112+ memset(&msg, 0, sizeof(msg));
1113+ msg.cmd = CHAN_FLOW_DISABLE;
1114+ msg.hss_port = port->id;
1115+ if (npe_send_message(npe, &msg, "CHAN_FLOW_DISABLE")) {
1116+ printk(KERN_CRIT "HSS-%i: unable to stop channelized flow\n",
1117+ port->id);
1118+ BUG();
1119+ }
1120+ hss_config_get_status(port); /* make sure it's halted */
1121+ port->chan_started = 0;
1122+}
1123+
1124+static int hss_config_load_firmware(struct port *port)
1125+{
1126+ struct msg msg;
1127+
1128+ if (port->initialized)
1129+ return 0;
1130+
1131+ if (!npe_running(npe)) {
1132+ int err;
1133+ if ((err = npe_load_firmware(npe, "NPE-A-HSS",
1134+ port->dev)))
1135+ return err;
1136+ }
1137+
1138+ do {
1139+ /* HSS main configuration */
1140+ hss_config_set_line(port);
1141+
1142+ hss_config_set_frame(port);
1143+
1144+ /* Channelized operation settings */
1145+ memset(&msg, 0, sizeof(msg));
1146+ msg.cmd = CHAN_TX_BLK_CFG_WRITE;
1147+ msg.hss_port = port->id;
1148+ msg.data8b = (CHAN_TX_LIST_FRAMES & ~7) / 2;
1149+ msg.data8a = msg.data8b / 4;
1150+ msg.data8d = CHAN_TX_LIST_FRAMES - msg.data8b;
1151+ msg.data8c = msg.data8d / 4;
1152+ if (npe_send_message(npe, &msg, "CHAN_TX_BLK_CFG_WRITE"))
1153+ break;
1154+
1155+ memset(&msg, 0, sizeof(msg));
1156+ msg.cmd = CHAN_RX_BUF_CFG_WRITE;
1157+ msg.hss_port = port->id;
1158+ msg.data8a = CHAN_RX_TRIGGER / 8;
1159+ msg.data8b = CHAN_RX_FRAMES;
1160+ if (npe_send_message(npe, &msg, "CHAN_RX_BUF_CFG_WRITE"))
1161+ break;
1162+
1163+ memset(&msg, 0, sizeof(msg));
1164+ msg.cmd = CHAN_TX_BUF_SIZE_WRITE;
1165+ msg.hss_port = port->id;
1166+ msg.data8a = CHAN_TX_LISTS;
1167+ if (npe_send_message(npe, &msg, "CHAN_TX_BUF_SIZE_WRITE"))
1168+ break;
1169+
1170+ port->initialized = 1;
1171+ return 0;
1172+ } while (0);
1173+
1174+ printk(KERN_CRIT "HSS-%i: unable to start HSS operation\n", port->id);
1175+ BUG();
1176+}
1177+
1178+void hss_chan_irq(void *pdev)
1179+{
1180+ struct port *port = pdev;
1181+
1182+ qmgr_disable_irq(queue_ids[port->id].chan);
1183+
1184+ tasklet_hi_schedule(&port->task);
1185+}
1186+
1187+
1188+int hss_prepare_chan(struct port *port)
1189+{
1190+ int err, i, j;
1191+ u32 *temp;
1192+ u32 temp2;
1193+ u8 *temp3;
1194+
1195+ if (port->initialized)
1196+ return 0;
1197+
1198+ if ((err = hss_config_load_firmware(port)))
1199+ return err;
1200+
1201+ if ((err = qmgr_request_queue(queue_ids[port->id].chan,
1202+ CHAN_QUEUE_LEN, 0, 0, "%s:hss", "hss")))
1203+ return err;
1204+
1205+ port->chan_tx_buf = dma_alloc_coherent(port->dev, chan_tx_buf_len(port), &port->chan_tx_buf_phys, GFP_DMA);
1206+ memset(port->chan_tx_buf, 0, chan_tx_buf_len(port));
1207+
1208+ port->chan_tx_pointers = dma_alloc_coherent(port->dev, chan_tx_buf_len(port) / CHAN_TX_LIST_FRAMES * 4, &port->chan_tx_pointers_phys, GFP_DMA);
1209+
1210+ temp3 = port->chan_tx_buf;
1211+ for (i = 0; i < CHAN_TX_LISTS; i++) {
1212+ for (j = 0; j < 8; j++) {
1213+ port->tx_lists[i][j] = temp3;
1214+ temp3 += CHAN_TX_LIST_FRAMES * 4;
1215+ }
1216+ }
1217+
1218+ temp = port->chan_tx_pointers;
1219+ temp2 = port->chan_tx_buf_phys;
1220+ for (i = 0; i < CHAN_TX_LISTS; i++)
1221+ {
1222+ for (j = 0; j < 32; j++)
1223+ {
1224+ *temp = temp2;
1225+ temp2 += CHAN_TX_LIST_FRAMES;
1226+ temp++;
1227+ }
1228+ }
1229+
1230+ port->chan_rx_buf = dma_alloc_coherent(port->dev, chan_rx_buf_len(port), &port->chan_rx_buf_phys, GFP_DMA);
1231+
1232+ for (i = 0; i < 8; i++) {
1233+ temp3 = port->chan_rx_buf + (i * 4 * 128);
1234+ for (j = 0; j < 8; j++) {
1235+ port->rx_frames[i][j] = temp3;
1236+ temp3 += CHAN_RX_TRIGGER;
1237+ }
1238+ }
1239+
1240+ qmgr_set_irq(queue_ids[port->id].chan, QUEUE_IRQ_SRC_NOT_EMPTY,
1241+ hss_chan_irq, port);
1242+
1243+ return 0;
1244+
1245+}
1246+
1247+int hss_tx_start(struct hss_device *hdev)
1248+{
1249+ unsigned long flags;
1250+ struct port *port = hdev->port;
1251+
1252+ hdev->tx_loc = 0;
1253+ hdev->tx_frame = 0;
1254+
1255+ set_bit((1 << hdev->id), &port->chan_tx_bitmap);
1256+
1257+ if (!port->chan_started)
1258+ {
1259+ qmgr_enable_irq(queue_ids[port->id].chan);
1260+ spin_lock_irqsave(&npe_lock, flags);
1261+ hss_config_start_chan(port);
1262+ spin_unlock_irqrestore(&npe_lock, flags);
1263+ hss_chan_irq(port);
1264+ }
1265+
1266+ return 0;
1267+}
1268+EXPORT_SYMBOL(hss_tx_start);
1269+
1270+int hss_rx_start(struct hss_device *hdev)
1271+{
1272+ unsigned long flags;
1273+ struct port *port = hdev->port;
1274+
1275+ hdev->rx_loc = 0;
1276+ hdev->rx_frame = 0;
1277+
1278+ set_bit((1 << hdev->id), &port->chan_rx_bitmap);
1279+
1280+ if (!port->chan_started)
1281+ {
1282+ qmgr_enable_irq(queue_ids[port->id].chan);
1283+ spin_lock_irqsave(&npe_lock, flags);
1284+ hss_config_start_chan(port);
1285+ spin_unlock_irqrestore(&npe_lock, flags);
1286+ hss_chan_irq(port);
1287+ }
1288+
1289+ return 0;
1290+}
1291+EXPORT_SYMBOL(hss_rx_start);
1292+
1293+int hss_tx_stop(struct hss_device *hdev)
1294+{
1295+ struct port *port = hdev->port;
1296+
1297+ clear_bit((1 << hdev->id), &port->chan_tx_bitmap);
1298+
1299+ return 0;
1300+}
1301+EXPORT_SYMBOL(hss_tx_stop);
1302+
1303+int hss_rx_stop(struct hss_device *hdev)
1304+{
1305+ struct port *port = hdev->port;
1306+
1307+ clear_bit((1 << hdev->id), &port->chan_rx_bitmap);
1308+
1309+ return 0;
1310+}
1311+EXPORT_SYMBOL(hss_rx_stop);
1312+
1313+int hss_chan_open(struct hss_device *hdev)
1314+{
1315+ struct port *port = hdev->port;
1316+ int i, err = 0;
1317+
1318+ if (port->chan_open)
1319+ return 0;
1320+
1321+ if (port->mode == MODE_HDLC) {
1322+ err = -ENOSYS;
1323+ goto out;
1324+ }
1325+
1326+ if (port->mode == MODE_G704 && port->channels[0] == hdev->id) {
1327+ err = -EBUSY; /* channel #0 is used for G.704 signaling */
1328+ goto out;
1329+ }
1330+
1331+ for (i = MAX_CHANNELS; i > port->frame_size / 8; i--)
1332+ if (port->channels[i - 1] == hdev->id) {
1333+ err = -ECHRNG; /* frame too short */
1334+ goto out;
1335+ }
1336+
1337+ hdev->rx_loc = hdev->tx_loc = 0;
1338+ hdev->rx_frame = hdev->tx_frame = 0;
1339+
1340+ //clear_bit((1 << hdev->id), &port->chan_rx_bitmap);
1341+ //clear_bit((1 << hdev->id), &port->chan_tx_bitmap);
1342+
1343+ if (!port->initialized) {
1344+ hss_prepare_chan(port);
1345+
1346+ hss_config_stop_chan(port);
1347+ hdev->open_count++;
1348+ port->chan_open_count++;
1349+
1350+ hss_config_set_lut(port);
1351+ hss_config_load(port);
1352+
1353+ }
1354+ port->chan_open = 1;
1355+
1356+out:
1357+ return err;
1358+}
1359+EXPORT_SYMBOL(hss_chan_open);
1360+
1361+int hss_chan_close(struct hss_device *hdev)
1362+{
1363+ return 0;
1364+}
1365+EXPORT_SYMBOL(hss_chan_close);
1366+
1367+void hss_chan_read(unsigned long data)
1368+{
1369+ struct port *port = (void *)data;
1370+ struct hss_device *hdev;
1371+ u8 *hw_buf, *save_buf;
1372+ u8 *buf;
1373+ u32 v;
1374+ unsigned int tx_list, rx_frame;
1375+ int i, j, channel;
1376+ u8 more_work = 0;
1377+
1378+/*
1379+ My Data in the hardware buffer is scattered by channels into 4 trunks
1380+ as follows for rx
1381+
1382+ channel 0 channel 1 channel 2 channel 3
1383+Trunk 1 = 0 -> 127 128 -> 255 256 -> 383 384 -> 512
1384+Trunk 2 = 513 -> 639 640 -> 768 769 -> 895 896 -> 1023
1385+Trunk 3 = 1024 -> 1151 1152 -> 1207 1208 -> 1407 1408 -> 1535
1386+Trunk 4 = 1535 -> 1663 1664 -> 1791 1792 -> 1920 1921 -> 2047
1387+
1388+ I will get CHAN_RX_TRIGGER worth of bytes out of each channel on each trunk
1389+ with each IRQ
1390+
1391+ For TX Data, it is split into 8 lists with each list containing 16 bytes per
1392+ channel
1393+
1394+Trunk 1 = 0 -> 16 17 -> 32 33 -> 48 49 -> 64
1395+Trunk 2 = 65 -> 80 81 -> 96 97 -> 112 113 -> 128
1396+Trunk 3 = 129 -> 144 145 -> 160 161 -> 176 177 -> 192
1397+Trunk 4 = 193 -> 208 209 -> 224 225 -> 240 241 -> 256
1398+
1399+*/
1400+
1401+
1402+ while ((v = qmgr_get_entry(queue_ids[port->id].chan)))
1403+ {
1404+ tx_list = (v >> 8) & 0xFF;
1405+ rx_frame = v & 0xFF;
1406+
1407+ if (tx_list == 7)
1408+ tx_list = 0;
1409+ else
1410+ tx_list++;
1411+ for (channel = 0; channel < 8; channel++) {
1412+
1413+ hdev = port->chan_devices[channel];
1414+ if (!hdev)
1415+ continue;
1416+
1417+ if (test_bit(1 << channel, &port->chan_tx_bitmap)) {
1418+ buf = (u8 *)hdev->tx_buf + hdev->tx_loc;
1419+#if 0
1420+ hw_buf = (u8 *)port->chan_tx_buf;
1421+ hw_buf += (tx_list * CHAN_TX_LIST_FRAMES * 32);
1422+ hw_buf += (4 * CHAN_TX_LIST_FRAMES * channel);
1423+ save_buf = hw_buf;
1424+#else
1425+ save_buf = port->tx_lists[tx_list][channel];
1426+#endif
1427+ for (i = 0; i < CHAN_TX_LIST_FRAMES; i++) {
1428+ hw_buf = save_buf + i;
1429+ for (j = 0; j < 4; j++) {
1430+ *hw_buf = *(buf++);
1431+ hw_buf += CHAN_TX_LIST_FRAMES;
1432+ }
1433+
1434+ hdev->tx_loc += 4;
1435+ hdev->tx_frame++;
1436+ if (hdev->tx_loc >= hdev->tx_buffer_size) {
1437+ hdev->tx_loc = 0;
1438+ buf = (u8 *)hdev->tx_buf;
1439+ }
1440+ }
1441+ } else {
1442+#if 0
1443+ hw_buf = (u8 *)port->chan_tx_buf;
1444+ hw_buf += (tx_list * CHAN_TX_LIST_FRAMES * 32);
1445+ hw_buf += (4 * CHAN_TX_LIST_FRAMES * channel);
1446+#else
1447+ hw_buf = port->tx_lists[tx_list][channel];
1448+#endif
1449+ memset(hw_buf, 0, 64);
1450+ }
1451+
1452+ if (hdev->tx_frame >= hdev->tx_period_size && test_bit(1 << channel, &port->chan_tx_bitmap))
1453+ {
1454+ hdev->tx_frame %= hdev->tx_period_size;
1455+ if (hdev->tx_callback)
1456+ hdev->tx_callback(hdev->tx_data);
1457+ more_work = 1;
1458+ }
1459+
1460+ if (test_bit(1 << channel, &port->chan_rx_bitmap)) {
1461+ buf = (u8 *)hdev->rx_buf + hdev->rx_loc;
1462+#if 0
1463+ hw_buf = (u8 *)port->chan_rx_buf;
1464+ hw_buf += (4 * CHAN_RX_FRAMES * channel);
1465+ hw_buf += rx_frame;
1466+ save_buf = hw_buf;
1467+#else
1468+ save_buf = port->rx_frames[channel][rx_frame >> 4];
1469+#endif
1470+ for (i = 0; i < CHAN_RX_TRIGGER; i++) {
1471+ hw_buf = save_buf + i;
1472+ for (j = 0; j < 4; j++) {
1473+ *(buf++) = *hw_buf;
1474+ hw_buf += CHAN_RX_FRAMES;
1475+ }
1476+ hdev->rx_loc += 4;
1477+ hdev->rx_frame++;
1478+ if (hdev->rx_loc >= hdev->rx_buffer_size) {
1479+ hdev->rx_loc = 0;
1480+ buf = (u8 *)hdev->rx_buf;
1481+ }
1482+ }
1483+ }
1484+
1485+ if (hdev->rx_frame >= hdev->rx_period_size && test_bit(1 << channel, &port->chan_rx_bitmap))
1486+ {
1487+ hdev->rx_frame %= hdev->rx_period_size;
1488+ if (hdev->rx_callback)
1489+ hdev->rx_callback(hdev->rx_data);
1490+ more_work = 1;
1491+ }
1492+ }
1493+#if 0
1494+ if (more_work)
1495+ {
1496+ tasklet_hi_schedule(&port->task);
1497+ return;
1498+ }
1499+#endif
1500+ }
1501+
1502+ qmgr_enable_irq(queue_ids[port->id].chan);
1503+
1504+ return;
1505+
1506+}
1507+
1508+struct hss_device *hss_chan_create(struct port *port, unsigned int channel)
1509+{
1510+ struct hss_device *chan_dev;
1511+ unsigned long flags;
1512+
1513+ chan_dev = kzalloc(sizeof(struct hss_device), GFP_KERNEL);
1514+
1515+ spin_lock_irqsave(&npe_lock, flags);
1516+
1517+ chan_dev->id = channel;
1518+ chan_dev->port = port;
1519+
1520+ port->channels[channel] = channel;
1521+
1522+ port->chan_devices[channel] = chan_dev;
1523+
1524+ spin_unlock_irqrestore(&npe_lock, flags);
1525+
1526+ return chan_dev;
1527+}
1528+
1529+/*****************************************************************************
1530+ * initialization
1531+ ****************************************************************************/
1532+
1533+static struct platform_device gw_avila_hss_device_0 = {
1534+ .name = "ixp4xx_hss",
1535+ .id = 0,
1536+};
1537+
1538+static struct platform_device gw_avila_hss_device_1 = {
1539+ .name = "ixp4xx_hss",
1540+ .id = 1,
1541+};
1542+
1543+static struct platform_device *gw_avila_hss_port_0;
1544+static struct platform_device *gw_avila_hss_port_1;
1545+static u64 hss_dmamask = 0xFFFFFFFF;
1546+
1547+struct hss_device *hss_init(int id, int channel)
1548+{
1549+ struct port *port = hss_port[id];
1550+ struct hss_device *hdev;
1551+ int ret;
1552+
1553+ if (!lock_init)
1554+ {
1555+ spin_lock_init(&npe_lock);
1556+ lock_init = 1;
1557+ npe = npe_request(0);
1558+ }
1559+
1560+ if (!port->init) {
1561+ if (id == 0) {
1562+ gw_avila_hss_port_0 = platform_device_alloc("hss-port", 0);
1563+
1564+ platform_set_drvdata(gw_avila_hss_port_0, &gw_avila_hss_device_0);
1565+ port->dev = &gw_avila_hss_port_0->dev;
1566+
1567+ if (!port->dev->dma_mask)
1568+ port->dev->dma_mask = &hss_dmamask;
1569+ if (!port->dev->coherent_dma_mask)
1570+ port->dev->coherent_dma_mask = 0xFFFFFFFF;
1571+
1572+ ret = platform_device_add(gw_avila_hss_port_0);
1573+
1574+ if (ret)
1575+ platform_device_put(gw_avila_hss_port_0);
1576+
1577+ tasklet_init(&port->task, hss_chan_read, (unsigned long) port);
1578+ }
1579+ else
1580+ {
1581+ gw_avila_hss_port_1 = platform_device_alloc("hss-port", 1);
1582+
1583+ platform_set_drvdata(gw_avila_hss_port_1, &gw_avila_hss_device_1);
1584+ port->dev = &gw_avila_hss_port_1->dev;
1585+
1586+ if (!port->dev->dma_mask)
1587+ port->dev->dma_mask = &hss_dmamask;
1588+ if (!port->dev->coherent_dma_mask)
1589+ port->dev->coherent_dma_mask = 0xFFFFFFFF;
1590+
1591+ ret = platform_device_add(gw_avila_hss_port_1);
1592+
1593+ if (ret)
1594+ platform_device_put(gw_avila_hss_port_1);
1595+
1596+ tasklet_init(&port->task, hss_chan_read, (unsigned long) port);
1597+ }
1598+
1599+ port->init = 1;
1600+ port->id = id;
1601+ port->clock_type = CLOCK_EXT;
1602+ port->clock_rate = 8192000;
1603+ port->frame_size = 256; /* E1 */
1604+ port->mode = MODE_RAW;
1605+ port->next_rx_frame = 0;
1606+ memset(port->channels, CHANNEL_UNUSED, sizeof(port->channels));
1607+ }
1608+
1609+ hdev = hss_chan_create(port, channel);
1610+
1611+ return hdev;
1612+}
1613+EXPORT_SYMBOL(hss_init);
1614+
1615+int hss_set_tx_callback(struct hss_device *hdev, void (*tx_callback)(void *), void *tx_data)
1616+{
1617+ BUG_ON(tx_callback == NULL);
1618+ hdev->tx_callback = tx_callback;
1619+ hdev->tx_data = tx_data;
1620+
1621+ return 0;
1622+}
1623+EXPORT_SYMBOL(hss_set_tx_callback);
1624+
1625+int hss_set_rx_callback(struct hss_device *hdev, void (*rx_callback)(void *), void *rx_data)
1626+{
1627+ BUG_ON(rx_callback == NULL);
1628+ hdev->rx_callback = rx_callback;
1629+ hdev->rx_data = rx_data;
1630+
1631+ return 0;
1632+}
1633+EXPORT_SYMBOL(hss_set_rx_callback);
1634+
1635+int hss_config_rx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size)
1636+{
1637+ /*
1638+ * Period Size and Buffer Size are in Frames which are u32
1639+ * We convert the u32 *buf to u8 in order to make channel reads
1640+ * and rx_loc easier
1641+ */
1642+
1643+ hdev->rx_buf = (u8 *)buf;
1644+ hdev->rx_buffer_size = buffer_size << 2;
1645+ hdev->rx_period_size = period_size;
1646+
1647+ return 0;
1648+}
1649+EXPORT_SYMBOL(hss_config_rx_dma);
1650+
1651+int hss_config_tx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size)
1652+{
1653+ /*
1654+ * Period Size and Buffer Size are in Frames which are u32
1655+ * We convert the u32 *buf to u8 in order to make channel reads
1656+ * and rx_loc easier
1657+ */
1658+
1659+ hdev->tx_buf = (u8 *)buf;
1660+ hdev->tx_buffer_size = buffer_size << 2;
1661+ hdev->tx_period_size = period_size;
1662+
1663+ return 0;
1664+}
1665+EXPORT_SYMBOL(hss_config_tx_dma);
1666+
1667+unsigned long hss_curr_offset_rx(struct hss_device *hdev)
1668+{
1669+ return hdev->rx_loc >> 2;
1670+}
1671+EXPORT_SYMBOL(hss_curr_offset_rx);
1672+
1673+unsigned long hss_curr_offset_tx(struct hss_device *hdev)
1674+{
1675+ return hdev->tx_loc >> 2;
1676+}
1677+EXPORT_SYMBOL(hss_curr_offset_tx);
1678+
1679+MODULE_AUTHOR("Chris Lang");
1680+MODULE_DESCRIPTION("Intel IXP4xx HSS Audio driver");
1681+MODULE_LICENSE("GPL v2");
1682--- /dev/null
1683+++ b/sound/soc/gw-avila/ixp4xx_hss.h
1684@@ -0,0 +1,401 @@
1685+/*
1686+ *
1687+ *
1688+ * Copyright (C) 2009 Gateworks Corporation
1689+ *
1690+ * This program is free software; you can redistribute it and/or modify it
1691+ * under the terms of version 2 of the GNU General Public License
1692+ * as published by the Free Software Foundation.
1693+ */
1694+
1695+#include <linux/types.h>
1696+#include <linux/bitops.h>
1697+#include <linux/dma-mapping.h>
1698+#include <linux/dmapool.h>
1699+#include <linux/fs.h>
1700+#include <linux/io.h>
1701+#include <linux/kernel.h>
1702+#include <linux/platform_device.h>
1703+#include <linux/poll.h>
1704+#include <mach/npe.h>
1705+#include <mach/qmgr.h>
1706+#include <linux/interrupt.h>
1707+
1708+//#include <linux/hdlc.h> XXX We aren't HDLC
1709+
1710+#define DEBUG_QUEUES 0
1711+#define DEBUG_DESC 0
1712+#define DEBUG_RX 0
1713+#define DEBUG_TX 0
1714+#define DEBUG_PKT_BYTES 0
1715+#define DEBUG_CLOSE 0
1716+#define DEBUG_FRAMER 0
1717+
1718+#define DRV_NAME "ixp4xx_hss"
1719+
1720+#define PKT_EXTRA_FLAGS 0 /* orig 1 */
1721+#define TX_FRAME_SYNC_OFFSET 0 /* channelized */
1722+#define PKT_NUM_PIPES 1 /* 1, 2 or 4 */
1723+#define PKT_PIPE_FIFO_SIZEW 4 /* total 4 dwords per HSS */
1724+
1725+#define RX_DESCS 512 /* also length of all RX queues */
1726+#define TX_DESCS 512 /* also length of all TX queues */
1727+
1728+//#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
1729+#define RX_SIZE (HDLC_MAX_MRU + 4) /* NPE needs more space */
1730+#define MAX_CLOSE_WAIT 1000 /* microseconds */
1731+#define HSS_COUNT 2
1732+#define MIN_FRAME_SIZE 16 /* bits */
1733+#define MAX_FRAME_SIZE 257 /* 256 bits + framing bit */
1734+#define MAX_CHANNELS (MAX_FRAME_SIZE / 8)
1735+#define MAX_CHAN_DEVICES 32
1736+#define CHANNEL_HDLC 0xFE
1737+#define CHANNEL_UNUSED 0xFF
1738+
1739+#define NAPI_WEIGHT 16
1740+#define CHAN_RX_TRIGGER 16 /* 8 RX frames = 1 ms @ E1 */
1741+#define CHAN_RX_FRAMES 128
1742+#define CHAN_RX_TRUNKS 1
1743+#define MAX_CHAN_RX_BAD_SYNC (CHAN_RX_TRIGGER / 2 /* pairs */ - 3)
1744+
1745+#define CHAN_TX_LIST_FRAMES CHAN_RX_TRIGGER /* bytes/channel per list, 16 - 48 */
1746+#define CHAN_TX_LISTS 8
1747+#define CHAN_TX_TRUNKS CHAN_RX_TRUNKS
1748+#define CHAN_TX_FRAMES (CHAN_TX_LIST_FRAMES * CHAN_TX_LISTS)
1749+
1750+#define CHAN_QUEUE_LEN 32 /* minimum possible */
1751+
1752+#define chan_rx_buf_len(port) (port->frame_size / 8 * CHAN_RX_FRAMES * CHAN_RX_TRUNKS)
1753+#define chan_tx_buf_len(port) (port->frame_size / 8 * CHAN_TX_FRAMES * CHAN_TX_TRUNKS)
1754+
1755+/* Queue IDs */
1756+#define HSS0_CHL_RXTRIG_QUEUE 12 /* orig size = 32 dwords */
1757+#define HSS0_PKT_RX_QUEUE 13 /* orig size = 32 dwords */
1758+#define HSS0_PKT_TX0_QUEUE 14 /* orig size = 16 dwords */
1759+#define HSS0_PKT_TX1_QUEUE 15
1760+#define HSS0_PKT_TX2_QUEUE 16
1761+#define HSS0_PKT_TX3_QUEUE 17
1762+#define HSS0_PKT_RXFREE0_QUEUE 18 /* orig size = 16 dwords */
1763+#define HSS0_PKT_RXFREE1_QUEUE 19
1764+#define HSS0_PKT_RXFREE2_QUEUE 20
1765+#define HSS0_PKT_RXFREE3_QUEUE 21
1766+#define HSS0_PKT_TXDONE_QUEUE 22 /* orig size = 64 dwords */
1767+
1768+#define HSS1_CHL_RXTRIG_QUEUE 10
1769+#define HSS1_PKT_RX_QUEUE 0
1770+#define HSS1_PKT_TX0_QUEUE 5
1771+#define HSS1_PKT_TX1_QUEUE 6
1772+#define HSS1_PKT_TX2_QUEUE 7
1773+#define HSS1_PKT_TX3_QUEUE 8
1774+#define HSS1_PKT_RXFREE0_QUEUE 1
1775+#define HSS1_PKT_RXFREE1_QUEUE 2
1776+#define HSS1_PKT_RXFREE2_QUEUE 3
1777+#define HSS1_PKT_RXFREE3_QUEUE 4
1778+#define HSS1_PKT_TXDONE_QUEUE 9
1779+
1780+#define NPE_PKT_MODE_HDLC 0
1781+#define NPE_PKT_MODE_RAW 1
1782+#define NPE_PKT_MODE_56KMODE 2
1783+#define NPE_PKT_MODE_56KENDIAN_MSB 4
1784+
1785+/* PKT_PIPE_HDLC_CFG_WRITE flags */
1786+#define PKT_HDLC_IDLE_ONES 0x1 /* default = flags */
1787+#define PKT_HDLC_CRC_32 0x2 /* default = CRC-16 */
1788+#define PKT_HDLC_MSB_ENDIAN 0x4 /* default = LE */
1789+
1790+
1791+/* hss_config, PCRs */
1792+/* Frame sync sampling, default = active low */
1793+#define PCR_FRM_SYNC_ACTIVE_HIGH 0x40000000
1794+#define PCR_FRM_SYNC_FALLINGEDGE 0x80000000
1795+#define PCR_FRM_SYNC_RISINGEDGE 0xC0000000
1796+
1797+/* Frame sync pin: input (default) or output generated off a given clk edge */
1798+#define PCR_FRM_SYNC_OUTPUT_FALLING 0x20000000
1799+#define PCR_FRM_SYNC_OUTPUT_RISING 0x30000000
1800+
1801+/* Frame and data clock sampling on edge, default = falling */
1802+#define PCR_FCLK_EDGE_RISING 0x08000000
1803+#define PCR_DCLK_EDGE_RISING 0x04000000
1804+
1805+/* Clock direction, default = input */
1806+#define PCR_SYNC_CLK_DIR_OUTPUT 0x02000000
1807+
1808+/* Generate/Receive frame pulses, default = enabled */
1809+#define PCR_FRM_PULSE_DISABLED 0x01000000
1810+
1811+ /* Data rate is full (default) or half the configured clk speed */
1812+#define PCR_HALF_CLK_RATE 0x00200000
1813+
1814+/* Invert data between NPE and HSS FIFOs? (default = no) */
1815+#define PCR_DATA_POLARITY_INVERT 0x00100000
1816+
1817+/* TX/RX endianness, default = LSB */
1818+#define PCR_MSB_ENDIAN 0x00080000
1819+
1820+/* Normal (default) / open drain mode (TX only) */
1821+#define PCR_TX_PINS_OPEN_DRAIN 0x00040000
1822+
1823+/* No framing bit transmitted and expected on RX? (default = framing bit) */
1824+#define PCR_SOF_NO_FBIT 0x00020000
1825+
1826+/* Drive data pins? */
1827+#define PCR_TX_DATA_ENABLE 0x00010000
1828+
1829+/* Voice 56k type: drive the data pins low (default), high, high Z */
1830+#define PCR_TX_V56K_HIGH 0x00002000
1831+#define PCR_TX_V56K_HIGH_IMP 0x00004000
1832+
1833+/* Unassigned type: drive the data pins low (default), high, high Z */
1834+#define PCR_TX_UNASS_HIGH 0x00000800
1835+#define PCR_TX_UNASS_HIGH_IMP 0x00001000
1836+
1837+/* T1 @ 1.544MHz only: Fbit dictated in FIFO (default) or high Z */
1838+#define PCR_TX_FB_HIGH_IMP 0x00000400
1839+
1840+/* 56k data endiannes - which bit unused: high (default) or low */
1841+#define PCR_TX_56KE_BIT_0_UNUSED 0x00000200
1842+
1843+/* 56k data transmission type: 32/8 bit data (default) or 56K data */
1844+#define PCR_TX_56KS_56K_DATA 0x00000100
1845+
1846+/* hss_config, cCR */
1847+/* Number of packetized clients, default = 1 */
1848+#define CCR_NPE_HFIFO_2_HDLC 0x04000000
1849+#define CCR_NPE_HFIFO_3_OR_4HDLC 0x08000000
1850+
1851+/* default = no loopback */
1852+#define CCR_LOOPBACK 0x02000000
1853+
1854+/* HSS number, default = 0 (first) */
1855+#define CCR_SECOND_HSS 0x01000000
1856+
1857+
1858+/* hss_config, clkCR: main:10, num:10, denom:12 */
1859+#define CLK42X_SPEED_EXP ((0x3FF << 22) | ( 2 << 12) | 15) /*65 KHz*/
1860+
1861+#define CLK42X_SPEED_512KHZ (( 130 << 22) | ( 2 << 12) | 15)
1862+#define CLK42X_SPEED_1536KHZ (( 43 << 22) | ( 18 << 12) | 47)
1863+#define CLK42X_SPEED_1544KHZ (( 43 << 22) | ( 33 << 12) | 192)
1864+#define CLK42X_SPEED_2048KHZ (( 32 << 22) | ( 34 << 12) | 63)
1865+#define CLK42X_SPEED_4096KHZ (( 16 << 22) | ( 34 << 12) | 127)
1866+#define CLK42X_SPEED_8192KHZ (( 8 << 22) | ( 34 << 12) | 255)
1867+
1868+#define CLK46X_SPEED_512KHZ (( 130 << 22) | ( 24 << 12) | 127)
1869+#define CLK46X_SPEED_1536KHZ (( 43 << 22) | (152 << 12) | 383)
1870+#define CLK46X_SPEED_1544KHZ (( 43 << 22) | ( 66 << 12) | 385)
1871+#define CLK46X_SPEED_2048KHZ (( 32 << 22) | (280 << 12) | 511)
1872+#define CLK46X_SPEED_4096KHZ (( 16 << 22) | (280 << 12) | 1023)
1873+#define CLK46X_SPEED_8192KHZ (( 8 << 22) | (280 << 12) | 2047)
1874+
1875+
1876+/* hss_config, LUT entries */
1877+#define TDMMAP_UNASSIGNED 0
1878+#define TDMMAP_HDLC 1 /* HDLC - packetized */
1879+#define TDMMAP_VOICE56K 2 /* Voice56K - 7-bit channelized */
1880+#define TDMMAP_VOICE64K 3 /* Voice64K - 8-bit channelized */
1881+
1882+/* offsets into HSS config */
1883+#define HSS_CONFIG_TX_PCR 0x00 /* port configuration registers */
1884+#define HSS_CONFIG_RX_PCR 0x04
1885+#define HSS_CONFIG_CORE_CR 0x08 /* loopback control, HSS# */
1886+#define HSS_CONFIG_CLOCK_CR 0x0C /* clock generator control */
1887+#define HSS_CONFIG_TX_FCR 0x10 /* frame configuration registers */
1888+#define HSS_CONFIG_RX_FCR 0x14
1889+#define HSS_CONFIG_TX_LUT 0x18 /* channel look-up tables */
1890+#define HSS_CONFIG_RX_LUT 0x38
1891+
1892+
1893+/* NPE command codes */
1894+/* writes the ConfigWord value to the location specified by offset */
1895+#define PORT_CONFIG_WRITE 0x40
1896+
1897+/* triggers the NPE to load the contents of the configuration table */
1898+#define PORT_CONFIG_LOAD 0x41
1899+
1900+/* triggers the NPE to return an HssErrorReadResponse message */
1901+#define PORT_ERROR_READ 0x42
1902+
1903+/* reset NPE internal status and enable the HssChannelized operation */
1904+#define CHAN_FLOW_ENABLE 0x43
1905+#define CHAN_FLOW_DISABLE 0x44
1906+#define CHAN_IDLE_PATTERN_WRITE 0x45
1907+#define CHAN_NUM_CHANS_WRITE 0x46
1908+#define CHAN_RX_BUF_ADDR_WRITE 0x47
1909+#define CHAN_RX_BUF_CFG_WRITE 0x48
1910+#define CHAN_TX_BLK_CFG_WRITE 0x49
1911+#define CHAN_TX_BUF_ADDR_WRITE 0x4A
1912+#define CHAN_TX_BUF_SIZE_WRITE 0x4B
1913+#define CHAN_TSLOTSWITCH_ENABLE 0x4C
1914+#define CHAN_TSLOTSWITCH_DISABLE 0x4D
1915+
1916+/* downloads the gainWord value for a timeslot switching channel associated
1917+ with bypassNum */
1918+#define CHAN_TSLOTSWITCH_GCT_DOWNLOAD 0x4E
1919+
1920+/* triggers the NPE to reset internal status and enable the HssPacketized
1921+ operation for the flow specified by pPipe */
1922+#define PKT_PIPE_FLOW_ENABLE 0x50
1923+#define PKT_PIPE_FLOW_DISABLE 0x51
1924+#define PKT_NUM_PIPES_WRITE 0x52
1925+#define PKT_PIPE_FIFO_SIZEW_WRITE 0x53
1926+#define PKT_PIPE_HDLC_CFG_WRITE 0x54
1927+#define PKT_PIPE_IDLE_PATTERN_WRITE 0x55
1928+#define PKT_PIPE_RX_SIZE_WRITE 0x56
1929+#define PKT_PIPE_MODE_WRITE 0x57
1930+
1931+/* HDLC packet status values - desc->status */
1932+#define ERR_SHUTDOWN 1 /* stop or shutdown occurrance */
1933+#define ERR_HDLC_ALIGN 2 /* HDLC alignment error */
1934+#define ERR_HDLC_FCS 3 /* HDLC Frame Check Sum error */
1935+#define ERR_RXFREE_Q_EMPTY 4 /* RX-free queue became empty while receiving
1936+ this packet (if buf_len < pkt_len) */
1937+#define ERR_HDLC_TOO_LONG 5 /* HDLC frame size too long */
1938+#define ERR_HDLC_ABORT 6 /* abort sequence received */
1939+#define ERR_DISCONNECTING 7 /* disconnect is in progress */
1940+
1941+#define CLOCK_EXT 0
1942+#define CLOCK_INT 1
1943+
1944+enum mode {MODE_HDLC = 0, MODE_RAW, MODE_G704};
1945+enum rx_tx_bit {
1946+ TX_BIT = 0,
1947+ RX_BIT = 1
1948+};
1949+enum chan_bit {
1950+ CHAN_0 = (1 << 0),
1951+ CHAN_1 = (1 << 1),
1952+ CHAN_2 = (1 << 2),
1953+ CHAN_3 = (1 << 3),
1954+ CHAN_4 = (1 << 4),
1955+ CHAN_5 = (1 << 5),
1956+ CHAN_6 = (1 << 6),
1957+ CHAN_7 = (1 << 7),
1958+ CHAN_8 = (1 << 8),
1959+ CHAN_9 = (1 << 9),
1960+ CHAN_10 = (1 << 10),
1961+ CHAN_11 = (1 << 11),
1962+ CHAN_12 = (1 << 12),
1963+ CHAN_13 = (1 << 13),
1964+ CHAN_14 = (1 << 14),
1965+ CHAN_15 = (1 << 15)
1966+};
1967+
1968+enum alignment { NOT_ALIGNED = 0, EVEN_FIRST, ODD_FIRST };
1969+
1970+#ifdef __ARMEB__
1971+typedef struct sk_buff buffer_t;
1972+#define free_buffer dev_kfree_skb
1973+#define free_buffer_irq dev_kfree_skb_irq
1974+#else
1975+typedef void buffer_t;
1976+#define free_buffer kfree
1977+#define free_buffer_irq kfree
1978+#endif
1979+
1980+struct hss_device {
1981+ struct port *port;
1982+ unsigned int open_count, excl_open;
1983+ unsigned long tx_loc, rx_loc; /* bytes */
1984+ unsigned long tx_frame, rx_frame; /* Frames */
1985+ u8 id, chan_count;
1986+ u8 log_channels[MAX_CHANNELS];
1987+
1988+ u8 *rx_buf;
1989+ u8 *tx_buf;
1990+
1991+ size_t rx_buffer_size;
1992+ size_t rx_period_size;
1993+ size_t tx_buffer_size;
1994+ size_t tx_period_size;
1995+
1996+ void (*rx_callback)(void *data);
1997+ void *rx_data;
1998+ void (*tx_callback)(void *data);
1999+ void *tx_data;
2000+ void *private_data;
2001+};
2002+
2003+extern struct hss_device *hss_handle[32];
2004+extern struct port *hss_port[2];
2005+
2006+struct port {
2007+ unsigned char init;
2008+
2009+ struct device *dev;
2010+
2011+ struct tasklet_struct task;
2012+ unsigned int id;
2013+ unsigned long chan_rx_bitmap;
2014+ unsigned long chan_tx_bitmap;
2015+ unsigned char chan_open;
2016+
2017+ /* the following fields must be protected by npe_lock */
2018+ enum mode mode;
2019+ unsigned int clock_type, clock_rate, loopback;
2020+ unsigned int frame_size, frame_sync_offset;
2021+ unsigned int next_rx_frame;
2022+
2023+ struct hss_device *chan_devices[MAX_CHAN_DEVICES];
2024+ u32 chan_tx_buf_phys, chan_rx_buf_phys;
2025+ u32 chan_tx_pointers_phys;
2026+ u32 *chan_tx_pointers;
2027+ u8 *chan_rx_buf;
2028+ u8 *chan_tx_buf;
2029+ u8 *tx_lists[CHAN_TX_LISTS][8];
2030+ u8 *rx_frames[8][CHAN_TX_LISTS];
2031+ unsigned int chan_open_count, hdlc_open;
2032+ unsigned int chan_started, initialized, just_set_offset;
2033+ unsigned int chan_last_rx, chan_last_tx;
2034+
2035+ /* assigned channels, may be invalid with given frame length or mode */
2036+ u8 channels[MAX_CHANNELS];
2037+ int msg_count;
2038+};
2039+
2040+/* NPE message structure */
2041+struct msg {
2042+#ifdef __ARMEB__
2043+ u8 cmd, unused, hss_port, index;
2044+ union {
2045+ struct { u8 data8a, data8b, data8c, data8d; };
2046+ struct { u16 data16a, data16b; };
2047+ struct { u32 data32; };
2048+ };
2049+#else
2050+ u8 index, hss_port, unused, cmd;
2051+ union {
2052+ struct { u8 data8d, data8c, data8b, data8a; };
2053+ struct { u16 data16b, data16a; };
2054+ struct { u32 data32; };
2055+ };
2056+#endif
2057+};
2058+
2059+#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \
2060+ (n) * sizeof(struct desc))
2061+#define rx_desc_ptr(port, n) (&(port)->desc_tab[n])
2062+
2063+#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \
2064+ ((n) + RX_DESCS) * sizeof(struct desc))
2065+#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS])
2066+
2067+int hss_prepare_chan(struct port *port);
2068+void hss_chan_stop(struct port *port);
2069+
2070+struct hss_device *hss_init(int id, int channel);
2071+int hss_chan_open(struct hss_device *hdev);
2072+int hss_chan_close(struct hss_device *hdev);
2073+
2074+int hss_set_tx_callback(struct hss_device *hdev, void (*tx_callback)(void *), void *tx_data);
2075+int hss_set_rx_callback(struct hss_device *hdev, void (*rx_callback)(void *), void *rx_data);
2076+int hss_tx_start(struct hss_device *hdev);
2077+int hss_tx_stop(struct hss_device *hdev);
2078+int hss_rx_start(struct hss_device *hdev);
2079+int hss_rx_stop(struct hss_device *hdev);
2080+
2081+int hss_config_rx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size);
2082+int hss_config_tx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size);
2083+unsigned long hss_curr_offset_rx(struct hss_device *hdev);
2084+unsigned long hss_curr_offset_tx(struct hss_device *hdev);
2085+
2086

Archive Download this file



interactive