2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2006-10-12 14:28:10 +02:00
/*
* pxa2xx - i2s . c - - ALSA Soc Audio Layer
*
* Copyright 2005 Wolfson Microelectronics PLC .
* Author : Liam Girdwood
2008-10-12 13:17:36 +01:00
* lrg @ slimlogic . co . uk
2006-10-12 14:28:10 +02:00
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/delay.h>
2008-05-26 03:28:09 +01:00
# include <linux/clk.h>
2008-08-31 00:45:02 +04:00
# include <linux/platform_device.h>
2012-04-02 10:24:08 +02:00
# include <linux/io.h>
2006-10-12 14:28:10 +02:00
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/initval.h>
# include <sound/soc.h>
2008-09-10 05:01:20 +04:00
# include <sound/pxa2xx-lib.h>
2013-08-12 10:42:39 +02:00
# include <sound/dmaengine_pcm.h>
2006-10-12 14:28:10 +02:00
2019-09-02 00:02:08 +02:00
# include <linux/platform_data/asoc-pxa.h>
2006-10-12 14:28:10 +02:00
2007-02-02 17:20:40 +01:00
# include "pxa2xx-i2s.h"
2006-10-12 14:28:10 +02:00
2008-09-08 15:37:50 +08:00
/*
* I2S Controller Register and Bit Definitions
*/
2019-09-18 10:52:31 +02:00
# define SACR0 (0x0000) /* Global Control Register */
# define SACR1 (0x0004) /* Serial Audio I 2 S/MSB-Justified Control Register */
# define SASR0 (0x000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
# define SAIMR (0x0014) /* Serial Audio Interrupt Mask Register */
# define SAICR (0x0018) /* Serial Audio Interrupt Clear Register */
# define SADIV (0x0060) /* Audio Clock Divider Register. */
# define SADR (0x0080) /* Serial Audio Data Register (TX and RX FIFO access Register). */
2008-09-08 15:37:50 +08:00
# define SACR0_RFTH(x) ((x) << 12) /* Rx FIFO Interrupt or DMA Trigger Threshold */
# define SACR0_TFTH(x) ((x) << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */
# define SACR0_STRF (1 << 5) /* FIFO Select for EFWR Special Function */
# define SACR0_EFWR (1 << 4) /* Enable EFWR Function */
# define SACR0_RST (1 << 3) /* FIFO, i2s Register Reset */
2017-02-25 22:50:29 +02:00
# define SACR0_BCKD (1 << 2) /* Bit Clock Direction */
2008-09-08 15:37:50 +08:00
# define SACR0_ENB (1 << 0) /* Enable I2S Link */
# define SACR1_ENLBF (1 << 5) /* Enable Loopback */
2017-02-25 22:50:29 +02:00
# define SACR1_DRPL (1 << 4) /* Disable Replaying Function */
2008-09-08 15:37:50 +08:00
# define SACR1_DREC (1 << 3) /* Disable Recording Function */
# define SACR1_AMSL (1 << 0) /* Specify Alternate Mode */
# define SASR0_I2SOFF (1 << 7) /* Controller Status */
# define SASR0_ROR (1 << 6) /* Rx FIFO Overrun */
# define SASR0_TUR (1 << 5) /* Tx FIFO Underrun */
# define SASR0_RFS (1 << 4) /* Rx FIFO Service Request */
# define SASR0_TFS (1 << 3) /* Tx FIFO Service Request */
# define SASR0_BSY (1 << 2) /* I2S Busy */
# define SASR0_RNE (1 << 1) /* Rx FIFO Not Empty */
2017-02-25 22:50:29 +02:00
# define SASR0_TNF (1 << 0) /* Tx FIFO Not Empty */
2008-09-08 15:37:50 +08:00
# define SAICR_ROR (1 << 6) /* Clear Rx FIFO Overrun Interrupt */
# define SAICR_TUR (1 << 5) /* Clear Tx FIFO Underrun Interrupt */
# define SAIMR_ROR (1 << 6) /* Enable Rx FIFO Overrun Condition Interrupt */
# define SAIMR_TUR (1 << 5) /* Enable Tx FIFO Underrun Condition Interrupt */
# define SAIMR_RFS (1 << 4) /* Enable Rx FIFO Service Interrupt */
# define SAIMR_TFS (1 << 3) /* Enable Tx FIFO Service Interrupt */
2008-09-10 05:01:20 +04:00
2006-10-12 14:28:10 +02:00
struct pxa_i2s_port {
u32 sadiv ;
u32 sacr0 ;
u32 sacr1 ;
u32 saimr ;
int master ;
2007-02-02 17:20:40 +01:00
u32 fmt ;
2006-10-12 14:28:10 +02:00
} ;
static struct pxa_i2s_port pxa_i2s ;
2008-05-26 03:28:09 +01:00
static struct clk * clk_i2s ;
2010-03-17 20:15:21 +00:00
static int clk_ena = 0 ;
2019-09-18 10:52:31 +02:00
static void __iomem * i2s_reg_base ;
2006-10-12 14:28:10 +02:00
2013-08-12 10:42:39 +02:00
static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = {
. addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ,
2018-06-28 22:08:37 +02:00
. chan_name = " tx " ,
2013-08-12 10:42:39 +02:00
. maxburst = 32 ,
2006-10-12 14:28:10 +02:00
} ;
2013-08-12 10:42:39 +02:00
static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
. addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ,
2018-06-28 22:08:37 +02:00
. chan_name = " rx " ,
2013-08-12 10:42:39 +02:00
. maxburst = 32 ,
2006-10-12 14:28:10 +02:00
} ;
2008-11-18 22:11:38 +00:00
static int pxa2xx_i2s_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
2006-10-12 14:28:10 +02:00
{
2020-07-20 10:18:20 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 14:19:49 +09:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
2006-10-12 14:28:10 +02:00
2008-05-26 03:28:09 +01:00
if ( IS_ERR ( clk_i2s ) )
return PTR_ERR ( clk_i2s ) ;
2020-05-15 09:47:41 +09:00
if ( ! snd_soc_dai_active ( cpu_dai ) )
2019-09-18 10:52:31 +02:00
writel ( 0 , i2s_reg_base + SACR0 ) ;
2006-10-12 14:28:10 +02:00
return 0 ;
}
/* wait for I2S controller to be ready */
static int pxa_i2s_wait ( void )
{
int i ;
/* flush the Rx FIFO */
2017-02-25 22:42:33 +02:00
for ( i = 0 ; i < 16 ; i + + )
2019-09-18 10:52:31 +02:00
readl ( i2s_reg_base + SADR ) ;
2006-10-12 14:28:10 +02:00
return 0 ;
}
2008-07-07 16:08:11 +01:00
static int pxa2xx_i2s_set_dai_fmt ( struct snd_soc_dai * cpu_dai ,
2007-02-02 17:20:40 +01:00
unsigned int fmt )
2006-10-12 14:28:10 +02:00
{
2007-02-02 17:20:40 +01:00
/* interface format */
switch ( fmt & SND_SOC_DAIFMT_FORMAT_MASK ) {
case SND_SOC_DAIFMT_I2S :
pxa_i2s . fmt = 0 ;
break ;
case SND_SOC_DAIFMT_LEFT_J :
pxa_i2s . fmt = SACR1_AMSL ;
break ;
}
2006-10-12 14:28:10 +02:00
2022-05-19 16:42:38 +01:00
switch ( fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK ) {
case SND_SOC_DAIFMT_BP_FP :
2006-10-12 14:28:10 +02:00
pxa_i2s . master = 1 ;
2007-02-02 17:20:40 +01:00
break ;
2022-05-19 16:42:38 +01:00
case SND_SOC_DAIFMT_BC_FP :
2007-02-02 17:20:40 +01:00
pxa_i2s . master = 0 ;
break ;
default :
break ;
}
return 0 ;
}
2006-10-12 14:28:10 +02:00
2008-07-07 16:08:11 +01:00
static int pxa2xx_i2s_set_dai_sysclk ( struct snd_soc_dai * cpu_dai ,
2007-02-02 17:20:40 +01:00
int clk_id , unsigned int freq , int dir )
{
if ( clk_id ! = PXA2XX_I2S_SYSCLK )
return - ENODEV ;
return 0 ;
}
static int pxa2xx_i2s_hw_params ( struct snd_pcm_substream * substream ,
2008-11-18 22:11:38 +00:00
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
2007-02-02 17:20:40 +01:00
{
2013-08-12 10:42:39 +02:00
struct snd_dmaengine_dai_dma_data * dma_data ;
2007-02-02 17:20:40 +01:00
2013-11-05 18:40:03 +01:00
if ( WARN_ON ( IS_ERR ( clk_i2s ) ) )
return - EINVAL ;
2012-03-15 19:16:12 +01:00
clk_prepare_enable ( clk_i2s ) ;
2010-03-17 20:15:21 +00:00
clk_ena = 1 ;
2006-10-12 14:28:10 +02:00
pxa_i2s_wait ( ) ;
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
2010-03-22 10:11:15 +01:00
dma_data = & pxa2xx_i2s_pcm_stereo_out ;
2006-10-12 14:28:10 +02:00
else
2010-03-22 10:11:15 +01:00
dma_data = & pxa2xx_i2s_pcm_stereo_in ;
2010-03-17 20:15:21 +00:00
snd_soc_dai_set_dma_data ( dai , substream , dma_data ) ;
2006-10-12 14:28:10 +02:00
/* is port used by another stream */
if ( ! ( SACR0 & SACR0_ENB ) ) {
2019-09-18 10:52:31 +02:00
writel ( 0 , i2s_reg_base + SACR0 ) ;
2006-10-12 14:28:10 +02:00
if ( pxa_i2s . master )
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SACR0 ) | ( SACR0_BCKD ) , i2s_reg_base + SACR0 ) ;
2006-10-12 14:28:10 +02:00
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SACR0 ) | ( SACR0_RFTH ( 14 ) | SACR0_TFTH ( 1 ) ) , i2s_reg_base + SACR0 ) ;
writel ( readl ( i2s_reg_base + SACR1 ) | ( pxa_i2s . fmt ) , i2s_reg_base + SACR1 ) ;
2006-10-12 14:28:10 +02:00
}
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SAIMR ) | ( SAIMR_TFS ) , i2s_reg_base + SAIMR ) ;
2006-10-12 14:28:10 +02:00
else
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SAIMR ) | ( SAIMR_RFS ) , i2s_reg_base + SAIMR ) ;
2006-10-12 14:28:10 +02:00
2007-02-02 17:20:40 +01:00
switch ( params_rate ( params ) ) {
case 8000 :
2019-09-18 10:52:31 +02:00
writel ( 0x48 , i2s_reg_base + SADIV ) ;
2007-02-02 17:20:40 +01:00
break ;
case 11025 :
2019-09-18 10:52:31 +02:00
writel ( 0x34 , i2s_reg_base + SADIV ) ;
2007-02-02 17:20:40 +01:00
break ;
case 16000 :
2019-09-18 10:52:31 +02:00
writel ( 0x24 , i2s_reg_base + SADIV ) ;
2007-02-02 17:20:40 +01:00
break ;
case 22050 :
2019-09-18 10:52:31 +02:00
writel ( 0x1a , i2s_reg_base + SADIV ) ;
2007-02-02 17:20:40 +01:00
break ;
case 44100 :
2019-09-18 10:52:31 +02:00
writel ( 0xd , i2s_reg_base + SADIV ) ;
2007-02-02 17:20:40 +01:00
break ;
case 48000 :
2019-09-18 10:52:31 +02:00
writel ( 0xc , i2s_reg_base + SADIV ) ;
2007-02-02 17:20:40 +01:00
break ;
case 96000 : /* not in manual and possibly slightly inaccurate */
2019-09-18 10:52:31 +02:00
writel ( 0x6 , i2s_reg_base + SADIV ) ;
2007-02-02 17:20:40 +01:00
break ;
}
2006-10-12 14:28:10 +02:00
return 0 ;
}
2008-11-18 22:11:38 +00:00
static int pxa2xx_i2s_trigger ( struct snd_pcm_substream * substream , int cmd ,
struct snd_soc_dai * dai )
2006-10-12 14:28:10 +02:00
{
int ret = 0 ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
2009-05-13 22:16:46 +02:00
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SACR1 ) & ( ~ SACR1_DRPL ) , i2s_reg_base + SACR1 ) ;
2009-05-13 22:16:46 +02:00
else
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SACR1 ) & ( ~ SACR1_DREC ) , i2s_reg_base + SACR1 ) ;
writel ( readl ( i2s_reg_base + SACR0 ) | ( SACR0_ENB ) , i2s_reg_base + SACR0 ) ;
2006-10-12 14:28:10 +02:00
break ;
case SNDRV_PCM_TRIGGER_RESUME :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_SUSPEND :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
break ;
default :
ret = - EINVAL ;
}
return ret ;
}
2008-11-18 22:11:38 +00:00
static void pxa2xx_i2s_shutdown ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
2006-10-12 14:28:10 +02:00
{
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SACR1 ) | ( SACR1_DRPL ) , i2s_reg_base + SACR1 ) ;
writel ( readl ( i2s_reg_base + SAIMR ) & ( ~ SAIMR_TFS ) , i2s_reg_base + SAIMR ) ;
2006-10-12 14:28:10 +02:00
} else {
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SACR1 ) | ( SACR1_DREC ) , i2s_reg_base + SACR1 ) ;
writel ( readl ( i2s_reg_base + SAIMR ) & ( ~ SAIMR_RFS ) , i2s_reg_base + SAIMR ) ;
2006-10-12 14:28:10 +02:00
}
2019-09-18 10:52:31 +02:00
if ( ( readl ( i2s_reg_base + SACR1 ) & ( SACR1_DREC | SACR1_DRPL ) ) = = ( SACR1_DREC | SACR1_DRPL ) ) {
writel ( readl ( i2s_reg_base + SACR0 ) & ( ~ SACR0_ENB ) , i2s_reg_base + SACR0 ) ;
2006-10-12 14:28:10 +02:00
pxa_i2s_wait ( ) ;
2010-03-17 20:15:21 +00:00
if ( clk_ena ) {
2012-03-15 19:16:12 +01:00
clk_disable_unprepare ( clk_i2s ) ;
2010-03-17 20:15:21 +00:00
clk_ena = 0 ;
2009-07-01 18:23:26 +01:00
}
2006-10-12 14:28:10 +02:00
}
}
# ifdef CONFIG_PM
2020-01-20 10:04:59 +09:00
static int pxa2xx_soc_pcm_suspend ( struct snd_soc_component * component )
2006-10-12 14:28:10 +02:00
{
/* store registers */
2019-09-18 10:52:31 +02:00
pxa_i2s . sacr0 = readl ( i2s_reg_base + SACR0 ) ;
pxa_i2s . sacr1 = readl ( i2s_reg_base + SACR1 ) ;
pxa_i2s . saimr = readl ( i2s_reg_base + SAIMR ) ;
pxa_i2s . sadiv = readl ( i2s_reg_base + SADIV ) ;
2006-10-12 14:28:10 +02:00
/* deactivate link */
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SACR0 ) & ( ~ SACR0_ENB ) , i2s_reg_base + SACR0 ) ;
2006-10-12 14:28:10 +02:00
pxa_i2s_wait ( ) ;
return 0 ;
}
2020-01-20 10:04:59 +09:00
static int pxa2xx_soc_pcm_resume ( struct snd_soc_component * component )
2006-10-12 14:28:10 +02:00
{
pxa_i2s_wait ( ) ;
2019-09-18 10:52:31 +02:00
writel ( pxa_i2s . sacr0 & ~ SACR0_ENB , i2s_reg_base + SACR0 ) ;
writel ( pxa_i2s . sacr1 , i2s_reg_base + SACR1 ) ;
writel ( pxa_i2s . saimr , i2s_reg_base + SAIMR ) ;
writel ( pxa_i2s . sadiv , i2s_reg_base + SADIV ) ;
2009-05-13 22:16:59 +02:00
2019-09-18 10:52:31 +02:00
writel ( pxa_i2s . sacr0 , i2s_reg_base + SACR0 ) ;
2006-10-12 14:28:10 +02:00
return 0 ;
}
# else
2020-01-20 10:04:59 +09:00
# define pxa2xx_soc_pcm_suspend NULL
# define pxa2xx_soc_pcm_resume NULL
2006-10-12 14:28:10 +02:00
# endif
2010-03-17 20:15:21 +00:00
static int pxa2xx_i2s_probe ( struct snd_soc_dai * dai )
{
clk_i2s = clk_get ( dai - > dev , " I2SCLK " ) ;
if ( IS_ERR ( clk_i2s ) )
return PTR_ERR ( clk_i2s ) ;
/*
* PXA Developer ' s Manual :
* If SACR0 [ ENB ] is toggled in the middle of a normal operation ,
* the SACR0 [ RST ] bit must also be set and cleared to reset all
* I2S controller registers .
*/
2019-09-18 10:52:31 +02:00
writel ( SACR0_RST , i2s_reg_base + SACR0 ) ;
writel ( 0 , i2s_reg_base + SACR0 ) ;
2010-03-17 20:15:21 +00:00
/* Make sure RPL and REC are disabled */
2019-09-18 10:52:31 +02:00
writel ( SACR1_DRPL | SACR1_DREC , i2s_reg_base + SACR1 ) ;
2010-03-17 20:15:21 +00:00
/* Along with FIFO servicing */
2019-09-18 10:52:31 +02:00
writel ( readl ( i2s_reg_base + SAIMR ) & ( ~ ( SAIMR_RFS | SAIMR_TFS ) ) , i2s_reg_base + SAIMR ) ;
2010-03-17 20:15:21 +00:00
2015-09-30 22:51:52 +02:00
snd_soc_dai_init_dma_data ( dai , & pxa2xx_i2s_pcm_stereo_out ,
& pxa2xx_i2s_pcm_stereo_in ) ;
2010-03-17 20:15:21 +00:00
return 0 ;
}
static int pxa2xx_i2s_remove ( struct snd_soc_dai * dai )
{
clk_put ( clk_i2s ) ;
clk_i2s = ERR_PTR ( - ENOENT ) ;
return 0 ;
}
2007-02-02 17:20:40 +01:00
# define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 )
2006-10-12 14:28:10 +02:00
2011-11-23 11:40:40 +01:00
static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
2009-03-03 09:41:00 +08:00
. startup = pxa2xx_i2s_startup ,
. shutdown = pxa2xx_i2s_shutdown ,
. trigger = pxa2xx_i2s_trigger ,
. hw_params = pxa2xx_i2s_hw_params ,
2022-05-19 16:43:05 +01:00
. set_fmt = pxa2xx_i2s_set_dai_fmt ,
2009-03-03 09:41:00 +08:00
. set_sysclk = pxa2xx_i2s_set_dai_sysclk ,
} ;
2010-03-17 20:15:21 +00:00
static struct snd_soc_dai_driver pxa_i2s_dai = {
. probe = pxa2xx_i2s_probe ,
. remove = pxa2xx_i2s_remove ,
2006-10-12 14:28:10 +02:00
. playback = {
. channels_min = 2 ,
2007-02-02 17:20:40 +01:00
. channels_max = 2 ,
. rates = PXA2XX_I2S_RATES ,
. formats = SNDRV_PCM_FMTBIT_S16_LE , } ,
2006-10-12 14:28:10 +02:00
. capture = {
. channels_min = 2 ,
2007-02-02 17:20:40 +01:00
. channels_max = 2 ,
. rates = PXA2XX_I2S_RATES ,
. formats = SNDRV_PCM_FMTBIT_S16_LE , } ,
2009-03-03 09:41:00 +08:00
. ops = & pxa_i2s_dai_ops ,
2021-01-15 13:53:58 +09:00
. symmetric_rate = 1 ,
2006-10-12 14:28:10 +02:00
} ;
2013-03-21 03:34:37 -07:00
static const struct snd_soc_component_driver pxa_i2s_component = {
2022-06-23 13:51:42 +01:00
. name = " pxa-i2s " ,
. pcm_construct = pxa2xx_soc_pcm_new ,
. open = pxa2xx_soc_pcm_open ,
. close = pxa2xx_soc_pcm_close ,
. hw_params = pxa2xx_soc_pcm_hw_params ,
. prepare = pxa2xx_soc_pcm_prepare ,
. trigger = pxa2xx_soc_pcm_trigger ,
. pointer = pxa2xx_soc_pcm_pointer ,
. suspend = pxa2xx_soc_pcm_suspend ,
. resume = pxa2xx_soc_pcm_resume ,
. legacy_dai_naming = 1 ,
2013-03-21 03:34:37 -07:00
} ;
2010-03-17 20:15:21 +00:00
static int pxa2xx_i2s_drv_probe ( struct platform_device * pdev )
2008-08-31 00:45:02 +04:00
{
2019-09-18 10:52:31 +02:00
struct resource * res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " missing MMIO resource \n " ) ;
return - ENXIO ;
}
i2s_reg_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( i2s_reg_base ) ) {
dev_err ( & pdev - > dev , " ioremap failed \n " ) ;
return PTR_ERR ( i2s_reg_base ) ;
}
pxa2xx_i2s_pcm_stereo_out . addr = res - > start + SADR ;
pxa2xx_i2s_pcm_stereo_in . addr = res - > start + SADR ;
2015-08-28 10:49:44 +08:00
return devm_snd_soc_register_component ( & pdev - > dev , & pxa_i2s_component ,
& pxa_i2s_dai , 1 ) ;
2008-08-31 00:45:02 +04:00
}
static struct platform_driver pxa2xx_i2s_driver = {
2010-03-17 20:15:21 +00:00
. probe = pxa2xx_i2s_drv_probe ,
2008-08-31 00:45:02 +04:00
. driver = {
. name = " pxa2xx-i2s " ,
} ,
} ;
static int __init pxa2xx_i2s_init ( void )
{
clk_i2s = ERR_PTR ( - ENOENT ) ;
return platform_driver_register ( & pxa2xx_i2s_driver ) ;
}
static void __exit pxa2xx_i2s_exit ( void )
{
platform_driver_unregister ( & pxa2xx_i2s_driver ) ;
}
module_init ( pxa2xx_i2s_init ) ;
module_exit ( pxa2xx_i2s_exit ) ;
2006-10-12 14:28:10 +02:00
/* Module information */
2008-10-12 13:17:36 +01:00
MODULE_AUTHOR ( " Liam Girdwood, lrg@slimlogic.co.uk " ) ;
2006-10-12 14:28:10 +02:00
MODULE_DESCRIPTION ( " pxa2xx I2S SoC Interface " ) ;
MODULE_LICENSE ( " GPL " ) ;
2010-08-20 17:18:45 +01:00
MODULE_ALIAS ( " platform:pxa2xx-i2s " ) ;