1/*
2 * ath-pcm.h -- ALSA PCM interface for the QCA Wasp based audio interface
3 *
4 * Copyright (c) 2013 The Linux Foundation. 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
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#ifndef _ATH_PCM_H_
20#define _ATH_PCM_H_
21
22#include <linux/sound.h>
23#include <linux/list.h>
24#include <linux/spinlock.h>
25
26extern spinlock_t ath79_pcm_lock;
27
28struct ath79_pcm_desc {
29	unsigned int	OWN	:  1,    /* bit 31 */
30			EOM	:  1,    /* bit 30 */
31			rsvd1	:  6,    /* bit 29-24 */
32			size	: 12,    /* bit 23-12 */
33			length	: 12,    /* bit 11-00 */
34			rsvd2	:  4,    /* bit 31-28 */
35			BufPtr	: 28,    /* bit 27-00 */
36			rsvd3	:  4,    /* bit 31-28 */
37			NextPtr	: 28;    /* bit 27-00 */
38
39	unsigned int Va[6];
40	unsigned int Ua[6];
41	unsigned int Ca[6];
42	unsigned int Vb[6];
43	unsigned int Ub[6];
44	unsigned int Cb[6];
45
46	/* Software specific data
47	 * These data are not taken into account by the HW */
48	struct list_head list; /* List linking all the buffer in virt@ space */
49	dma_addr_t phys; /* Physical address of the descriptor */
50};
51
52struct ath79_pcm_rt_priv {
53	struct list_head dma_head;
54	struct ath79_pcm_desc *last_played;
55	unsigned int elapsed_size;
56	unsigned int delay_time;
57	int direction;
58};
59
60/* Replaces struct ath_i2s_softc */
61struct ath79_pcm_pltfm_priv {
62	struct snd_pcm_substream *playback;
63	struct snd_pcm_substream *capture;
64};
65
66/* platform data */
67extern struct snd_soc_platform_driver ath79_soc_platform;
68
69void ath79_mbox_interrupt_ack(u32);
70void ath79_mbox_dma_start(struct ath79_pcm_rt_priv *);
71void ath79_mbox_dma_stop(struct ath79_pcm_rt_priv *);
72void ath79_mbox_dma_prepare(struct ath79_pcm_rt_priv *);
73int ath79_mbox_dma_map(struct ath79_pcm_rt_priv *, dma_addr_t, int,int);
74void ath79_mbox_dma_unmap(struct ath79_pcm_rt_priv *);
75int ath79_mbox_dma_init(struct device *);
76void ath79_mbox_dma_exit(void);
77void ath79_mbox_dma_reset(void);
78
79static inline unsigned int ath79_pcm_set_own_bits(struct ath79_pcm_rt_priv *rtpriv)
80{
81	struct ath79_pcm_desc *desc;
82	unsigned int size_played = 0;
83
84	spin_lock(&ath79_pcm_lock);
85	list_for_each_entry(desc, &rtpriv->dma_head, list) {
86		if (desc->OWN == 0) {
87			desc->OWN = 1;
88			size_played += desc->size;
89		}
90	}
91	spin_unlock(&ath79_pcm_lock);
92	return size_played;
93}
94
95static inline void ath79_pcm_clear_own_bits(struct ath79_pcm_rt_priv *rtpriv)
96{
97	struct ath79_pcm_desc *desc;
98
99	spin_lock(&ath79_pcm_lock);
100	list_for_each_entry(desc, &rtpriv->dma_head, list) {
101		if (desc->OWN == 1) {
102			desc->OWN = 0;
103		}
104	}
105	spin_unlock(&ath79_pcm_lock);
106}
107
108static inline struct ath79_pcm_desc *ath79_pcm_get_last_played(struct ath79_pcm_rt_priv *rtpriv)
109{
110	struct ath79_pcm_desc *desc, *prev;
111
112	spin_lock(&ath79_pcm_lock);
113	prev = list_entry(rtpriv->dma_head.prev, struct ath79_pcm_desc, list);
114	list_for_each_entry(desc, &rtpriv->dma_head, list) {
115		if (desc->OWN == 1 && prev->OWN == 0) {
116			return desc;
117		}
118		prev = desc;
119	}
120	spin_unlock(&ath79_pcm_lock);
121
122	/* If we didn't find the last played buffer, return NULL */
123	return NULL;
124}
125
126#endif /* _ATH_PCM_H_ */
127