hac.c (8056B)
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 75struct 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 */ 99static 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 135static 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 162static 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 190static 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 198static 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 216static 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 228static 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 235static 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 266static const struct snd_soc_dai_ops hac_dai_ops = { 267 .hw_params = hac_hw_params, 268}; 269 270static struct snd_soc_dai_driver sh4_hac_dai[] = { 271{ 272 .name = "hac-dai.0", 273 .playback = { 274 .rates = AC97_RATES, 275 .formats = AC97_FMTS, 276 .channels_min = 2, 277 .channels_max = 2, 278 }, 279 .capture = { 280 .rates = AC97_RATES, 281 .formats = AC97_FMTS, 282 .channels_min = 2, 283 .channels_max = 2, 284 }, 285 .ops = &hac_dai_ops, 286}, 287#ifdef CONFIG_CPU_SUBTYPE_SH7760 288{ 289 .name = "hac-dai.1", 290 .id = 1, 291 .playback = { 292 .rates = AC97_RATES, 293 .formats = AC97_FMTS, 294 .channels_min = 2, 295 .channels_max = 2, 296 }, 297 .capture = { 298 .rates = AC97_RATES, 299 .formats = AC97_FMTS, 300 .channels_min = 2, 301 .channels_max = 2, 302 }, 303 .ops = &hac_dai_ops, 304 305}, 306#endif 307}; 308 309static const struct snd_soc_component_driver sh4_hac_component = { 310 .name = "sh4-hac", 311}; 312 313static int hac_soc_platform_probe(struct platform_device *pdev) 314{ 315 int ret; 316 317 ret = snd_soc_set_ac97_ops(&hac_ac97_ops); 318 if (ret != 0) 319 return ret; 320 321 return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component, 322 sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); 323} 324 325static int hac_soc_platform_remove(struct platform_device *pdev) 326{ 327 snd_soc_set_ac97_ops(NULL); 328 return 0; 329} 330 331static struct platform_driver hac_pcm_driver = { 332 .driver = { 333 .name = "hac-pcm-audio", 334 }, 335 336 .probe = hac_soc_platform_probe, 337 .remove = hac_soc_platform_remove, 338}; 339 340module_platform_driver(hac_pcm_driver); 341 342MODULE_LICENSE("GPL v2"); 343MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver"); 344MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");