| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 1 | /* sound/soc/s3c24xx/s3c2412-i2s.c | 
|  | 2 | * | 
|  | 3 | * ALSA Soc Audio Layer - S3C2412 I2S driver | 
|  | 4 | * | 
|  | 5 | * Copyright (c) 2006 Wolfson Microelectronics PLC. | 
|  | 6 | *	Graeme Gregory graeme.gregory@wolfsonmicro.com | 
|  | 7 | *	linux@wolfsonmicro.com | 
|  | 8 | * | 
|  | 9 | * Copyright (c) 2007, 2004-2005 Simtec Electronics | 
|  | 10 | *	http://armlinux.simtec.co.uk/ | 
|  | 11 | *	Ben Dooks <ben@simtec.co.uk> | 
|  | 12 | * | 
|  | 13 | * This program is free software; you can redistribute  it and/or modify it | 
|  | 14 | * under  the terms of  the GNU General  Public License as published by the | 
|  | 15 | * Free Software Foundation;  either version 2 of the  License, or (at your | 
|  | 16 | * option) any later version. | 
|  | 17 | */ | 
|  | 18 |  | 
|  | 19 | #include <linux/init.h> | 
|  | 20 | #include <linux/module.h> | 
|  | 21 | #include <linux/device.h> | 
|  | 22 | #include <linux/delay.h> | 
|  | 23 | #include <linux/clk.h> | 
|  | 24 | #include <linux/kernel.h> | 
| Ben Dooks | 8150bc8 | 2009-03-04 00:49:26 +0000 | [diff] [blame] | 25 | #include <linux/io.h> | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 26 |  | 
|  | 27 | #include <sound/core.h> | 
|  | 28 | #include <sound/pcm.h> | 
|  | 29 | #include <sound/pcm_params.h> | 
|  | 30 | #include <sound/initval.h> | 
|  | 31 | #include <sound/soc.h> | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 32 | #include <mach/hardware.h> | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 33 |  | 
| Ben Dooks | 8150bc8 | 2009-03-04 00:49:26 +0000 | [diff] [blame] | 34 | #include <plat/regs-s3c2412-iis.h> | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 35 |  | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 36 | #include <plat/regs-gpio.h> | 
| Ben Dooks | 899e6cf | 2009-03-04 00:49:28 +0000 | [diff] [blame] | 37 | #include <plat/audio.h> | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 38 | #include <mach/dma.h> | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 39 |  | 
|  | 40 | #include "s3c24xx-pcm.h" | 
|  | 41 | #include "s3c2412-i2s.h" | 
|  | 42 |  | 
|  | 43 | #define S3C2412_I2S_DEBUG 0 | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 44 |  | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 45 | static struct s3c2410_dma_client s3c2412_dma_client_out = { | 
|  | 46 | .name		= "I2S PCM Stereo out" | 
|  | 47 | }; | 
|  | 48 |  | 
|  | 49 | static struct s3c2410_dma_client s3c2412_dma_client_in = { | 
|  | 50 | .name		= "I2S PCM Stereo in" | 
|  | 51 | }; | 
|  | 52 |  | 
|  | 53 | static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = { | 
|  | 54 | .client		= &s3c2412_dma_client_out, | 
|  | 55 | .channel	= DMACH_I2S_OUT, | 
|  | 56 | .dma_addr	= S3C2410_PA_IIS + S3C2412_IISTXD, | 
|  | 57 | .dma_size	= 4, | 
|  | 58 | }; | 
|  | 59 |  | 
|  | 60 | static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = { | 
|  | 61 | .client		= &s3c2412_dma_client_in, | 
|  | 62 | .channel	= DMACH_I2S_IN, | 
|  | 63 | .dma_addr	= S3C2410_PA_IIS + S3C2412_IISRXD, | 
|  | 64 | .dma_size	= 4, | 
|  | 65 | }; | 
|  | 66 |  | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 67 | static struct s3c_i2sv2_info s3c2412_i2s; | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 68 |  | 
|  | 69 | /* | 
|  | 70 | * Set S3C2412 Clock source | 
|  | 71 | */ | 
| Liam Girdwood | 1992a6f | 2008-07-07 16:08:24 +0100 | [diff] [blame] | 72 | static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 73 | int clk_id, unsigned int freq, int dir) | 
|  | 74 | { | 
|  | 75 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | 
|  | 76 |  | 
| Mark Brown | ee7d476 | 2009-03-06 18:04:34 +0000 | [diff] [blame] | 77 | pr_debug("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id, | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 78 | freq, dir); | 
|  | 79 |  | 
|  | 80 | switch (clk_id) { | 
|  | 81 | case S3C2412_CLKSRC_PCLK: | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 82 | s3c2412_i2s.master = 1; | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 83 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | 
|  | 84 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; | 
|  | 85 | break; | 
|  | 86 | case S3C2412_CLKSRC_I2SCLK: | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 87 | s3c2412_i2s.master = 0; | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 88 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | 
|  | 89 | iismod |= S3C2412_IISMOD_MASTER_EXTERNAL; | 
|  | 90 | break; | 
|  | 91 | default: | 
|  | 92 | return -EINVAL; | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD); | 
|  | 96 | return 0; | 
|  | 97 | } | 
|  | 98 |  | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 99 |  | 
|  | 100 | struct clk *s3c2412_get_iisclk(void) | 
|  | 101 | { | 
|  | 102 | return s3c2412_i2s.iis_clk; | 
|  | 103 | } | 
|  | 104 | EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); | 
|  | 105 |  | 
|  | 106 |  | 
| Mark Brown | bdb9287 | 2008-06-11 13:47:10 +0100 | [diff] [blame] | 107 | static int s3c2412_i2s_probe(struct platform_device *pdev, | 
| Liam Girdwood | 1992a6f | 2008-07-07 16:08:24 +0100 | [diff] [blame] | 108 | struct snd_soc_dai *dai) | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 109 | { | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 110 | int ret; | 
|  | 111 |  | 
| Mark Brown | ee7d476 | 2009-03-06 18:04:34 +0000 | [diff] [blame] | 112 | pr_debug("Entered %s\n", __func__); | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 113 |  | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 114 | ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS); | 
|  | 115 | if (ret) | 
|  | 116 | return ret; | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 117 |  | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 118 | s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in; | 
|  | 119 | s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out; | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 120 |  | 
|  | 121 | s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); | 
|  | 122 | if (s3c2412_i2s.iis_cclk == NULL) { | 
| Mark Brown | ee7d476 | 2009-03-06 18:04:34 +0000 | [diff] [blame] | 123 | pr_debug("failed to get i2sclk clock\n"); | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 124 | iounmap(s3c2412_i2s.regs); | 
|  | 125 | return -ENODEV; | 
|  | 126 | } | 
|  | 127 |  | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 128 | /* Set MPLL as the source for IIS CLK */ | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 129 |  | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 130 | clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 131 | clk_enable(s3c2412_i2s.iis_cclk); | 
|  | 132 |  | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 133 | s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk; | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 134 |  | 
|  | 135 | /* Configure the I2S pins in correct mode */ | 
|  | 136 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); | 
|  | 137 | s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); | 
|  | 138 | s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK); | 
|  | 139 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); | 
|  | 140 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); | 
|  | 141 |  | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 142 | return 0; | 
|  | 143 | } | 
|  | 144 |  | 
|  | 145 | #define S3C2412_I2S_RATES \ | 
|  | 146 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | 
|  | 147 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 
|  | 148 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 
|  | 149 |  | 
| Eric Miao | 6335d05 | 2009-03-03 09:41:00 +0800 | [diff] [blame] | 150 | static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = { | 
| Eric Miao | 6335d05 | 2009-03-03 09:41:00 +0800 | [diff] [blame] | 151 | .set_sysclk	= s3c2412_i2s_set_sysclk, | 
|  | 152 | }; | 
|  | 153 |  | 
| Liam Girdwood | 1992a6f | 2008-07-07 16:08:24 +0100 | [diff] [blame] | 154 | struct snd_soc_dai s3c2412_i2s_dai = { | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 155 | .name		= "s3c2412-i2s", | 
|  | 156 | .id		= 0, | 
|  | 157 | .probe		= s3c2412_i2s_probe, | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 158 | .playback = { | 
|  | 159 | .channels_min	= 2, | 
|  | 160 | .channels_max	= 2, | 
|  | 161 | .rates		= S3C2412_I2S_RATES, | 
|  | 162 | .formats	= SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, | 
|  | 163 | }, | 
|  | 164 | .capture = { | 
|  | 165 | .channels_min	= 2, | 
|  | 166 | .channels_max	= 2, | 
|  | 167 | .rates		= S3C2412_I2S_RATES, | 
|  | 168 | .formats	= SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, | 
|  | 169 | }, | 
| Eric Miao | 6335d05 | 2009-03-03 09:41:00 +0800 | [diff] [blame] | 170 | .ops = &s3c2412_i2s_dai_ops, | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 171 | }; | 
|  | 172 | EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); | 
|  | 173 |  | 
| Takashi Iwai | c9b3a40 | 2008-12-10 07:47:22 +0100 | [diff] [blame] | 174 | static int __init s3c2412_i2s_init(void) | 
| Mark Brown | 3f4b783 | 2008-12-03 19:26:35 +0000 | [diff] [blame] | 175 | { | 
| Ben Dooks | dc85447 | 2009-03-04 00:49:30 +0000 | [diff] [blame] | 176 | return  s3c_i2sv2_register_dai(&s3c2412_i2s_dai); | 
| Mark Brown | 3f4b783 | 2008-12-03 19:26:35 +0000 | [diff] [blame] | 177 | } | 
|  | 178 | module_init(s3c2412_i2s_init); | 
|  | 179 |  | 
|  | 180 | static void __exit s3c2412_i2s_exit(void) | 
|  | 181 | { | 
|  | 182 | snd_soc_unregister_dai(&s3c2412_i2s_dai); | 
|  | 183 | } | 
|  | 184 | module_exit(s3c2412_i2s_exit); | 
|  | 185 |  | 
| Ben Dooks | 49646df | 2008-01-10 14:47:21 +0100 | [diff] [blame] | 186 | /* Module information */ | 
|  | 187 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | 
|  | 188 | MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); | 
|  | 189 | MODULE_LICENSE("GPL"); |