Manuel Lauss | 4a161d2 | 2008-07-09 16:27:56 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Sample Au12x0/Au1550 PSC AC97 sound machine. |
| 3 | * |
| 4 | * Copyright (c) 2007-2008 Manuel Lauss <mano@roarinelk.homelinux.net> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms outlined in the file COPYING at the root of this |
| 8 | * source archive. |
| 9 | * |
| 10 | * This is a very generic AC97 sound machine driver for boards which |
| 11 | * have (AC97) audio at PSC1 (e.g. DB1200 demoboards). |
| 12 | */ |
| 13 | |
| 14 | #include <linux/module.h> |
| 15 | #include <linux/moduleparam.h> |
| 16 | #include <linux/timer.h> |
| 17 | #include <linux/interrupt.h> |
| 18 | #include <linux/platform_device.h> |
| 19 | #include <sound/core.h> |
| 20 | #include <sound/pcm.h> |
| 21 | #include <sound/soc.h> |
| 22 | #include <sound/soc-dapm.h> |
| 23 | #include <asm/mach-au1x00/au1000.h> |
| 24 | #include <asm/mach-au1x00/au1xxx_psc.h> |
| 25 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
| 26 | |
| 27 | #include "../codecs/ac97.h" |
| 28 | #include "psc.h" |
| 29 | |
| 30 | static int au1xpsc_sample_ac97_init(struct snd_soc_codec *codec) |
| 31 | { |
| 32 | snd_soc_dapm_sync(codec); |
| 33 | return 0; |
| 34 | } |
| 35 | |
| 36 | static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { |
| 37 | .name = "AC97", |
| 38 | .stream_name = "AC97 HiFi", |
| 39 | .cpu_dai = &au1xpsc_ac97_dai, /* see psc-ac97.c */ |
| 40 | .codec_dai = &ac97_dai, /* see codecs/ac97.c */ |
| 41 | .init = au1xpsc_sample_ac97_init, |
| 42 | .ops = NULL, |
| 43 | }; |
| 44 | |
Mark Brown | 8750654 | 2008-11-18 20:50:34 +0000 | [diff] [blame^] | 45 | static struct snd_soc_card au1xpsc_sample_ac97_machine = { |
Manuel Lauss | 4a161d2 | 2008-07-09 16:27:56 +0200 | [diff] [blame] | 46 | .name = "Au1xxx PSC AC97 Audio", |
| 47 | .dai_link = &au1xpsc_sample_ac97_dai, |
| 48 | .num_links = 1, |
| 49 | }; |
| 50 | |
| 51 | static struct snd_soc_device au1xpsc_sample_ac97_devdata = { |
Mark Brown | 8750654 | 2008-11-18 20:50:34 +0000 | [diff] [blame^] | 52 | .card = &au1xpsc_sample_ac97_machine, |
Manuel Lauss | 4a161d2 | 2008-07-09 16:27:56 +0200 | [diff] [blame] | 53 | .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ |
| 54 | .codec_dev = &soc_codec_dev_ac97, |
| 55 | }; |
| 56 | |
| 57 | static struct resource au1xpsc_psc1_res[] = { |
| 58 | [0] = { |
| 59 | .start = CPHYSADDR(PSC1_BASE_ADDR), |
| 60 | .end = CPHYSADDR(PSC1_BASE_ADDR) + 0x000fffff, |
| 61 | .flags = IORESOURCE_MEM, |
| 62 | }, |
| 63 | [1] = { |
| 64 | #ifdef CONFIG_SOC_AU1200 |
| 65 | .start = AU1200_PSC1_INT, |
| 66 | .end = AU1200_PSC1_INT, |
| 67 | #elif defined(CONFIG_SOC_AU1550) |
| 68 | .start = AU1550_PSC1_INT, |
| 69 | .end = AU1550_PSC1_INT, |
| 70 | #endif |
| 71 | .flags = IORESOURCE_IRQ, |
| 72 | }, |
| 73 | [2] = { |
| 74 | .start = DSCR_CMD0_PSC1_TX, |
| 75 | .end = DSCR_CMD0_PSC1_TX, |
| 76 | .flags = IORESOURCE_DMA, |
| 77 | }, |
| 78 | [3] = { |
| 79 | .start = DSCR_CMD0_PSC1_RX, |
| 80 | .end = DSCR_CMD0_PSC1_RX, |
| 81 | .flags = IORESOURCE_DMA, |
| 82 | }, |
| 83 | }; |
| 84 | |
| 85 | static struct platform_device *au1xpsc_sample_ac97_dev; |
| 86 | |
| 87 | static int __init au1xpsc_sample_ac97_load(void) |
| 88 | { |
| 89 | int ret; |
| 90 | |
| 91 | #ifdef CONFIG_SOC_AU1200 |
| 92 | unsigned long io; |
| 93 | |
| 94 | /* modify sys_pinfunc for AC97 on PSC1 */ |
| 95 | io = au_readl(SYS_PINFUNC); |
| 96 | io |= SYS_PINFUNC_P1C; |
| 97 | io &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B); |
| 98 | au_writel(io, SYS_PINFUNC); |
| 99 | au_sync(); |
| 100 | #endif |
| 101 | |
| 102 | ret = -ENOMEM; |
| 103 | |
| 104 | /* setup PSC clock source for AC97 part: external clock provided |
| 105 | * by codec. The psc-ac97.c driver depends on this setting! |
| 106 | */ |
| 107 | au_writel(PSC_SEL_CLK_SERCLK, PSC1_BASE_ADDR + PSC_SEL_OFFSET); |
| 108 | au_sync(); |
| 109 | |
| 110 | au1xpsc_sample_ac97_dev = platform_device_alloc("soc-audio", -1); |
| 111 | if (!au1xpsc_sample_ac97_dev) |
| 112 | goto out; |
| 113 | |
| 114 | au1xpsc_sample_ac97_dev->resource = |
| 115 | kmemdup(au1xpsc_psc1_res, sizeof(struct resource) * |
| 116 | ARRAY_SIZE(au1xpsc_psc1_res), GFP_KERNEL); |
| 117 | au1xpsc_sample_ac97_dev->num_resources = ARRAY_SIZE(au1xpsc_psc1_res); |
| 118 | au1xpsc_sample_ac97_dev->id = 1; |
| 119 | |
| 120 | platform_set_drvdata(au1xpsc_sample_ac97_dev, |
| 121 | &au1xpsc_sample_ac97_devdata); |
| 122 | au1xpsc_sample_ac97_devdata.dev = &au1xpsc_sample_ac97_dev->dev; |
| 123 | ret = platform_device_add(au1xpsc_sample_ac97_dev); |
| 124 | |
| 125 | if (ret) { |
| 126 | platform_device_put(au1xpsc_sample_ac97_dev); |
| 127 | au1xpsc_sample_ac97_dev = NULL; |
| 128 | } |
| 129 | |
| 130 | out: |
| 131 | return ret; |
| 132 | } |
| 133 | |
| 134 | static void __exit au1xpsc_sample_ac97_exit(void) |
| 135 | { |
| 136 | platform_device_unregister(au1xpsc_sample_ac97_dev); |
| 137 | } |
| 138 | |
| 139 | module_init(au1xpsc_sample_ac97_load); |
| 140 | module_exit(au1xpsc_sample_ac97_exit); |
| 141 | |
| 142 | MODULE_LICENSE("GPL"); |
| 143 | MODULE_DESCRIPTION("Au1xxx PSC sample AC97 machine"); |
| 144 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); |