diff options
Diffstat (limited to 'sound/soc/s3c24xx/s3c-i2s-v2.c')
-rw-r--r-- | sound/soc/s3c24xx/s3c-i2s-v2.c | 91 |
1 files changed, 77 insertions, 14 deletions
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index ab680aac3fcb..1a283170ca92 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c | |||
@@ -37,6 +37,20 @@ | |||
37 | 37 | ||
38 | #include "s3c-i2s-v2.h" | 38 | #include "s3c-i2s-v2.h" |
39 | 39 | ||
40 | #undef S3C_IIS_V2_SUPPORTED | ||
41 | |||
42 | #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) | ||
43 | #define S3C_IIS_V2_SUPPORTED | ||
44 | #endif | ||
45 | |||
46 | #ifdef CONFIG_PLAT_S3C64XX | ||
47 | #define S3C_IIS_V2_SUPPORTED | ||
48 | #endif | ||
49 | |||
50 | #ifndef S3C_IIS_V2_SUPPORTED | ||
51 | #error Unsupported CPU model | ||
52 | #endif | ||
53 | |||
40 | #define S3C2412_I2S_DEBUG_CON 0 | 54 | #define S3C2412_I2S_DEBUG_CON 0 |
41 | 55 | ||
42 | static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) | 56 | static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) |
@@ -75,7 +89,7 @@ static inline void dbg_showcon(const char *fn, u32 con) | |||
75 | 89 | ||
76 | 90 | ||
77 | /* Turn on or off the transmission path. */ | 91 | /* Turn on or off the transmission path. */ |
78 | void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) | 92 | static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) |
79 | { | 93 | { |
80 | void __iomem *regs = i2s->regs; | 94 | void __iomem *regs = i2s->regs; |
81 | u32 fic, con, mod; | 95 | u32 fic, con, mod; |
@@ -105,7 +119,9 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) | |||
105 | break; | 119 | break; |
106 | 120 | ||
107 | default: | 121 | default: |
108 | dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n"); | 122 | dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n", |
123 | mod & S3C2412_IISMOD_MODE_MASK); | ||
124 | break; | ||
109 | } | 125 | } |
110 | 126 | ||
111 | writel(con, regs + S3C2412_IISCON); | 127 | writel(con, regs + S3C2412_IISCON); |
@@ -132,7 +148,9 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) | |||
132 | break; | 148 | break; |
133 | 149 | ||
134 | default: | 150 | default: |
135 | dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n"); | 151 | dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n", |
152 | mod & S3C2412_IISMOD_MODE_MASK); | ||
153 | break; | ||
136 | } | 154 | } |
137 | 155 | ||
138 | writel(mod, regs + S3C2412_IISMOD); | 156 | writel(mod, regs + S3C2412_IISMOD); |
@@ -143,9 +161,8 @@ void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) | |||
143 | dbg_showcon(__func__, con); | 161 | dbg_showcon(__func__, con); |
144 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | 162 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); |
145 | } | 163 | } |
146 | EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl); | ||
147 | 164 | ||
148 | void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) | 165 | static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) |
149 | { | 166 | { |
150 | void __iomem *regs = i2s->regs; | 167 | void __iomem *regs = i2s->regs; |
151 | u32 fic, con, mod; | 168 | u32 fic, con, mod; |
@@ -175,7 +192,8 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) | |||
175 | break; | 192 | break; |
176 | 193 | ||
177 | default: | 194 | default: |
178 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | 195 | dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n", |
196 | mod & S3C2412_IISMOD_MODE_MASK); | ||
179 | } | 197 | } |
180 | 198 | ||
181 | writel(mod, regs + S3C2412_IISMOD); | 199 | writel(mod, regs + S3C2412_IISMOD); |
@@ -199,7 +217,8 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) | |||
199 | break; | 217 | break; |
200 | 218 | ||
201 | default: | 219 | default: |
202 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | 220 | dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n", |
221 | mod & S3C2412_IISMOD_MODE_MASK); | ||
203 | } | 222 | } |
204 | 223 | ||
205 | writel(con, regs + S3C2412_IISCON); | 224 | writel(con, regs + S3C2412_IISCON); |
@@ -209,7 +228,6 @@ void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) | |||
209 | fic = readl(regs + S3C2412_IISFIC); | 228 | fic = readl(regs + S3C2412_IISFIC); |
210 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | 229 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); |
211 | } | 230 | } |
212 | EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl); | ||
213 | 231 | ||
214 | /* | 232 | /* |
215 | * Wait for the LR signal to allow synchronisation to the L/R clock | 233 | * Wait for the LR signal to allow synchronisation to the L/R clock |
@@ -266,7 +284,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
266 | */ | 284 | */ |
267 | #define IISMOD_MASTER_MASK (1 << 11) | 285 | #define IISMOD_MASTER_MASK (1 << 11) |
268 | #define IISMOD_SLAVE (1 << 11) | 286 | #define IISMOD_SLAVE (1 << 11) |
269 | #define IISMOD_MASTER (0x0) | 287 | #define IISMOD_MASTER (0 << 11) |
270 | #endif | 288 | #endif |
271 | 289 | ||
272 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 290 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
@@ -281,7 +299,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
281 | iismod |= IISMOD_MASTER; | 299 | iismod |= IISMOD_MASTER; |
282 | break; | 300 | break; |
283 | default: | 301 | default: |
284 | pr_debug("unknwon master/slave format\n"); | 302 | pr_err("unknwon master/slave format\n"); |
285 | return -EINVAL; | 303 | return -EINVAL; |
286 | } | 304 | } |
287 | 305 | ||
@@ -298,7 +316,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
298 | iismod |= S3C2412_IISMOD_SDF_IIS; | 316 | iismod |= S3C2412_IISMOD_SDF_IIS; |
299 | break; | 317 | break; |
300 | default: | 318 | default: |
301 | pr_debug("Unknown data format\n"); | 319 | pr_err("Unknown data format\n"); |
302 | return -EINVAL; | 320 | return -EINVAL; |
303 | } | 321 | } |
304 | 322 | ||
@@ -327,6 +345,7 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | |||
327 | iismod = readl(i2s->regs + S3C2412_IISMOD); | 345 | iismod = readl(i2s->regs + S3C2412_IISMOD); |
328 | pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); | 346 | pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); |
329 | 347 | ||
348 | #if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) | ||
330 | switch (params_format(params)) { | 349 | switch (params_format(params)) { |
331 | case SNDRV_PCM_FORMAT_S8: | 350 | case SNDRV_PCM_FORMAT_S8: |
332 | iismod |= S3C2412_IISMOD_8BIT; | 351 | iismod |= S3C2412_IISMOD_8BIT; |
@@ -335,6 +354,25 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | |||
335 | iismod &= ~S3C2412_IISMOD_8BIT; | 354 | iismod &= ~S3C2412_IISMOD_8BIT; |
336 | break; | 355 | break; |
337 | } | 356 | } |
357 | #endif | ||
358 | |||
359 | #ifdef CONFIG_PLAT_S3C64XX | ||
360 | iismod &= ~0x606; | ||
361 | /* Sample size */ | ||
362 | switch (params_format(params)) { | ||
363 | case SNDRV_PCM_FORMAT_S8: | ||
364 | /* 8 bit sample, 16fs BCLK */ | ||
365 | iismod |= 0x2004; | ||
366 | break; | ||
367 | case SNDRV_PCM_FORMAT_S16_LE: | ||
368 | /* 16 bit sample, 32fs BCLK */ | ||
369 | break; | ||
370 | case SNDRV_PCM_FORMAT_S24_LE: | ||
371 | /* 24 bit sample, 48fs BCLK */ | ||
372 | iismod |= 0x4002; | ||
373 | break; | ||
374 | } | ||
375 | #endif | ||
338 | 376 | ||
339 | writel(iismod, i2s->regs + S3C2412_IISMOD); | 377 | writel(iismod, i2s->regs + S3C2412_IISMOD); |
340 | pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); | 378 | pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); |
@@ -489,6 +527,8 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, | |||
489 | unsigned int best_rate = 0; | 527 | unsigned int best_rate = 0; |
490 | unsigned int best_deviation = INT_MAX; | 528 | unsigned int best_deviation = INT_MAX; |
491 | 529 | ||
530 | pr_debug("Input clock rate %ldHz\n", clkrate); | ||
531 | |||
492 | if (fstab == NULL) | 532 | if (fstab == NULL) |
493 | fstab = iis_fs_tab; | 533 | fstab = iis_fs_tab; |
494 | 534 | ||
@@ -507,7 +547,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, | |||
507 | actual = clkrate / (fsdiv * div); | 547 | actual = clkrate / (fsdiv * div); |
508 | deviation = actual - rate; | 548 | deviation = actual - rate; |
509 | 549 | ||
510 | printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n", | 550 | printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n", |
511 | fsdiv, div, actual, deviation); | 551 | fsdiv, div, actual, deviation); |
512 | 552 | ||
513 | deviation = abs(deviation); | 553 | deviation = abs(deviation); |
@@ -523,7 +563,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, | |||
523 | break; | 563 | break; |
524 | } | 564 | } |
525 | 565 | ||
526 | printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n", | 566 | printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n", |
527 | best_fs, best_div, best_rate); | 567 | best_fs, best_div, best_rate); |
528 | 568 | ||
529 | info->fs_div = best_fs; | 569 | info->fs_div = best_fs; |
@@ -539,12 +579,31 @@ int s3c_i2sv2_probe(struct platform_device *pdev, | |||
539 | unsigned long base) | 579 | unsigned long base) |
540 | { | 580 | { |
541 | struct device *dev = &pdev->dev; | 581 | struct device *dev = &pdev->dev; |
582 | unsigned int iismod; | ||
542 | 583 | ||
543 | i2s->dev = dev; | 584 | i2s->dev = dev; |
544 | 585 | ||
545 | /* record our i2s structure for later use in the callbacks */ | 586 | /* record our i2s structure for later use in the callbacks */ |
546 | dai->private_data = i2s; | 587 | dai->private_data = i2s; |
547 | 588 | ||
589 | if (!base) { | ||
590 | struct resource *res = platform_get_resource(pdev, | ||
591 | IORESOURCE_MEM, | ||
592 | 0); | ||
593 | if (!res) { | ||
594 | dev_err(dev, "Unable to get register resource\n"); | ||
595 | return -ENXIO; | ||
596 | } | ||
597 | |||
598 | if (!request_mem_region(res->start, resource_size(res), | ||
599 | "s3c64xx-i2s-v4")) { | ||
600 | dev_err(dev, "Unable to request register region\n"); | ||
601 | return -EBUSY; | ||
602 | } | ||
603 | |||
604 | base = res->start; | ||
605 | } | ||
606 | |||
548 | i2s->regs = ioremap(base, 0x100); | 607 | i2s->regs = ioremap(base, 0x100); |
549 | if (i2s->regs == NULL) { | 608 | if (i2s->regs == NULL) { |
550 | dev_err(dev, "cannot ioremap registers\n"); | 609 | dev_err(dev, "cannot ioremap registers\n"); |
@@ -560,12 +619,16 @@ int s3c_i2sv2_probe(struct platform_device *pdev, | |||
560 | 619 | ||
561 | clk_enable(i2s->iis_pclk); | 620 | clk_enable(i2s->iis_pclk); |
562 | 621 | ||
622 | /* Mark ourselves as in TXRX mode so we can run through our cleanup | ||
623 | * process without warnings. */ | ||
624 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
625 | iismod |= S3C2412_IISMOD_MODE_TXRX; | ||
626 | writel(iismod, i2s->regs + S3C2412_IISMOD); | ||
563 | s3c2412_snd_txctrl(i2s, 0); | 627 | s3c2412_snd_txctrl(i2s, 0); |
564 | s3c2412_snd_rxctrl(i2s, 0); | 628 | s3c2412_snd_rxctrl(i2s, 0); |
565 | 629 | ||
566 | return 0; | 630 | return 0; |
567 | } | 631 | } |
568 | |||
569 | EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); | 632 | EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); |
570 | 633 | ||
571 | #ifdef CONFIG_PM | 634 | #ifdef CONFIG_PM |