root/sound/soc/sh/hac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hac_get_codec_data
  2. hac_read_codec_aux
  3. hac_ac97_write
  4. hac_ac97_read
  5. hac_ac97_warmrst
  6. hac_ac97_coldrst
  7. hac_hw_params
  8. hac_soc_platform_probe
  9. hac_soc_platform_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 //
   3 // Hitachi Audio Controller (AC97) support for SH7760/SH7780
   4 //
   5 // Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
   6 //
   7 // dont forget to set IPSEL/OMSEL register bits (in your board code) to
   8 // enable HAC output pins!
   9 
  10 /* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
  11  * the FIRST can be used since ASoC does not pass any information to the
  12  * ac97_read/write() functions regarding WHICH unit to use.  You'll have
  13  * to edit the code a bit to use the other AC97 unit.           --mlau
  14  */
  15 
  16 #include <linux/init.h>
  17 #include <linux/module.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/interrupt.h>
  20 #include <linux/wait.h>
  21 #include <linux/delay.h>
  22 #include <sound/core.h>
  23 #include <sound/pcm.h>
  24 #include <sound/ac97_codec.h>
  25 #include <sound/initval.h>
  26 #include <sound/soc.h>
  27 
  28 /* regs and bits */
  29 #define HACCR           0x08
  30 #define HACCSAR         0x20
  31 #define HACCSDR         0x24
  32 #define HACPCML         0x28
  33 #define HACPCMR         0x2C
  34 #define HACTIER         0x50
  35 #define HACTSR          0x54
  36 #define HACRIER         0x58
  37 #define HACRSR          0x5C
  38 #define HACACR          0x60
  39 
  40 #define CR_CR           (1 << 15)       /* "codec-ready" indicator */
  41 #define CR_CDRT         (1 << 11)       /* cold reset */
  42 #define CR_WMRT         (1 << 10)       /* warm reset */
  43 #define CR_B9           (1 << 9)        /* the mysterious "bit 9" */
  44 #define CR_ST           (1 << 5)        /* AC97 link start bit */
  45 
  46 #define CSAR_RD         (1 << 19)       /* AC97 data read bit */
  47 #define CSAR_WR         (0)
  48 
  49 #define TSR_CMDAMT      (1 << 31)
  50 #define TSR_CMDDMT      (1 << 30)
  51 
  52 #define RSR_STARY       (1 << 22)
  53 #define RSR_STDRY       (1 << 21)
  54 
  55 #define ACR_DMARX16     (1 << 30)
  56 #define ACR_DMATX16     (1 << 29)
  57 #define ACR_TX12ATOM    (1 << 26)
  58 #define ACR_DMARX20     ((1 << 24) | (1 << 22))
  59 #define ACR_DMATX20     ((1 << 23) | (1 << 21))
  60 
  61 #define CSDR_SHIFT      4
  62 #define CSDR_MASK       (0xffff << CSDR_SHIFT)
  63 #define CSAR_SHIFT      12
  64 #define CSAR_MASK       (0x7f << CSAR_SHIFT)
  65 
  66 #define AC97_WRITE_RETRY        1
  67 #define AC97_READ_RETRY         5
  68 
  69 /* manual-suggested AC97 codec access timeouts (us) */
  70 #define TMO_E1  500     /* 21 < E1 < 1000 */
  71 #define TMO_E2  13      /* 13 < E2 */
  72 #define TMO_E3  21      /* 21 < E3 */
  73 #define TMO_E4  500     /* 21 < E4 < 1000 */
  74 
  75 struct hac_priv {
  76         unsigned long mmio;     /* HAC base address */
  77 } hac_cpu_data[] = {
  78 #if defined(CONFIG_CPU_SUBTYPE_SH7760)
  79         {
  80                 .mmio   = 0xFE240000,
  81         },
  82         {
  83                 .mmio   = 0xFE250000,
  84         },
  85 #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
  86         {
  87                 .mmio   = 0xFFE40000,
  88         },
  89 #else
  90 #error "Unsupported SuperH SoC"
  91 #endif
  92 };
  93 
  94 #define HACREG(reg)     (*(unsigned long *)(hac->mmio + (reg)))
  95 
  96 /*
  97  * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
  98  */
  99 static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
 100                               unsigned short *v)
 101 {
 102         unsigned int to1, to2, i;
 103         unsigned short adr;
 104 
 105         for (i = AC97_READ_RETRY; i; i--) {
 106                 *v = 0;
 107                 /* wait for HAC to receive something from the codec */
 108                 for (to1 = TMO_E4;
 109                      to1 && !(HACREG(HACRSR) & RSR_STARY);
 110                      --to1)
 111                         udelay(1);
 112                 for (to2 = TMO_E4; 
 113                      to2 && !(HACREG(HACRSR) & RSR_STDRY);
 114                      --to2)
 115                         udelay(1);
 116 
 117                 if (!to1 && !to2)
 118                         return 0;       /* codec comm is down */
 119 
 120                 adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
 121                 *v  = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
 122 
 123                 HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
 124 
 125                 if (r == adr)
 126                         break;
 127 
 128                 /* manual says: wait at least 21 usec before retrying */
 129                 udelay(21);
 130         }
 131         HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
 132         return i;
 133 }
 134 
 135 static unsigned short hac_read_codec_aux(struct hac_priv *hac,
 136                                          unsigned short reg)
 137 {
 138         unsigned short val;
 139         unsigned int i, to;
 140 
 141         for (i = AC97_READ_RETRY; i; i--) {
 142                 /* send_read_request */
 143                 local_irq_disable();
 144                 HACREG(HACTSR) &= ~(TSR_CMDAMT);
 145                 HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
 146                 local_irq_enable();
 147 
 148                 for (to = TMO_E3;
 149                      to && !(HACREG(HACTSR) & TSR_CMDAMT);
 150                      --to)
 151                         udelay(1);
 152 
 153                 HACREG(HACTSR) &= ~TSR_CMDAMT;
 154                 val = 0;
 155                 if (hac_get_codec_data(hac, reg, &val) != 0)
 156                         break;
 157         }
 158 
 159         return i ? val : ~0;
 160 }
 161 
 162 static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 163                            unsigned short val)
 164 {
 165         int unit_id = 0 /* ac97->private_data */;
 166         struct hac_priv *hac = &hac_cpu_data[unit_id];
 167         unsigned int i, to;
 168         /* write_codec_aux */
 169         for (i = AC97_WRITE_RETRY; i; i--) {
 170                 /* send_write_request */
 171                 local_irq_disable();
 172                 HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
 173                 HACREG(HACCSDR) = (val << CSDR_SHIFT);
 174                 HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
 175                 local_irq_enable();
 176 
 177                 /* poll-wait for CMDAMT and CMDDMT */
 178                 for (to = TMO_E1;
 179                      to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
 180                      --to)
 181                         udelay(1);
 182 
 183                 HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
 184                 if (to)
 185                         break;
 186                 /* timeout, try again */
 187         }
 188 }
 189 
 190 static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
 191                                     unsigned short reg)
 192 {
 193         int unit_id = 0 /* ac97->private_data */;
 194         struct hac_priv *hac = &hac_cpu_data[unit_id];
 195         return hac_read_codec_aux(hac, reg);
 196 }
 197 
 198 static void hac_ac97_warmrst(struct snd_ac97 *ac97)
 199 {
 200         int unit_id = 0 /* ac97->private_data */;
 201         struct hac_priv *hac = &hac_cpu_data[unit_id];
 202         unsigned int tmo;
 203 
 204         HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
 205         msleep(10);
 206         HACREG(HACCR) = CR_ST | CR_B9;
 207         for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
 208                 udelay(1);
 209 
 210         if (!tmo)
 211                 printk(KERN_INFO "hac: reset: AC97 link down!\n");
 212         /* settings this bit lets us have a conversation with codec */
 213         HACREG(HACACR) |= ACR_TX12ATOM;
 214 }
 215 
 216 static void hac_ac97_coldrst(struct snd_ac97 *ac97)
 217 {
 218         int unit_id = 0 /* ac97->private_data */;
 219         struct hac_priv *hac;
 220         hac = &hac_cpu_data[unit_id];
 221 
 222         HACREG(HACCR) = 0;
 223         HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
 224         msleep(10);
 225         hac_ac97_warmrst(ac97);
 226 }
 227 
 228 static struct snd_ac97_bus_ops hac_ac97_ops = {
 229         .read   = hac_ac97_read,
 230         .write  = hac_ac97_write,
 231         .reset  = hac_ac97_coldrst,
 232         .warm_reset = hac_ac97_warmrst,
 233 };
 234 
 235 static int hac_hw_params(struct snd_pcm_substream *substream,
 236                          struct snd_pcm_hw_params *params,
 237                          struct snd_soc_dai *dai)
 238 {
 239         struct hac_priv *hac = &hac_cpu_data[dai->id];
 240         int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
 241 
 242         switch (params->msbits) {
 243         case 16:
 244                 HACREG(HACACR) |= d ?  ACR_DMARX16 :  ACR_DMATX16;
 245                 HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
 246                 break;
 247         case 20:
 248                 HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
 249                 HACREG(HACACR) |= d ?  ACR_DMARX20 :  ACR_DMATX20;
 250                 break;
 251         default:
 252                 pr_debug("hac: invalid depth %d bit\n", params->msbits);
 253                 return -EINVAL;
 254                 break;
 255         }
 256 
 257         return 0;
 258 }
 259 
 260 #define AC97_RATES      \
 261         SNDRV_PCM_RATE_8000_192000
 262 
 263 #define AC97_FMTS       \
 264         SNDRV_PCM_FMTBIT_S16_LE
 265 
 266 static const struct snd_soc_dai_ops hac_dai_ops = {
 267         .hw_params      = hac_hw_params,
 268 };
 269 
 270 static struct snd_soc_dai_driver sh4_hac_dai[] = {
 271 {
 272         .name                   = "hac-dai.0",
 273         .bus_control            = true,
 274         .playback = {
 275                 .rates          = AC97_RATES,
 276                 .formats        = AC97_FMTS,
 277                 .channels_min   = 2,
 278                 .channels_max   = 2,
 279         },
 280         .capture = {
 281                 .rates          = AC97_RATES,
 282                 .formats        = AC97_FMTS,
 283                 .channels_min   = 2,
 284                 .channels_max   = 2,
 285         },
 286         .ops = &hac_dai_ops,
 287 },
 288 #ifdef CONFIG_CPU_SUBTYPE_SH7760
 289 {
 290         .name                   = "hac-dai.1",
 291         .id                     = 1,
 292         .playback = {
 293                 .rates          = AC97_RATES,
 294                 .formats        = AC97_FMTS,
 295                 .channels_min   = 2,
 296                 .channels_max   = 2,
 297         },
 298         .capture = {
 299                 .rates          = AC97_RATES,
 300                 .formats        = AC97_FMTS,
 301                 .channels_min   = 2,
 302                 .channels_max   = 2,
 303         },
 304         .ops = &hac_dai_ops,
 305 
 306 },
 307 #endif
 308 };
 309 
 310 static const struct snd_soc_component_driver sh4_hac_component = {
 311         .name           = "sh4-hac",
 312 };
 313 
 314 static int hac_soc_platform_probe(struct platform_device *pdev)
 315 {
 316         int ret;
 317 
 318         ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
 319         if (ret != 0)
 320                 return ret;
 321 
 322         return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component,
 323                                           sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
 324 }
 325 
 326 static int hac_soc_platform_remove(struct platform_device *pdev)
 327 {
 328         snd_soc_set_ac97_ops(NULL);
 329         return 0;
 330 }
 331 
 332 static struct platform_driver hac_pcm_driver = {
 333         .driver = {
 334                         .name = "hac-pcm-audio",
 335         },
 336 
 337         .probe = hac_soc_platform_probe,
 338         .remove = hac_soc_platform_remove,
 339 };
 340 
 341 module_platform_driver(hac_pcm_driver);
 342 
 343 MODULE_LICENSE("GPL v2");
 344 MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
 345 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");

/* [<][>][^][v][top][bottom][index][help] */