1b3c70c9eSManuel Lauss /* 2b3c70c9eSManuel Lauss * Au1000/Au1500/Au1100 AC97C controller driver for ASoC 3b3c70c9eSManuel Lauss * 4b3c70c9eSManuel Lauss * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com> 5b3c70c9eSManuel Lauss * 6b3c70c9eSManuel Lauss * based on the old ALSA driver originally written by 7b3c70c9eSManuel Lauss * Charles Eidsness <charles@cooper-street.com> 8b3c70c9eSManuel Lauss */ 9b3c70c9eSManuel Lauss 10b3c70c9eSManuel Lauss #include <linux/init.h> 11b3c70c9eSManuel Lauss #include <linux/module.h> 12b3c70c9eSManuel Lauss #include <linux/slab.h> 13b3c70c9eSManuel Lauss #include <linux/device.h> 14b3c70c9eSManuel Lauss #include <linux/delay.h> 15b3c70c9eSManuel Lauss #include <linux/mutex.h> 16b3c70c9eSManuel Lauss #include <linux/platform_device.h> 17b3c70c9eSManuel Lauss #include <linux/suspend.h> 18b3c70c9eSManuel Lauss #include <sound/core.h> 19b3c70c9eSManuel Lauss #include <sound/pcm.h> 20b3c70c9eSManuel Lauss #include <sound/initval.h> 21b3c70c9eSManuel Lauss #include <sound/soc.h> 22b3c70c9eSManuel Lauss #include <asm/mach-au1x00/au1000.h> 23b3c70c9eSManuel Lauss 24b3c70c9eSManuel Lauss #include "psc.h" 25b3c70c9eSManuel Lauss 26b3c70c9eSManuel Lauss /* register offsets and bits */ 27b3c70c9eSManuel Lauss #define AC97_CONFIG 0x00 28b3c70c9eSManuel Lauss #define AC97_STATUS 0x04 29b3c70c9eSManuel Lauss #define AC97_DATA 0x08 30b3c70c9eSManuel Lauss #define AC97_CMDRESP 0x0c 31b3c70c9eSManuel Lauss #define AC97_ENABLE 0x10 32b3c70c9eSManuel Lauss 33b3c70c9eSManuel Lauss #define CFG_RC(x) (((x) & 0x3ff) << 13) /* valid rx slots mask */ 34b3c70c9eSManuel Lauss #define CFG_XS(x) (((x) & 0x3ff) << 3) /* valid tx slots mask */ 35b3c70c9eSManuel Lauss #define CFG_SG (1 << 2) /* sync gate */ 36b3c70c9eSManuel Lauss #define CFG_SN (1 << 1) /* sync control */ 37b3c70c9eSManuel Lauss #define CFG_RS (1 << 0) /* acrst# control */ 38b3c70c9eSManuel Lauss #define STAT_XU (1 << 11) /* tx underflow */ 39b3c70c9eSManuel Lauss #define STAT_XO (1 << 10) /* tx overflow */ 40b3c70c9eSManuel Lauss #define STAT_RU (1 << 9) /* rx underflow */ 41b3c70c9eSManuel Lauss #define STAT_RO (1 << 8) /* rx overflow */ 42b3c70c9eSManuel Lauss #define STAT_RD (1 << 7) /* codec ready */ 43b3c70c9eSManuel Lauss #define STAT_CP (1 << 6) /* command pending */ 44b3c70c9eSManuel Lauss #define STAT_TE (1 << 4) /* tx fifo empty */ 45b3c70c9eSManuel Lauss #define STAT_TF (1 << 3) /* tx fifo full */ 46b3c70c9eSManuel Lauss #define STAT_RE (1 << 1) /* rx fifo empty */ 47b3c70c9eSManuel Lauss #define STAT_RF (1 << 0) /* rx fifo full */ 48b3c70c9eSManuel Lauss #define CMD_SET_DATA(x) (((x) & 0xffff) << 16) 49b3c70c9eSManuel Lauss #define CMD_GET_DATA(x) ((x) & 0xffff) 50b3c70c9eSManuel Lauss #define CMD_READ (1 << 7) 51b3c70c9eSManuel Lauss #define CMD_WRITE (0 << 7) 52b3c70c9eSManuel Lauss #define CMD_IDX(x) ((x) & 0x7f) 53b3c70c9eSManuel Lauss #define EN_D (1 << 1) /* DISable bit */ 54b3c70c9eSManuel Lauss #define EN_CE (1 << 0) /* clock enable bit */ 55b3c70c9eSManuel Lauss 56b3c70c9eSManuel Lauss /* how often to retry failed codec register reads/writes */ 57b3c70c9eSManuel Lauss #define AC97_RW_RETRIES 5 58b3c70c9eSManuel Lauss 59b3c70c9eSManuel Lauss #define AC97_RATES \ 60b3c70c9eSManuel Lauss SNDRV_PCM_RATE_CONTINUOUS 61b3c70c9eSManuel Lauss 62b3c70c9eSManuel Lauss #define AC97_FMTS \ 63b3c70c9eSManuel Lauss (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE) 64b3c70c9eSManuel Lauss 65b3c70c9eSManuel Lauss /* instance data. There can be only one, MacLeod!!!!, fortunately there IS only 66b3c70c9eSManuel Lauss * once AC97C on early Alchemy chips. The newer ones aren't so lucky. 67b3c70c9eSManuel Lauss */ 68b3c70c9eSManuel Lauss static struct au1xpsc_audio_data *ac97c_workdata; 69b3c70c9eSManuel Lauss #define ac97_to_ctx(x) ac97c_workdata 70b3c70c9eSManuel Lauss 71b3c70c9eSManuel Lauss static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg) 72b3c70c9eSManuel Lauss { 73b3c70c9eSManuel Lauss return __raw_readl(ctx->mmio + reg); 74b3c70c9eSManuel Lauss } 75b3c70c9eSManuel Lauss 76b3c70c9eSManuel Lauss static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v) 77b3c70c9eSManuel Lauss { 78b3c70c9eSManuel Lauss __raw_writel(v, ctx->mmio + reg); 79b3c70c9eSManuel Lauss wmb(); 80b3c70c9eSManuel Lauss } 81b3c70c9eSManuel Lauss 82b3c70c9eSManuel Lauss static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97, 83b3c70c9eSManuel Lauss unsigned short r) 84b3c70c9eSManuel Lauss { 85b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97); 86b3c70c9eSManuel Lauss unsigned int tmo, retry; 87b3c70c9eSManuel Lauss unsigned long data; 88b3c70c9eSManuel Lauss 89b3c70c9eSManuel Lauss data = ~0; 90b3c70c9eSManuel Lauss retry = AC97_RW_RETRIES; 91b3c70c9eSManuel Lauss do { 92b3c70c9eSManuel Lauss mutex_lock(&ctx->lock); 93b3c70c9eSManuel Lauss 94b3c70c9eSManuel Lauss tmo = 5; 95b3c70c9eSManuel Lauss while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) 96b3c70c9eSManuel Lauss udelay(21); /* wait an ac97 frame time */ 97b3c70c9eSManuel Lauss if (!tmo) { 98b3c70c9eSManuel Lauss pr_debug("ac97rd timeout #1\n"); 99b3c70c9eSManuel Lauss goto next; 100b3c70c9eSManuel Lauss } 101b3c70c9eSManuel Lauss 102b3c70c9eSManuel Lauss WR(ctx, AC97_CMDRESP, CMD_IDX(r) | CMD_READ); 103b3c70c9eSManuel Lauss 104b3c70c9eSManuel Lauss /* stupid errata: data is only valid for 21us, so 105b3c70c9eSManuel Lauss * poll, Forrest, poll... 106b3c70c9eSManuel Lauss */ 107b3c70c9eSManuel Lauss tmo = 0x10000; 108b3c70c9eSManuel Lauss while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) 109b3c70c9eSManuel Lauss asm volatile ("nop"); 110b3c70c9eSManuel Lauss data = RD(ctx, AC97_CMDRESP); 111b3c70c9eSManuel Lauss 112b3c70c9eSManuel Lauss if (!tmo) 113b3c70c9eSManuel Lauss pr_debug("ac97rd timeout #2\n"); 114b3c70c9eSManuel Lauss 115b3c70c9eSManuel Lauss next: 116b3c70c9eSManuel Lauss mutex_unlock(&ctx->lock); 117b3c70c9eSManuel Lauss } while (--retry && !tmo); 118b3c70c9eSManuel Lauss 119b3c70c9eSManuel Lauss pr_debug("AC97RD %04x %04lx %d\n", r, data, retry); 120b3c70c9eSManuel Lauss 121b3c70c9eSManuel Lauss return retry ? data & 0xffff : 0xffff; 122b3c70c9eSManuel Lauss } 123b3c70c9eSManuel Lauss 124b3c70c9eSManuel Lauss static void au1xac97c_ac97_write(struct snd_ac97 *ac97, unsigned short r, 125b3c70c9eSManuel Lauss unsigned short v) 126b3c70c9eSManuel Lauss { 127b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97); 128b3c70c9eSManuel Lauss unsigned int tmo, retry; 129b3c70c9eSManuel Lauss 130b3c70c9eSManuel Lauss retry = AC97_RW_RETRIES; 131b3c70c9eSManuel Lauss do { 132b3c70c9eSManuel Lauss mutex_lock(&ctx->lock); 133b3c70c9eSManuel Lauss 134b3c70c9eSManuel Lauss for (tmo = 5; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--) 135b3c70c9eSManuel Lauss udelay(21); 136b3c70c9eSManuel Lauss if (!tmo) { 137b3c70c9eSManuel Lauss pr_debug("ac97wr timeout #1\n"); 138b3c70c9eSManuel Lauss goto next; 139b3c70c9eSManuel Lauss } 140b3c70c9eSManuel Lauss 141b3c70c9eSManuel Lauss WR(ctx, AC97_CMDRESP, CMD_WRITE | CMD_IDX(r) | CMD_SET_DATA(v)); 142b3c70c9eSManuel Lauss 143b3c70c9eSManuel Lauss for (tmo = 10; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--) 144b3c70c9eSManuel Lauss udelay(21); 145b3c70c9eSManuel Lauss if (!tmo) 146b3c70c9eSManuel Lauss pr_debug("ac97wr timeout #2\n"); 147b3c70c9eSManuel Lauss next: 148b3c70c9eSManuel Lauss mutex_unlock(&ctx->lock); 149b3c70c9eSManuel Lauss } while (--retry && !tmo); 150b3c70c9eSManuel Lauss 151b3c70c9eSManuel Lauss pr_debug("AC97WR %04x %04x %d\n", r, v, retry); 152b3c70c9eSManuel Lauss } 153b3c70c9eSManuel Lauss 154b3c70c9eSManuel Lauss static void au1xac97c_ac97_warm_reset(struct snd_ac97 *ac97) 155b3c70c9eSManuel Lauss { 156b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97); 157b3c70c9eSManuel Lauss 158b3c70c9eSManuel Lauss WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG | CFG_SN); 159b3c70c9eSManuel Lauss msleep(20); 160b3c70c9eSManuel Lauss WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG); 161b3c70c9eSManuel Lauss WR(ctx, AC97_CONFIG, ctx->cfg); 162b3c70c9eSManuel Lauss } 163b3c70c9eSManuel Lauss 164b3c70c9eSManuel Lauss static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97) 165b3c70c9eSManuel Lauss { 166b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97); 167b3c70c9eSManuel Lauss int i; 168b3c70c9eSManuel Lauss 169b3c70c9eSManuel Lauss WR(ctx, AC97_CONFIG, ctx->cfg | CFG_RS); 170b3c70c9eSManuel Lauss msleep(500); 171b3c70c9eSManuel Lauss WR(ctx, AC97_CONFIG, ctx->cfg); 172b3c70c9eSManuel Lauss 173b3c70c9eSManuel Lauss /* wait for codec ready */ 174b3c70c9eSManuel Lauss i = 50; 175b3c70c9eSManuel Lauss while (((RD(ctx, AC97_STATUS) & STAT_RD) == 0) && --i) 176b3c70c9eSManuel Lauss msleep(20); 177b3c70c9eSManuel Lauss if (!i) 178b3c70c9eSManuel Lauss printk(KERN_ERR "ac97c: codec not ready after cold reset\n"); 179b3c70c9eSManuel Lauss } 180b3c70c9eSManuel Lauss 181b3c70c9eSManuel Lauss /* AC97 controller operations */ 182b3c70c9eSManuel Lauss struct snd_ac97_bus_ops soc_ac97_ops = { 183b3c70c9eSManuel Lauss .read = au1xac97c_ac97_read, 184b3c70c9eSManuel Lauss .write = au1xac97c_ac97_write, 185b3c70c9eSManuel Lauss .reset = au1xac97c_ac97_cold_reset, 186b3c70c9eSManuel Lauss .warm_reset = au1xac97c_ac97_warm_reset, 187b3c70c9eSManuel Lauss }; 188b3c70c9eSManuel Lauss EXPORT_SYMBOL_GPL(soc_ac97_ops); /* globals be gone! */ 189b3c70c9eSManuel Lauss 190b3c70c9eSManuel Lauss static int alchemy_ac97c_startup(struct snd_pcm_substream *substream, 191b3c70c9eSManuel Lauss struct snd_soc_dai *dai) 192b3c70c9eSManuel Lauss { 193b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai); 194b3c70c9eSManuel Lauss snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]); 195b3c70c9eSManuel Lauss return 0; 196b3c70c9eSManuel Lauss } 197b3c70c9eSManuel Lauss 198b3c70c9eSManuel Lauss static struct snd_soc_dai_ops alchemy_ac97c_ops = { 199b3c70c9eSManuel Lauss .startup = alchemy_ac97c_startup, 200b3c70c9eSManuel Lauss }; 201b3c70c9eSManuel Lauss 202b3c70c9eSManuel Lauss static int au1xac97c_dai_probe(struct snd_soc_dai *dai) 203b3c70c9eSManuel Lauss { 204b3c70c9eSManuel Lauss return ac97c_workdata ? 0 : -ENODEV; 205b3c70c9eSManuel Lauss } 206b3c70c9eSManuel Lauss 207b3c70c9eSManuel Lauss static struct snd_soc_dai_driver au1xac97c_dai_driver = { 208b3c70c9eSManuel Lauss .name = "alchemy-ac97c", 209b3c70c9eSManuel Lauss .ac97_control = 1, 210b3c70c9eSManuel Lauss .probe = au1xac97c_dai_probe, 211b3c70c9eSManuel Lauss .playback = { 212b3c70c9eSManuel Lauss .rates = AC97_RATES, 213b3c70c9eSManuel Lauss .formats = AC97_FMTS, 214b3c70c9eSManuel Lauss .channels_min = 2, 215b3c70c9eSManuel Lauss .channels_max = 2, 216b3c70c9eSManuel Lauss }, 217b3c70c9eSManuel Lauss .capture = { 218b3c70c9eSManuel Lauss .rates = AC97_RATES, 219b3c70c9eSManuel Lauss .formats = AC97_FMTS, 220b3c70c9eSManuel Lauss .channels_min = 2, 221b3c70c9eSManuel Lauss .channels_max = 2, 222b3c70c9eSManuel Lauss }, 223b3c70c9eSManuel Lauss .ops = &alchemy_ac97c_ops, 224b3c70c9eSManuel Lauss }; 225b3c70c9eSManuel Lauss 226b3c70c9eSManuel Lauss static int __devinit au1xac97c_drvprobe(struct platform_device *pdev) 227b3c70c9eSManuel Lauss { 228b3c70c9eSManuel Lauss int ret; 229b3c70c9eSManuel Lauss struct resource *r; 230b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx; 231b3c70c9eSManuel Lauss 232b3c70c9eSManuel Lauss ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 233b3c70c9eSManuel Lauss if (!ctx) 234b3c70c9eSManuel Lauss return -ENOMEM; 235b3c70c9eSManuel Lauss 236b3c70c9eSManuel Lauss mutex_init(&ctx->lock); 237b3c70c9eSManuel Lauss 238b3c70c9eSManuel Lauss r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 239b3c70c9eSManuel Lauss if (!r) { 240b3c70c9eSManuel Lauss ret = -ENODEV; 241b3c70c9eSManuel Lauss goto out0; 242b3c70c9eSManuel Lauss } 243b3c70c9eSManuel Lauss 244b3c70c9eSManuel Lauss ret = -EBUSY; 245b3c70c9eSManuel Lauss if (!request_mem_region(r->start, resource_size(r), pdev->name)) 246b3c70c9eSManuel Lauss goto out0; 247b3c70c9eSManuel Lauss 248b3c70c9eSManuel Lauss ctx->mmio = ioremap_nocache(r->start, resource_size(r)); 249b3c70c9eSManuel Lauss if (!ctx->mmio) 250b3c70c9eSManuel Lauss goto out1; 251b3c70c9eSManuel Lauss 252b3c70c9eSManuel Lauss r = platform_get_resource(pdev, IORESOURCE_DMA, 0); 253b3c70c9eSManuel Lauss if (!r) 254b3c70c9eSManuel Lauss goto out1; 255b3c70c9eSManuel Lauss ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; 256b3c70c9eSManuel Lauss 257b3c70c9eSManuel Lauss r = platform_get_resource(pdev, IORESOURCE_DMA, 1); 258b3c70c9eSManuel Lauss if (!r) 259b3c70c9eSManuel Lauss goto out1; 260b3c70c9eSManuel Lauss ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; 261b3c70c9eSManuel Lauss 262b3c70c9eSManuel Lauss /* switch it on */ 263b3c70c9eSManuel Lauss WR(ctx, AC97_ENABLE, EN_D | EN_CE); 264b3c70c9eSManuel Lauss WR(ctx, AC97_ENABLE, EN_CE); 265b3c70c9eSManuel Lauss 266b3c70c9eSManuel Lauss ctx->cfg = CFG_RC(3) | CFG_XS(3); 267b3c70c9eSManuel Lauss WR(ctx, AC97_CONFIG, ctx->cfg); 268b3c70c9eSManuel Lauss 269b3c70c9eSManuel Lauss platform_set_drvdata(pdev, ctx); 270b3c70c9eSManuel Lauss 271b3c70c9eSManuel Lauss ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver); 272b3c70c9eSManuel Lauss if (ret) 273b3c70c9eSManuel Lauss goto out1; 274b3c70c9eSManuel Lauss 275b3c70c9eSManuel Lauss ac97c_workdata = ctx; 276b3c70c9eSManuel Lauss return 0; 277b3c70c9eSManuel Lauss 278b3c70c9eSManuel Lauss 279b3c70c9eSManuel Lauss snd_soc_unregister_dai(&pdev->dev); 280b3c70c9eSManuel Lauss out1: 281b3c70c9eSManuel Lauss release_mem_region(r->start, resource_size(r)); 282b3c70c9eSManuel Lauss out0: 283b3c70c9eSManuel Lauss kfree(ctx); 284b3c70c9eSManuel Lauss return ret; 285b3c70c9eSManuel Lauss } 286b3c70c9eSManuel Lauss 287b3c70c9eSManuel Lauss static int __devexit au1xac97c_drvremove(struct platform_device *pdev) 288b3c70c9eSManuel Lauss { 289b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); 290b3c70c9eSManuel Lauss struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 291b3c70c9eSManuel Lauss 292b3c70c9eSManuel Lauss snd_soc_unregister_dai(&pdev->dev); 293b3c70c9eSManuel Lauss 294b3c70c9eSManuel Lauss WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */ 295b3c70c9eSManuel Lauss 296b3c70c9eSManuel Lauss iounmap(ctx->mmio); 297b3c70c9eSManuel Lauss release_mem_region(r->start, resource_size(r)); 298b3c70c9eSManuel Lauss kfree(ctx); 299b3c70c9eSManuel Lauss 300b3c70c9eSManuel Lauss ac97c_workdata = NULL; /* MDEV */ 301b3c70c9eSManuel Lauss 302b3c70c9eSManuel Lauss return 0; 303b3c70c9eSManuel Lauss } 304b3c70c9eSManuel Lauss 305b3c70c9eSManuel Lauss #ifdef CONFIG_PM 306b3c70c9eSManuel Lauss static int au1xac97c_drvsuspend(struct device *dev) 307b3c70c9eSManuel Lauss { 308b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev); 309b3c70c9eSManuel Lauss 310b3c70c9eSManuel Lauss WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */ 311b3c70c9eSManuel Lauss 312b3c70c9eSManuel Lauss return 0; 313b3c70c9eSManuel Lauss } 314b3c70c9eSManuel Lauss 315b3c70c9eSManuel Lauss static int au1xac97c_drvresume(struct device *dev) 316b3c70c9eSManuel Lauss { 317b3c70c9eSManuel Lauss struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev); 318b3c70c9eSManuel Lauss 319b3c70c9eSManuel Lauss WR(ctx, AC97_ENABLE, EN_D | EN_CE); 320b3c70c9eSManuel Lauss WR(ctx, AC97_ENABLE, EN_CE); 321b3c70c9eSManuel Lauss WR(ctx, AC97_CONFIG, ctx->cfg); 322b3c70c9eSManuel Lauss 323b3c70c9eSManuel Lauss return 0; 324b3c70c9eSManuel Lauss } 325b3c70c9eSManuel Lauss 326b3c70c9eSManuel Lauss static const struct dev_pm_ops au1xpscac97_pmops = { 327b3c70c9eSManuel Lauss .suspend = au1xac97c_drvsuspend, 328b3c70c9eSManuel Lauss .resume = au1xac97c_drvresume, 329b3c70c9eSManuel Lauss }; 330b3c70c9eSManuel Lauss 331b3c70c9eSManuel Lauss #define AU1XPSCAC97_PMOPS (&au1xpscac97_pmops) 332b3c70c9eSManuel Lauss 333b3c70c9eSManuel Lauss #else 334b3c70c9eSManuel Lauss 335b3c70c9eSManuel Lauss #define AU1XPSCAC97_PMOPS NULL 336b3c70c9eSManuel Lauss 337b3c70c9eSManuel Lauss #endif 338b3c70c9eSManuel Lauss 339b3c70c9eSManuel Lauss static struct platform_driver au1xac97c_driver = { 340b3c70c9eSManuel Lauss .driver = { 341b3c70c9eSManuel Lauss .name = "alchemy-ac97c", 342b3c70c9eSManuel Lauss .owner = THIS_MODULE, 343b3c70c9eSManuel Lauss .pm = AU1XPSCAC97_PMOPS, 344b3c70c9eSManuel Lauss }, 345b3c70c9eSManuel Lauss .probe = au1xac97c_drvprobe, 346b3c70c9eSManuel Lauss .remove = __devexit_p(au1xac97c_drvremove), 347b3c70c9eSManuel Lauss }; 348b3c70c9eSManuel Lauss 349b3c70c9eSManuel Lauss static int __init au1xac97c_load(void) 350b3c70c9eSManuel Lauss { 351b3c70c9eSManuel Lauss ac97c_workdata = NULL; 352b3c70c9eSManuel Lauss return platform_driver_register(&au1xac97c_driver); 353b3c70c9eSManuel Lauss } 354b3c70c9eSManuel Lauss 355b3c70c9eSManuel Lauss static void __exit au1xac97c_unload(void) 356b3c70c9eSManuel Lauss { 357b3c70c9eSManuel Lauss platform_driver_unregister(&au1xac97c_driver); 358b3c70c9eSManuel Lauss } 359b3c70c9eSManuel Lauss 360b3c70c9eSManuel Lauss module_init(au1xac97c_load); 361b3c70c9eSManuel Lauss module_exit(au1xac97c_unload); 362b3c70c9eSManuel Lauss 363b3c70c9eSManuel Lauss MODULE_LICENSE("GPL"); 364b3c70c9eSManuel Lauss MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver"); 365b3c70c9eSManuel Lauss MODULE_AUTHOR("Manuel Lauss"); 366