blob: a455aac66067fc615783fb80339c53988f45f629 [file] [log] [blame]
/*
* ath-pcm.h -- ALSA PCM interface for the QCA Wasp based audio interface
*
* Copyright (c) 2013 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _ATH_PCM_H_
#define _ATH_PCM_H_
#include <linux/sound.h>
#include <linux/list.h>
#include <linux/spinlock.h>
extern spinlock_t ath79_pcm_lock;
struct ath79_pcm_desc {
unsigned int OWN : 1, /* bit 31 */
EOM : 1, /* bit 30 */
rsvd1 : 6, /* bit 29-24 */
size : 12, /* bit 23-12 */
length : 12, /* bit 11-00 */
rsvd2 : 4, /* bit 31-28 */
BufPtr : 28, /* bit 27-00 */
rsvd3 : 4, /* bit 31-28 */
NextPtr : 28; /* bit 27-00 */
unsigned int Va[6];
unsigned int Ua[6];
unsigned int Ca[6];
unsigned int Vb[6];
unsigned int Ub[6];
unsigned int Cb[6];
/* Software specific data
* These data are not taken into account by the HW */
struct list_head list; /* List linking all the buffer in virt@ space */
dma_addr_t phys; /* Physical address of the descriptor */
};
struct ath79_pcm_rt_priv {
struct list_head dma_head;
struct ath79_pcm_desc *last_played;
unsigned int elapsed_size;
unsigned int delay_time;
int direction;
};
/* Replaces struct ath_i2s_softc */
struct ath79_pcm_pltfm_priv {
struct snd_pcm_substream *playback;
struct snd_pcm_substream *capture;
};
/* platform data */
extern struct snd_soc_platform_driver ath79_soc_platform;
void ath79_mbox_interrupt_ack(u32);
void ath79_mbox_dma_start(struct ath79_pcm_rt_priv *);
void ath79_mbox_dma_stop(struct ath79_pcm_rt_priv *);
void ath79_mbox_dma_prepare(struct ath79_pcm_rt_priv *);
int ath79_mbox_dma_map(struct ath79_pcm_rt_priv *, dma_addr_t, int,int);
void ath79_mbox_dma_unmap(struct ath79_pcm_rt_priv *);
int ath79_mbox_dma_init(struct device *);
void ath79_mbox_dma_exit(void);
void ath79_mbox_dma_reset(void);
static inline unsigned int ath79_pcm_set_own_bits(struct ath79_pcm_rt_priv *rtpriv)
{
struct ath79_pcm_desc *desc;
unsigned int size_played = 0;
spin_lock(&ath79_pcm_lock);
list_for_each_entry(desc, &rtpriv->dma_head, list) {
if (desc->OWN == 0) {
desc->OWN = 1;
size_played += desc->size;
}
}
spin_unlock(&ath79_pcm_lock);
return size_played;
}
static inline void ath79_pcm_clear_own_bits(struct ath79_pcm_rt_priv *rtpriv)
{
struct ath79_pcm_desc *desc;
spin_lock(&ath79_pcm_lock);
list_for_each_entry(desc, &rtpriv->dma_head, list) {
if (desc->OWN == 1) {
desc->OWN = 0;
}
}
spin_unlock(&ath79_pcm_lock);
}
static inline struct ath79_pcm_desc *ath79_pcm_get_last_played(struct ath79_pcm_rt_priv *rtpriv)
{
struct ath79_pcm_desc *desc, *prev;
spin_lock(&ath79_pcm_lock);
prev = list_entry(rtpriv->dma_head.prev, struct ath79_pcm_desc, list);
list_for_each_entry(desc, &rtpriv->dma_head, list) {
if (desc->OWN == 1 && prev->OWN == 0) {
return desc;
}
prev = desc;
}
spin_unlock(&ath79_pcm_lock);
/* If we didn't find the last played buffer, return NULL */
return NULL;
}
#endif /* _ATH_PCM_H_ */