linux/sound/soc/au1x/psc-ac97.c
<<
>>
Prefs
   1/*
   2 * Au12x0/Au1550 PSC ALSA ASoC audio support.
   3 *
   4 * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
   5 *      Manuel Lauss <mano@roarinelk.homelinux.net>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * Au1xxx-PSC AC97 glue.
  12 *
  13 * NOTE: all of these drivers can only work with a SINGLE instance
  14 *       of a PSC. Multiple independent audio devices are impossible
  15 *       with ASoC v1.
  16 */
  17
  18#include <linux/init.h>
  19#include <linux/module.h>
  20#include <linux/device.h>
  21#include <linux/delay.h>
  22#include <linux/suspend.h>
  23#include <sound/core.h>
  24#include <sound/pcm.h>
  25#include <sound/initval.h>
  26#include <sound/soc.h>
  27#include <asm/mach-au1x00/au1000.h>
  28#include <asm/mach-au1x00/au1xxx_psc.h>
  29
  30#include "psc.h"
  31
  32#define AC97_DIR        \
  33        (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
  34
  35#define AC97_RATES      \
  36        SNDRV_PCM_RATE_8000_48000
  37
  38#define AC97_FMTS       \
  39        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE)
  40
  41#define AC97PCR_START(stype)    \
  42        ((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS)
  43#define AC97PCR_STOP(stype)     \
  44        ((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP)
  45#define AC97PCR_CLRFIFO(stype)  \
  46        ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC)
  47
  48/* instance data. There can be only one, MacLeod!!!! */
  49static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
  50
  51/* AC97 controller reads codec register */
  52static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
  53                                        unsigned short reg)
  54{
  55        /* FIXME */
  56        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
  57        unsigned short data, tmo;
  58
  59        au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata));
  60        au_sync();
  61
  62        tmo = 1000;
  63        while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo)
  64                udelay(2);
  65
  66        if (!tmo)
  67                data = 0xffff;
  68        else
  69                data = au_readl(AC97_CDC(pscdata)) & 0xffff;
  70
  71        au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
  72        au_sync();
  73
  74        return data;
  75}
  76
  77/* AC97 controller writes to codec register */
  78static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
  79                                unsigned short val)
  80{
  81        /* FIXME */
  82        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
  83        unsigned int tmo;
  84
  85        au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata));
  86        au_sync();
  87        tmo = 1000;
  88        while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo)
  89                au_sync();
  90
  91        au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
  92        au_sync();
  93}
  94
  95/* AC97 controller asserts a warm reset */
  96static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
  97{
  98        /* FIXME */
  99        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
 100
 101        au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
 102        au_sync();
 103        msleep(10);
 104        au_writel(0, AC97_RST(pscdata));
 105        au_sync();
 106}
 107
 108static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
 109{
 110        /* FIXME */
 111        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
 112        int i;
 113
 114        /* disable PSC during cold reset */
 115        au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
 116        au_sync();
 117        au_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata));
 118        au_sync();
 119
 120        /* issue cold reset */
 121        au_writel(PSC_AC97RST_RST, AC97_RST(pscdata));
 122        au_sync();
 123        msleep(500);
 124        au_writel(0, AC97_RST(pscdata));
 125        au_sync();
 126
 127        /* enable PSC */
 128        au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata));
 129        au_sync();
 130
 131        /* wait for PSC to indicate it's ready */
 132        i = 100000;
 133        while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i))
 134                au_sync();
 135
 136        if (i == 0) {
 137                printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n");
 138                return;
 139        }
 140
 141        /* enable the ac97 function */
 142        au_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
 143        au_sync();
 144
 145        /* wait for AC97 core to become ready */
 146        i = 100000;
 147        while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i))
 148                au_sync();
 149        if (i == 0)
 150                printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n");
 151}
 152
 153/* AC97 controller operations */
 154struct snd_ac97_bus_ops soc_ac97_ops = {
 155        .read           = au1xpsc_ac97_read,
 156        .write          = au1xpsc_ac97_write,
 157        .reset          = au1xpsc_ac97_cold_reset,
 158        .warm_reset     = au1xpsc_ac97_warm_reset,
 159};
 160EXPORT_SYMBOL_GPL(soc_ac97_ops);
 161
 162static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
 163                                  struct snd_pcm_hw_params *params,
 164                                  struct snd_soc_dai *dai)
 165{
 166        /* FIXME */
 167        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
 168        unsigned long r, stat;
 169        int chans, stype = SUBSTREAM_TYPE(substream);
 170
 171        chans = params_channels(params);
 172
 173        r = au_readl(AC97_CFG(pscdata));
 174        stat = au_readl(AC97_STAT(pscdata));
 175
 176        /* already active? */
 177        if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) {
 178                /* reject parameters not currently set up */
 179                if ((PSC_AC97CFG_GET_LEN(r) != params->msbits) ||
 180                    (pscdata->rate != params_rate(params)))
 181                        return -EINVAL;
 182        } else {
 183                /* disable AC97 device controller first */
 184                au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
 185                au_sync();
 186
 187                /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */
 188                r &= ~PSC_AC97CFG_LEN_MASK;
 189                r |= PSC_AC97CFG_SET_LEN(params->msbits);
 190
 191                /* channels: enable slots for front L/R channel */
 192                if (stype == PCM_TX) {
 193                        r &= ~PSC_AC97CFG_TXSLOT_MASK;
 194                        r |= PSC_AC97CFG_TXSLOT_ENA(3);
 195                        r |= PSC_AC97CFG_TXSLOT_ENA(4);
 196                } else {
 197                        r &= ~PSC_AC97CFG_RXSLOT_MASK;
 198                        r |= PSC_AC97CFG_RXSLOT_ENA(3);
 199                        r |= PSC_AC97CFG_RXSLOT_ENA(4);
 200                }
 201
 202                /* finally enable the AC97 controller again */
 203                au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
 204                au_sync();
 205
 206                pscdata->cfg = r;
 207                pscdata->rate = params_rate(params);
 208        }
 209
 210        return 0;
 211}
 212
 213static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
 214                                int cmd, struct snd_soc_dai *dai)
 215{
 216        /* FIXME */
 217        struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
 218        int ret, stype = SUBSTREAM_TYPE(substream);
 219
 220        ret = 0;
 221
 222        switch (cmd) {
 223        case SNDRV_PCM_TRIGGER_START:
 224        case SNDRV_PCM_TRIGGER_RESUME:
 225                au_writel(AC97PCR_START(stype), AC97_PCR(pscdata));
 226                au_sync();
 227                break;
 228        case SNDRV_PCM_TRIGGER_STOP:
 229        case SNDRV_PCM_TRIGGER_SUSPEND:
 230                au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata));
 231                au_sync();
 232                break;
 233        default:
 234                ret = -EINVAL;
 235        }
 236        return ret;
 237}
 238
 239static int au1xpsc_ac97_probe(struct platform_device *pdev,
 240                              struct snd_soc_dai *dai)
 241{
 242        int ret;
 243        struct resource *r;
 244        unsigned long sel;
 245
 246        if (au1xpsc_ac97_workdata)
 247                return -EBUSY;
 248
 249        au1xpsc_ac97_workdata =
 250                kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
 251        if (!au1xpsc_ac97_workdata)
 252                return -ENOMEM;
 253
 254        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 255        if (!r) {
 256                ret = -ENODEV;
 257                goto out0;
 258        }
 259
 260        ret = -EBUSY;
 261        au1xpsc_ac97_workdata->ioarea =
 262                request_mem_region(r->start, r->end - r->start + 1,
 263                                        "au1xpsc_ac97");
 264        if (!au1xpsc_ac97_workdata->ioarea)
 265                goto out0;
 266
 267        au1xpsc_ac97_workdata->mmio = ioremap(r->start, 0xffff);
 268        if (!au1xpsc_ac97_workdata->mmio)
 269                goto out1;
 270
 271        /* configuration: max dma trigger threshold, enable ac97 */
 272         au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 |
 273                                      PSC_AC97CFG_TT_FIFO8 |
 274                                      PSC_AC97CFG_DE_ENABLE;
 275
 276        /* preserve PSC clock source set up by platform (dev.platform_data
 277         * is already occupied by soc layer)
 278         */
 279        sel = au_readl(PSC_SEL(au1xpsc_ac97_workdata)) & PSC_SEL_CLK_MASK;
 280        au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
 281        au_sync();
 282        au_writel(0, PSC_SEL(au1xpsc_ac97_workdata));
 283        au_sync();
 284        au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(au1xpsc_ac97_workdata));
 285        au_sync();
 286        /* next up: cold reset.  Dont check for PSC-ready now since
 287         * there may not be any codec clock yet.
 288         */
 289
 290        return 0;
 291
 292out1:
 293        release_resource(au1xpsc_ac97_workdata->ioarea);
 294        kfree(au1xpsc_ac97_workdata->ioarea);
 295out0:
 296        kfree(au1xpsc_ac97_workdata);
 297        au1xpsc_ac97_workdata = NULL;
 298        return ret;
 299}
 300
 301static void au1xpsc_ac97_remove(struct platform_device *pdev,
 302                                struct snd_soc_dai *dai)
 303{
 304        /* disable PSC completely */
 305        au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
 306        au_sync();
 307        au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
 308        au_sync();
 309
 310        iounmap(au1xpsc_ac97_workdata->mmio);
 311        release_resource(au1xpsc_ac97_workdata->ioarea);
 312        kfree(au1xpsc_ac97_workdata->ioarea);
 313        kfree(au1xpsc_ac97_workdata);
 314        au1xpsc_ac97_workdata = NULL;
 315}
 316
 317static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai)
 318{
 319        /* save interesting registers and disable PSC */
 320        au1xpsc_ac97_workdata->pm[0] =
 321                        au_readl(PSC_SEL(au1xpsc_ac97_workdata));
 322
 323        au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
 324        au_sync();
 325        au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
 326        au_sync();
 327
 328        return 0;
 329}
 330
 331static int au1xpsc_ac97_resume(struct snd_soc_dai *dai)
 332{
 333        /* restore PSC clock config */
 334        au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE,
 335                        PSC_SEL(au1xpsc_ac97_workdata));
 336        au_sync();
 337
 338        /* after this point the ac97 core will cold-reset the codec.
 339         * During cold-reset the PSC is reinitialized and the last
 340         * configuration set up in hw_params() is restored.
 341         */
 342        return 0;
 343}
 344
 345static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
 346        .trigger        = au1xpsc_ac97_trigger,
 347        .hw_params      = au1xpsc_ac97_hw_params,
 348};
 349
 350struct snd_soc_dai au1xpsc_ac97_dai = {
 351        .name                   = "au1xpsc_ac97",
 352        .ac97_control           = 1,
 353        .probe                  = au1xpsc_ac97_probe,
 354        .remove                 = au1xpsc_ac97_remove,
 355        .suspend                = au1xpsc_ac97_suspend,
 356        .resume                 = au1xpsc_ac97_resume,
 357        .playback = {
 358                .rates          = AC97_RATES,
 359                .formats        = AC97_FMTS,
 360                .channels_min   = 2,
 361                .channels_max   = 2,
 362        },
 363        .capture = {
 364                .rates          = AC97_RATES,
 365                .formats        = AC97_FMTS,
 366                .channels_min   = 2,
 367                .channels_max   = 2,
 368        },
 369        .ops = &au1xpsc_ac97_dai_ops,
 370};
 371EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
 372
 373static int __init au1xpsc_ac97_init(void)
 374{
 375        au1xpsc_ac97_workdata = NULL;
 376        return snd_soc_register_dai(&au1xpsc_ac97_dai);
 377}
 378
 379static void __exit au1xpsc_ac97_exit(void)
 380{
 381        snd_soc_unregister_dai(&au1xpsc_ac97_dai);
 382}
 383
 384module_init(au1xpsc_ac97_init);
 385module_exit(au1xpsc_ac97_exit);
 386
 387MODULE_LICENSE("GPL");
 388MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver");
 389MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
 390
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.