2019-05-30 02:57:50 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-02-23 00:09:22 +03:00
/*
* omap - mcpdm . c - - OMAP ALSA SoC DAI driver using McPDM port
*
2011-07-05 20:50:45 +04:00
* Copyright ( C ) 2009 - 2011 Texas Instruments
2010-02-23 00:09:22 +03:00
*
2011-07-05 20:50:45 +04:00
* Author : Misael Lopez Cruz < misael . lopez @ ti . com >
2010-02-23 00:09:22 +03:00
* Contact : Jorge Eduardo Candelaria < x0107209 @ ti . com >
* Margarita Olaya < magi . olaya @ ti . com >
2011-07-05 20:50:45 +04:00
* Peter Ujfalusi < peter . ujfalusi @ ti . com >
2010-02-23 00:09:22 +03:00
*/
# include <linux/init.h>
# include <linux/module.h>
2011-07-05 20:50:45 +04:00
# include <linux/platform_device.h>
# include <linux/interrupt.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/slab.h>
# include <linux/pm_runtime.h>
2011-11-15 13:32:14 +04:00
# include <linux/of_device.h>
2011-07-05 20:50:45 +04:00
2010-02-23 00:09:22 +03:00
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
2013-04-03 13:06:05 +04:00
# include <sound/dmaengine_pcm.h>
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
# include "omap-mcpdm.h"
2018-05-07 11:49:58 +03:00
# include "sdma-pcm.h"
2010-02-23 00:09:22 +03:00
2013-03-20 13:47:12 +04:00
struct mcpdm_link_config {
u32 link_mask ; /* channel mask for the direction */
u32 threshold ; /* FIFO threshold */
} ;
2012-08-31 21:59:07 +04:00
2011-07-05 20:50:45 +04:00
struct omap_mcpdm {
struct device * dev ;
unsigned long phys_base ;
void __iomem * io_base ;
int irq ;
2018-11-14 14:06:22 +03:00
struct pm_qos_request pm_qos_req ;
int latency [ 2 ] ;
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
struct mutex mutex ;
2013-03-20 13:47:12 +04:00
/* Playback/Capture configuration */
struct mcpdm_link_config config [ 2 ] ;
2011-09-26 17:05:58 +04:00
/* McPDM dn offsets for rx1, and 2 channels */
u32 dn_rx_offset ;
2013-03-20 13:47:13 +04:00
/* McPDM needs to be restarted due to runtime reconfiguration */
bool restart ;
2013-04-03 13:06:05 +04:00
2016-05-18 16:46:35 +03:00
/* pm state for suspend/resume handling */
int pm_active_count ;
2013-04-03 13:06:05 +04:00
struct snd_dmaengine_dai_dma_data dma_data [ 2 ] ;
2010-02-23 00:09:22 +03:00
} ;
/*
* Stream DMA parameters
*/
2011-07-05 20:50:45 +04:00
static inline void omap_mcpdm_write ( struct omap_mcpdm * mcpdm , u16 reg , u32 val )
2010-02-23 00:09:22 +03:00
{
2013-11-16 04:01:19 +04:00
writel_relaxed ( val , mcpdm - > io_base + reg ) ;
2011-07-05 20:50:45 +04:00
}
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
static inline int omap_mcpdm_read ( struct omap_mcpdm * mcpdm , u16 reg )
{
2013-11-16 04:01:19 +04:00
return readl_relaxed ( mcpdm - > io_base + reg ) ;
2011-07-05 20:50:45 +04:00
}
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
# ifdef DEBUG
static void omap_mcpdm_reg_dump ( struct omap_mcpdm * mcpdm )
{
dev_dbg ( mcpdm - > dev , " *********************** \n " ) ;
dev_dbg ( mcpdm - > dev , " IRQSTATUS_RAW: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_IRQSTATUS_RAW ) ) ;
dev_dbg ( mcpdm - > dev , " IRQSTATUS: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_IRQSTATUS ) ) ;
dev_dbg ( mcpdm - > dev , " IRQENABLE_SET: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_IRQENABLE_SET ) ) ;
dev_dbg ( mcpdm - > dev , " IRQENABLE_CLR: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_IRQENABLE_CLR ) ) ;
dev_dbg ( mcpdm - > dev , " IRQWAKE_EN: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_IRQWAKE_EN ) ) ;
dev_dbg ( mcpdm - > dev , " DMAENABLE_SET: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_DMAENABLE_SET ) ) ;
dev_dbg ( mcpdm - > dev , " DMAENABLE_CLR: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_DMAENABLE_CLR ) ) ;
dev_dbg ( mcpdm - > dev , " DMAWAKEEN: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_DMAWAKEEN ) ) ;
dev_dbg ( mcpdm - > dev , " CTRL: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_CTRL ) ) ;
dev_dbg ( mcpdm - > dev , " DN_DATA: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_DN_DATA ) ) ;
dev_dbg ( mcpdm - > dev , " UP_DATA: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_UP_DATA ) ) ;
dev_dbg ( mcpdm - > dev , " FIFO_CTRL_DN: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_FIFO_CTRL_DN ) ) ;
dev_dbg ( mcpdm - > dev , " FIFO_CTRL_UP: 0x%04x \n " ,
omap_mcpdm_read ( mcpdm , MCPDM_REG_FIFO_CTRL_UP ) ) ;
dev_dbg ( mcpdm - > dev , " *********************** \n " ) ;
2010-02-23 00:09:22 +03:00
}
2011-07-05 20:50:45 +04:00
# else
static void omap_mcpdm_reg_dump ( struct omap_mcpdm * mcpdm ) { }
# endif
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
/*
* Enables the transfer through the PDM interface to / from the Phoenix
* codec by enabling the corresponding UP or DN channels .
*/
static void omap_mcpdm_start ( struct omap_mcpdm * mcpdm )
{
u32 ctrl = omap_mcpdm_read ( mcpdm , MCPDM_REG_CTRL ) ;
2013-03-20 13:47:12 +04:00
u32 link_mask = mcpdm - > config [ 0 ] . link_mask | mcpdm - > config [ 1 ] . link_mask ;
2011-07-05 20:50:45 +04:00
ctrl | = ( MCPDM_SW_DN_RST | MCPDM_SW_UP_RST ) ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_CTRL , ctrl ) ;
2013-03-20 13:47:12 +04:00
ctrl | = link_mask ;
2011-07-05 20:50:45 +04:00
omap_mcpdm_write ( mcpdm , MCPDM_REG_CTRL , ctrl ) ;
ctrl & = ~ ( MCPDM_SW_DN_RST | MCPDM_SW_UP_RST ) ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_CTRL , ctrl ) ;
}
/*
* Disables the transfer through the PDM interface to / from the Phoenix
* codec by disabling the corresponding UP or DN channels .
*/
static void omap_mcpdm_stop ( struct omap_mcpdm * mcpdm )
{
u32 ctrl = omap_mcpdm_read ( mcpdm , MCPDM_REG_CTRL ) ;
2013-03-20 13:47:13 +04:00
u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK ;
2011-07-05 20:50:45 +04:00
ctrl | = ( MCPDM_SW_DN_RST | MCPDM_SW_UP_RST ) ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_CTRL , ctrl ) ;
2013-03-20 13:47:12 +04:00
ctrl & = ~ ( link_mask ) ;
2011-07-05 20:50:45 +04:00
omap_mcpdm_write ( mcpdm , MCPDM_REG_CTRL , ctrl ) ;
ctrl & = ~ ( MCPDM_SW_DN_RST | MCPDM_SW_UP_RST ) ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_CTRL , ctrl ) ;
}
/*
* Is the physical McPDM interface active .
*/
static inline int omap_mcpdm_active ( struct omap_mcpdm * mcpdm )
{
return omap_mcpdm_read ( mcpdm , MCPDM_REG_CTRL ) &
( MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK ) ;
}
/*
* Configures McPDM uplink , and downlink for audio .
* This function should be called before omap_mcpdm_start .
*/
static void omap_mcpdm_open_streams ( struct omap_mcpdm * mcpdm )
{
2016-05-18 16:46:34 +03:00
u32 ctrl = omap_mcpdm_read ( mcpdm , MCPDM_REG_CTRL ) ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_CTRL , ctrl | MCPDM_WD_EN ) ;
2011-07-05 20:50:45 +04:00
omap_mcpdm_write ( mcpdm , MCPDM_REG_IRQENABLE_SET ,
MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL |
MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL ) ;
2011-09-26 17:05:58 +04:00
/* Enable DN RX1/2 offset cancellation feature, if configured */
if ( mcpdm - > dn_rx_offset ) {
u32 dn_offset = mcpdm - > dn_rx_offset ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_DN_OFFSET , dn_offset ) ;
dn_offset | = ( MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN ) ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_DN_OFFSET , dn_offset ) ;
}
2013-03-20 13:47:12 +04:00
omap_mcpdm_write ( mcpdm , MCPDM_REG_FIFO_CTRL_DN ,
mcpdm - > config [ SNDRV_PCM_STREAM_PLAYBACK ] . threshold ) ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_FIFO_CTRL_UP ,
mcpdm - > config [ SNDRV_PCM_STREAM_CAPTURE ] . threshold ) ;
2011-07-05 20:50:45 +04:00
omap_mcpdm_write ( mcpdm , MCPDM_REG_DMAENABLE_SET ,
MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE ) ;
}
/*
* Cleans McPDM uplink , and downlink configuration .
* This function should be called when the stream is closed .
*/
static void omap_mcpdm_close_streams ( struct omap_mcpdm * mcpdm )
2010-02-23 00:09:22 +03:00
{
2011-07-05 20:50:45 +04:00
/* Disable irq request generation for downlink */
omap_mcpdm_write ( mcpdm , MCPDM_REG_IRQENABLE_CLR ,
MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL ) ;
/* Disable DMA request generation for downlink */
omap_mcpdm_write ( mcpdm , MCPDM_REG_DMAENABLE_CLR , MCPDM_DMA_DN_ENABLE ) ;
/* Disable irq request generation for uplink */
omap_mcpdm_write ( mcpdm , MCPDM_REG_IRQENABLE_CLR ,
MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL ) ;
/* Disable DMA request generation for uplink */
omap_mcpdm_write ( mcpdm , MCPDM_REG_DMAENABLE_CLR , MCPDM_DMA_UP_ENABLE ) ;
2011-09-26 17:05:58 +04:00
/* Disable RX1/2 offset cancellation */
if ( mcpdm - > dn_rx_offset )
omap_mcpdm_write ( mcpdm , MCPDM_REG_DN_OFFSET , 0 ) ;
2011-07-05 20:50:45 +04:00
}
static irqreturn_t omap_mcpdm_irq_handler ( int irq , void * dev_id )
{
struct omap_mcpdm * mcpdm = dev_id ;
int irq_status ;
irq_status = omap_mcpdm_read ( mcpdm , MCPDM_REG_IRQSTATUS ) ;
/* Acknowledge irq event */
omap_mcpdm_write ( mcpdm , MCPDM_REG_IRQSTATUS , irq_status ) ;
if ( irq_status & MCPDM_DN_IRQ_FULL )
dev_dbg ( mcpdm - > dev , " DN (playback) FIFO Full \n " ) ;
if ( irq_status & MCPDM_DN_IRQ_EMPTY )
dev_dbg ( mcpdm - > dev , " DN (playback) FIFO Empty \n " ) ;
if ( irq_status & MCPDM_DN_IRQ )
dev_dbg ( mcpdm - > dev , " DN (playback) write request \n " ) ;
if ( irq_status & MCPDM_UP_IRQ_FULL )
dev_dbg ( mcpdm - > dev , " UP (capture) FIFO Full \n " ) ;
if ( irq_status & MCPDM_UP_IRQ_EMPTY )
dev_dbg ( mcpdm - > dev , " UP (capture) FIFO Empty \n " ) ;
if ( irq_status & MCPDM_UP_IRQ )
dev_dbg ( mcpdm - > dev , " UP (capture) write request \n " ) ;
return IRQ_HANDLED ;
2010-02-23 00:09:22 +03:00
}
2011-07-05 20:50:45 +04:00
static int omap_mcpdm_dai_startup ( struct snd_pcm_substream * substream ,
2010-02-23 00:09:22 +03:00
struct snd_soc_dai * dai )
{
2011-07-05 20:50:45 +04:00
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( dai ) ;
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
mutex_lock ( & mcpdm - > mutex ) ;
2016-05-18 16:46:34 +03:00
if ( ! dai - > active )
2011-07-05 20:50:45 +04:00
omap_mcpdm_open_streams ( mcpdm ) ;
2016-05-18 16:46:34 +03:00
2011-07-05 20:50:45 +04:00
mutex_unlock ( & mcpdm - > mutex ) ;
return 0 ;
}
static void omap_mcpdm_dai_shutdown ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( dai ) ;
2018-11-14 14:06:22 +03:00
int tx = ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) ;
int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE ;
int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK ;
2011-07-05 20:50:45 +04:00
mutex_lock ( & mcpdm - > mutex ) ;
if ( ! dai - > active ) {
if ( omap_mcpdm_active ( mcpdm ) ) {
omap_mcpdm_stop ( mcpdm ) ;
omap_mcpdm_close_streams ( mcpdm ) ;
2013-03-20 13:47:13 +04:00
mcpdm - > config [ 0 ] . link_mask = 0 ;
mcpdm - > config [ 1 ] . link_mask = 0 ;
2011-07-05 20:50:45 +04:00
}
}
2018-11-14 14:06:22 +03:00
if ( mcpdm - > latency [ stream2 ] )
pm_qos_update_request ( & mcpdm - > pm_qos_req ,
mcpdm - > latency [ stream2 ] ) ;
else if ( mcpdm - > latency [ stream1 ] )
pm_qos_remove_request ( & mcpdm - > pm_qos_req ) ;
mcpdm - > latency [ stream1 ] = 0 ;
2011-07-05 20:50:45 +04:00
mutex_unlock ( & mcpdm - > mutex ) ;
2010-02-23 00:09:22 +03:00
}
static int omap_mcpdm_dai_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
2011-07-05 20:50:45 +04:00
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( dai ) ;
2010-02-23 00:09:22 +03:00
int stream = substream - > stream ;
2013-04-03 13:06:05 +04:00
struct snd_dmaengine_dai_dma_data * dma_data ;
2013-03-20 13:47:12 +04:00
u32 threshold ;
2018-11-14 14:06:22 +03:00
int channels , latency ;
2011-07-05 20:50:45 +04:00
int link_mask = 0 ;
2010-02-23 00:09:22 +03:00
channels = params_channels ( params ) ;
switch ( channels ) {
2011-09-23 10:49:43 +04:00
case 5 :
if ( stream = = SNDRV_PCM_STREAM_CAPTURE )
/* up to 3 channels for capture */
return - EINVAL ;
link_mask | = 1 < < 4 ;
2018-08-03 19:32:52 +03:00
/* fall through */
2010-02-23 00:09:22 +03:00
case 4 :
if ( stream = = SNDRV_PCM_STREAM_CAPTURE )
2011-09-23 10:49:43 +04:00
/* up to 3 channels for capture */
2010-02-23 00:09:22 +03:00
return - EINVAL ;
link_mask | = 1 < < 3 ;
2018-08-03 19:32:52 +03:00
/* fall through */
2010-02-23 00:09:22 +03:00
case 3 :
link_mask | = 1 < < 2 ;
2018-08-03 19:32:52 +03:00
/* fall through */
2010-02-23 00:09:22 +03:00
case 2 :
link_mask | = 1 < < 1 ;
2018-08-03 19:32:52 +03:00
/* fall through */
2010-02-23 00:09:22 +03:00
case 1 :
link_mask | = 1 < < 0 ;
break ;
default :
/* unsupported number of channels */
return - EINVAL ;
}
2012-09-14 16:05:57 +04:00
dma_data = snd_soc_dai_get_dma_data ( dai , substream ) ;
2011-08-02 14:35:30 +04:00
2013-03-20 13:47:12 +04:00
threshold = mcpdm - > config [ stream ] . threshold ;
2011-07-05 20:50:45 +04:00
/* Configure McPDM channels, and DMA packet size */
2010-02-23 00:09:22 +03:00
if ( stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
2013-03-20 13:47:12 +04:00
link_mask < < = 3 ;
2013-03-20 13:47:13 +04:00
/* If capture is not running assume a stereo stream to come */
if ( ! mcpdm - > config [ ! stream ] . link_mask )
mcpdm - > config [ ! stream ] . link_mask = 0x3 ;
2013-04-03 13:06:05 +04:00
dma_data - > maxburst =
2013-03-20 13:47:12 +04:00
( MCPDM_DN_THRES_MAX - threshold ) * channels ;
2018-11-14 14:06:22 +03:00
latency = threshold ;
2010-02-23 00:09:22 +03:00
} else {
2013-03-20 13:47:13 +04:00
/* If playback is not running assume a stereo stream to come */
if ( ! mcpdm - > config [ ! stream ] . link_mask )
mcpdm - > config [ ! stream ] . link_mask = ( 0x3 < < 3 ) ;
2013-04-03 13:06:05 +04:00
dma_data - > maxburst = threshold * channels ;
2018-11-14 14:06:22 +03:00
latency = ( MCPDM_DN_THRES_MAX - threshold ) ;
2010-02-23 00:09:22 +03:00
}
2018-11-14 14:06:22 +03:00
/*
* The DMA must act to a DMA request within latency time ( usec ) to avoid
* under / overflow
*/
mcpdm - > latency [ stream ] = latency * USEC_PER_SEC / params_rate ( params ) ;
if ( ! mcpdm - > latency [ stream ] )
mcpdm - > latency [ stream ] = 10 ;
2013-03-20 13:47:13 +04:00
/* Check if we need to restart McPDM with this stream */
if ( mcpdm - > config [ stream ] . link_mask & &
mcpdm - > config [ stream ] . link_mask ! = link_mask )
mcpdm - > restart = true ;
2013-03-20 13:47:12 +04:00
mcpdm - > config [ stream ] . link_mask = link_mask ;
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
return 0 ;
2010-02-23 00:09:22 +03:00
}
2011-07-05 20:50:45 +04:00
static int omap_mcpdm_prepare ( struct snd_pcm_substream * substream ,
2010-02-23 00:09:22 +03:00
struct snd_soc_dai * dai )
{
2011-07-05 20:50:45 +04:00
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( dai ) ;
2018-11-14 14:06:22 +03:00
struct pm_qos_request * pm_qos_req = & mcpdm - > pm_qos_req ;
int tx = ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) ;
int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE ;
int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK ;
int latency = mcpdm - > latency [ stream2 ] ;
/* Prevent omap hardware from hitting off between FIFO fills */
if ( ! latency | | mcpdm - > latency [ stream1 ] < latency )
latency = mcpdm - > latency [ stream1 ] ;
if ( pm_qos_request_active ( pm_qos_req ) )
pm_qos_update_request ( pm_qos_req , latency ) ;
else if ( latency )
pm_qos_add_request ( pm_qos_req , PM_QOS_CPU_DMA_LATENCY , latency ) ;
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
if ( ! omap_mcpdm_active ( mcpdm ) ) {
omap_mcpdm_start ( mcpdm ) ;
omap_mcpdm_reg_dump ( mcpdm ) ;
2013-03-20 13:47:13 +04:00
} else if ( mcpdm - > restart ) {
omap_mcpdm_stop ( mcpdm ) ;
omap_mcpdm_start ( mcpdm ) ;
mcpdm - > restart = false ;
omap_mcpdm_reg_dump ( mcpdm ) ;
2011-07-05 20:50:45 +04:00
}
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
return 0 ;
2010-02-23 00:09:22 +03:00
}
2011-11-23 14:40:40 +04:00
static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
2010-02-23 00:09:22 +03:00
. startup = omap_mcpdm_dai_startup ,
. shutdown = omap_mcpdm_dai_shutdown ,
. hw_params = omap_mcpdm_dai_hw_params ,
2011-07-05 20:50:45 +04:00
. prepare = omap_mcpdm_prepare ,
2010-02-23 00:09:22 +03:00
} ;
2011-07-05 20:50:45 +04:00
static int omap_mcpdm_probe ( struct snd_soc_dai * dai )
{
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( dai ) ;
int ret ;
pm_runtime_enable ( mcpdm - > dev ) ;
/* Disable lines while request is ongoing */
pm_runtime_get_sync ( mcpdm - > dev ) ;
omap_mcpdm_write ( mcpdm , MCPDM_REG_CTRL , 0x00 ) ;
2016-08-23 10:27:19 +03:00
ret = request_irq ( mcpdm - > irq , omap_mcpdm_irq_handler , 0 , " McPDM " ,
( void * ) mcpdm ) ;
2010-02-23 00:09:22 +03:00
2011-07-05 20:50:45 +04:00
pm_runtime_put_sync ( mcpdm - > dev ) ;
if ( ret ) {
dev_err ( mcpdm - > dev , " Request for IRQ failed \n " ) ;
pm_runtime_disable ( mcpdm - > dev ) ;
}
/* Configure McPDM threshold values */
2013-03-20 13:47:12 +04:00
mcpdm - > config [ SNDRV_PCM_STREAM_PLAYBACK ] . threshold = 2 ;
mcpdm - > config [ SNDRV_PCM_STREAM_CAPTURE ] . threshold =
MCPDM_UP_THRES_MAX - 3 ;
2014-04-16 16:46:13 +04:00
snd_soc_dai_init_dma_data ( dai ,
& mcpdm - > dma_data [ SNDRV_PCM_STREAM_PLAYBACK ] ,
& mcpdm - > dma_data [ SNDRV_PCM_STREAM_CAPTURE ] ) ;
2011-07-05 20:50:45 +04:00
return ret ;
}
static int omap_mcpdm_remove ( struct snd_soc_dai * dai )
2010-03-17 23:15:21 +03:00
{
2011-07-05 20:50:45 +04:00
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( dai ) ;
2016-08-23 10:27:19 +03:00
free_irq ( mcpdm - > irq , ( void * ) mcpdm ) ;
2011-07-05 20:50:45 +04:00
pm_runtime_disable ( mcpdm - > dev ) ;
2018-11-14 14:06:22 +03:00
if ( pm_qos_request_active ( & mcpdm - > pm_qos_req ) )
pm_qos_remove_request ( & mcpdm - > pm_qos_req ) ;
2010-03-17 23:15:21 +03:00
return 0 ;
}
2016-05-18 16:46:35 +03:00
# ifdef CONFIG_PM_SLEEP
static int omap_mcpdm_suspend ( struct snd_soc_dai * dai )
{
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( dai ) ;
if ( dai - > active ) {
omap_mcpdm_stop ( mcpdm ) ;
omap_mcpdm_close_streams ( mcpdm ) ;
}
mcpdm - > pm_active_count = 0 ;
while ( pm_runtime_active ( mcpdm - > dev ) ) {
pm_runtime_put_sync ( mcpdm - > dev ) ;
mcpdm - > pm_active_count + + ;
}
return 0 ;
}
static int omap_mcpdm_resume ( struct snd_soc_dai * dai )
{
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( dai ) ;
if ( mcpdm - > pm_active_count ) {
while ( mcpdm - > pm_active_count - - )
pm_runtime_get_sync ( mcpdm - > dev ) ;
if ( dai - > active ) {
omap_mcpdm_open_streams ( mcpdm ) ;
omap_mcpdm_start ( mcpdm ) ;
}
}
return 0 ;
}
# else
# define omap_mcpdm_suspend NULL
# define omap_mcpdm_resume NULL
# endif
2011-07-05 20:50:45 +04:00
# define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
# define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE
2010-03-17 23:15:21 +03:00
static struct snd_soc_dai_driver omap_mcpdm_dai = {
2011-07-05 20:50:45 +04:00
. probe = omap_mcpdm_probe ,
. remove = omap_mcpdm_remove ,
2016-05-18 16:46:35 +03:00
. suspend = omap_mcpdm_suspend ,
. resume = omap_mcpdm_resume ,
2011-07-05 20:50:45 +04:00
. probe_order = SND_SOC_COMP_ORDER_LATE ,
. remove_order = SND_SOC_COMP_ORDER_EARLY ,
2010-02-23 00:09:22 +03:00
. playback = {
. channels_min = 1 ,
2011-09-23 10:49:43 +04:00
. channels_max = 5 ,
2010-02-23 00:09:22 +03:00
. rates = OMAP_MCPDM_RATES ,
. formats = OMAP_MCPDM_FORMATS ,
2012-01-18 15:18:24 +04:00
. sig_bits = 24 ,
2010-02-23 00:09:22 +03:00
} ,
. capture = {
. channels_min = 1 ,
2011-09-23 10:49:43 +04:00
. channels_max = 3 ,
2010-02-23 00:09:22 +03:00
. rates = OMAP_MCPDM_RATES ,
. formats = OMAP_MCPDM_FORMATS ,
2012-01-18 15:18:24 +04:00
. sig_bits = 24 ,
2010-02-23 00:09:22 +03:00
} ,
. ops = & omap_mcpdm_dai_ops ,
} ;
2010-03-17 23:15:21 +03:00
2013-03-21 14:33:37 +04:00
static const struct snd_soc_component_driver omap_mcpdm_component = {
. name = " omap-mcpdm " ,
} ;
2011-09-26 17:05:58 +04:00
void omap_mcpdm_configure_dn_offsets ( struct snd_soc_pcm_runtime * rtd ,
u8 rx1 , u8 rx2 )
{
struct omap_mcpdm * mcpdm = snd_soc_dai_get_drvdata ( rtd - > cpu_dai ) ;
mcpdm - > dn_rx_offset = MCPDM_DNOFST_RX1 ( rx1 ) | MCPDM_DNOFST_RX2 ( rx2 ) ;
}
EXPORT_SYMBOL_GPL ( omap_mcpdm_configure_dn_offsets ) ;
2012-12-07 18:26:29 +04:00
static int asoc_mcpdm_probe ( struct platform_device * pdev )
2010-03-17 23:15:21 +03:00
{
2011-07-05 20:50:45 +04:00
struct omap_mcpdm * mcpdm ;
struct resource * res ;
2014-04-16 16:46:14 +04:00
int ret ;
2011-07-05 20:50:45 +04:00
2012-07-23 13:39:51 +04:00
mcpdm = devm_kzalloc ( & pdev - > dev , sizeof ( struct omap_mcpdm ) , GFP_KERNEL ) ;
2011-07-05 20:50:45 +04:00
if ( ! mcpdm )
return - ENOMEM ;
platform_set_drvdata ( pdev , mcpdm ) ;
mutex_init ( & mcpdm - > mutex ) ;
2012-09-14 16:05:54 +04:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " dma " ) ;
if ( res = = NULL )
return - ENOMEM ;
2013-04-03 13:06:05 +04:00
mcpdm - > dma_data [ 0 ] . addr = res - > start + MCPDM_REG_DN_DATA ;
mcpdm - > dma_data [ 1 ] . addr = res - > start + MCPDM_REG_UP_DATA ;
2012-09-14 16:05:54 +04:00
2013-07-11 16:35:44 +04:00
mcpdm - > dma_data [ 0 ] . filter_data = " dn_link " ;
mcpdm - > dma_data [ 1 ] . filter_data = " up_link " ;
2012-09-14 16:05:54 +04:00
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " mpu " ) ;
2013-03-11 19:58:57 +04:00
mcpdm - > io_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( mcpdm - > io_base ) )
return PTR_ERR ( mcpdm - > io_base ) ;
2011-07-05 20:50:45 +04:00
mcpdm - > irq = platform_get_irq ( pdev , 0 ) ;
2012-07-23 13:39:51 +04:00
if ( mcpdm - > irq < 0 )
return mcpdm - > irq ;
2011-07-05 20:50:45 +04:00
mcpdm - > dev = & pdev - > dev ;
2010-03-17 23:15:21 +03:00
2014-04-16 16:46:14 +04:00
ret = devm_snd_soc_register_component ( & pdev - > dev ,
2013-09-17 08:58:02 +04:00
& omap_mcpdm_component ,
& omap_mcpdm_dai , 1 ) ;
2014-04-16 16:46:14 +04:00
if ( ret )
return ret ;
2018-05-07 11:49:58 +03:00
return sdma_pcm_platform_register ( & pdev - > dev , " dn_link " , " up_link " ) ;
2010-03-17 23:15:21 +03:00
}
2011-11-15 13:32:14 +04:00
static const struct of_device_id omap_mcpdm_of_match [ ] = {
{ . compatible = " ti,omap4-mcpdm " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , omap_mcpdm_of_match ) ;
2010-03-17 23:15:21 +03:00
static struct platform_driver asoc_mcpdm_driver = {
. driver = {
2011-07-05 20:50:45 +04:00
. name = " omap-mcpdm " ,
2011-11-15 13:32:14 +04:00
. of_match_table = omap_mcpdm_of_match ,
2010-03-17 23:15:21 +03:00
} ,
2011-07-05 20:50:45 +04:00
. probe = asoc_mcpdm_probe ,
2010-03-17 23:15:21 +03:00
} ;
2010-02-23 00:09:22 +03:00
2011-11-25 06:12:16 +04:00
module_platform_driver ( asoc_mcpdm_driver ) ;
2010-02-23 00:09:22 +03:00
2012-07-06 14:19:10 +04:00
MODULE_ALIAS ( " platform:omap-mcpdm " ) ;
2011-07-05 20:50:45 +04:00
MODULE_AUTHOR ( " Misael Lopez Cruz <misael.lopez@ti.com> " ) ;
2010-02-23 00:09:22 +03:00
MODULE_DESCRIPTION ( " OMAP PDM SoC Interface " ) ;
MODULE_LICENSE ( " GPL " ) ;