0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/dma-mapping.h>
0009 #include <linux/init.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/io.h>
0012 #include <linux/log2.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/spinlock.h>
0016
0017 #include <sound/control.h>
0018 #include <sound/core.h>
0019 #include <sound/initval.h>
0020 #include <sound/pcm.h>
0021 #include <sound/pcm_params.h>
0022
0023 MODULE_AUTHOR("Lauri Kasanen <cand@gmx.com>");
0024 MODULE_DESCRIPTION("N64 Audio");
0025 MODULE_LICENSE("GPL");
0026
0027 #define AI_NTSC_DACRATE 48681812
0028 #define AI_STATUS_BUSY (1 << 30)
0029 #define AI_STATUS_FULL (1 << 31)
0030
0031 #define AI_ADDR_REG 0
0032 #define AI_LEN_REG 1
0033 #define AI_CONTROL_REG 2
0034 #define AI_STATUS_REG 3
0035 #define AI_RATE_REG 4
0036 #define AI_BITCLOCK_REG 5
0037
0038 #define MI_INTR_REG 2
0039 #define MI_MASK_REG 3
0040
0041 #define MI_INTR_AI 0x04
0042
0043 #define MI_MASK_CLR_AI 0x0010
0044 #define MI_MASK_SET_AI 0x0020
0045
0046
0047 struct n64audio {
0048 u32 __iomem *ai_reg_base;
0049 u32 __iomem *mi_reg_base;
0050
0051 void *ring_base;
0052 dma_addr_t ring_base_dma;
0053
0054 struct snd_card *card;
0055
0056 struct {
0057 struct snd_pcm_substream *substream;
0058 int pos, nextpos;
0059 u32 writesize;
0060 u32 bufsize;
0061 spinlock_t lock;
0062 } chan;
0063 };
0064
0065 static void n64audio_write_reg(struct n64audio *priv, const u8 reg, const u32 value)
0066 {
0067 writel(value, priv->ai_reg_base + reg);
0068 }
0069
0070 static void n64mi_write_reg(struct n64audio *priv, const u8 reg, const u32 value)
0071 {
0072 writel(value, priv->mi_reg_base + reg);
0073 }
0074
0075 static u32 n64mi_read_reg(struct n64audio *priv, const u8 reg)
0076 {
0077 return readl(priv->mi_reg_base + reg);
0078 }
0079
0080 static void n64audio_push(struct n64audio *priv)
0081 {
0082 struct snd_pcm_runtime *runtime = priv->chan.substream->runtime;
0083 unsigned long flags;
0084 u32 count;
0085
0086 spin_lock_irqsave(&priv->chan.lock, flags);
0087
0088 count = priv->chan.writesize;
0089
0090 memcpy(priv->ring_base + priv->chan.nextpos,
0091 runtime->dma_area + priv->chan.nextpos, count);
0092
0093
0094
0095
0096
0097
0098 n64audio_write_reg(priv, AI_ADDR_REG, priv->ring_base_dma + priv->chan.nextpos);
0099 barrier();
0100 n64audio_write_reg(priv, AI_LEN_REG, count);
0101
0102 priv->chan.nextpos += count;
0103 priv->chan.nextpos %= priv->chan.bufsize;
0104
0105 runtime->delay = runtime->period_size;
0106
0107 spin_unlock_irqrestore(&priv->chan.lock, flags);
0108 }
0109
0110 static irqreturn_t n64audio_isr(int irq, void *dev_id)
0111 {
0112 struct n64audio *priv = dev_id;
0113 const u32 intrs = n64mi_read_reg(priv, MI_INTR_REG);
0114 unsigned long flags;
0115
0116
0117 if (!(intrs & MI_INTR_AI))
0118 return IRQ_NONE;
0119
0120 n64audio_write_reg(priv, AI_STATUS_REG, 1);
0121
0122 if (priv->chan.substream && snd_pcm_running(priv->chan.substream)) {
0123 spin_lock_irqsave(&priv->chan.lock, flags);
0124
0125 priv->chan.pos = priv->chan.nextpos;
0126
0127 spin_unlock_irqrestore(&priv->chan.lock, flags);
0128
0129 snd_pcm_period_elapsed(priv->chan.substream);
0130 if (priv->chan.substream && snd_pcm_running(priv->chan.substream))
0131 n64audio_push(priv);
0132 }
0133
0134 return IRQ_HANDLED;
0135 }
0136
0137 static const struct snd_pcm_hardware n64audio_pcm_hw = {
0138 .info = (SNDRV_PCM_INFO_MMAP |
0139 SNDRV_PCM_INFO_MMAP_VALID |
0140 SNDRV_PCM_INFO_INTERLEAVED |
0141 SNDRV_PCM_INFO_BLOCK_TRANSFER),
0142 .formats = SNDRV_PCM_FMTBIT_S16_BE,
0143 .rates = SNDRV_PCM_RATE_8000_48000,
0144 .rate_min = 8000,
0145 .rate_max = 48000,
0146 .channels_min = 2,
0147 .channels_max = 2,
0148 .buffer_bytes_max = 32768,
0149 .period_bytes_min = 1024,
0150 .period_bytes_max = 32768,
0151 .periods_min = 3,
0152
0153 .periods_max = 128,
0154 };
0155
0156 static int hw_rule_period_size(struct snd_pcm_hw_params *params,
0157 struct snd_pcm_hw_rule *rule)
0158 {
0159 struct snd_interval *c = hw_param_interval(params,
0160 SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
0161 int changed = 0;
0162
0163
0164
0165
0166
0167
0168
0169
0170 if (is_power_of_2(c->min)) {
0171 c->min += 2;
0172 changed = 1;
0173 }
0174 if (is_power_of_2(c->max)) {
0175 c->max -= 2;
0176 changed = 1;
0177 }
0178 if (snd_interval_checkempty(c)) {
0179 c->empty = 1;
0180 return -EINVAL;
0181 }
0182
0183 return changed;
0184 }
0185
0186 static int n64audio_pcm_open(struct snd_pcm_substream *substream)
0187 {
0188 struct snd_pcm_runtime *runtime = substream->runtime;
0189 int err;
0190
0191 runtime->hw = n64audio_pcm_hw;
0192 err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
0193 if (err < 0)
0194 return err;
0195
0196 err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
0197 if (err < 0)
0198 return err;
0199
0200 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
0201 hw_rule_period_size, NULL, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
0202 if (err < 0)
0203 return err;
0204
0205 return 0;
0206 }
0207
0208 static int n64audio_pcm_prepare(struct snd_pcm_substream *substream)
0209 {
0210 struct snd_pcm_runtime *runtime = substream->runtime;
0211 struct n64audio *priv = substream->pcm->private_data;
0212 u32 rate;
0213
0214 rate = ((2 * AI_NTSC_DACRATE / runtime->rate) + 1) / 2 - 1;
0215
0216 n64audio_write_reg(priv, AI_RATE_REG, rate);
0217
0218 rate /= 66;
0219 if (rate > 16)
0220 rate = 16;
0221 n64audio_write_reg(priv, AI_BITCLOCK_REG, rate - 1);
0222
0223 spin_lock_irq(&priv->chan.lock);
0224
0225
0226 priv->chan.pos = 0;
0227 priv->chan.nextpos = 0;
0228 priv->chan.substream = substream;
0229 priv->chan.writesize = snd_pcm_lib_period_bytes(substream);
0230 priv->chan.bufsize = snd_pcm_lib_buffer_bytes(substream);
0231
0232 spin_unlock_irq(&priv->chan.lock);
0233 return 0;
0234 }
0235
0236 static int n64audio_pcm_trigger(struct snd_pcm_substream *substream,
0237 int cmd)
0238 {
0239 struct n64audio *priv = substream->pcm->private_data;
0240
0241 switch (cmd) {
0242 case SNDRV_PCM_TRIGGER_START:
0243 n64audio_push(substream->pcm->private_data);
0244 n64audio_write_reg(priv, AI_CONTROL_REG, 1);
0245 n64mi_write_reg(priv, MI_MASK_REG, MI_MASK_SET_AI);
0246 break;
0247 case SNDRV_PCM_TRIGGER_STOP:
0248 n64audio_write_reg(priv, AI_CONTROL_REG, 0);
0249 n64mi_write_reg(priv, MI_MASK_REG, MI_MASK_CLR_AI);
0250 break;
0251 default:
0252 return -EINVAL;
0253 }
0254 return 0;
0255 }
0256
0257 static snd_pcm_uframes_t n64audio_pcm_pointer(struct snd_pcm_substream *substream)
0258 {
0259 struct n64audio *priv = substream->pcm->private_data;
0260
0261 return bytes_to_frames(substream->runtime,
0262 priv->chan.pos);
0263 }
0264
0265 static int n64audio_pcm_close(struct snd_pcm_substream *substream)
0266 {
0267 struct n64audio *priv = substream->pcm->private_data;
0268
0269 priv->chan.substream = NULL;
0270
0271 return 0;
0272 }
0273
0274 static const struct snd_pcm_ops n64audio_pcm_ops = {
0275 .open = n64audio_pcm_open,
0276 .prepare = n64audio_pcm_prepare,
0277 .trigger = n64audio_pcm_trigger,
0278 .pointer = n64audio_pcm_pointer,
0279 .close = n64audio_pcm_close,
0280 };
0281
0282
0283
0284
0285
0286
0287 static int __init n64audio_probe(struct platform_device *pdev)
0288 {
0289 struct snd_card *card;
0290 struct snd_pcm *pcm;
0291 struct n64audio *priv;
0292 int err, irq;
0293
0294 err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
0295 SNDRV_DEFAULT_STR1,
0296 THIS_MODULE, sizeof(*priv), &card);
0297 if (err < 0)
0298 return err;
0299
0300 priv = card->private_data;
0301
0302 spin_lock_init(&priv->chan.lock);
0303
0304 priv->card = card;
0305
0306 priv->ring_base = dma_alloc_coherent(card->dev, 32 * 1024, &priv->ring_base_dma,
0307 GFP_DMA|GFP_KERNEL);
0308 if (!priv->ring_base) {
0309 err = -ENOMEM;
0310 goto fail_card;
0311 }
0312
0313 priv->mi_reg_base = devm_platform_ioremap_resource(pdev, 0);
0314 if (IS_ERR(priv->mi_reg_base)) {
0315 err = PTR_ERR(priv->mi_reg_base);
0316 goto fail_dma_alloc;
0317 }
0318
0319 priv->ai_reg_base = devm_platform_ioremap_resource(pdev, 1);
0320 if (IS_ERR(priv->ai_reg_base)) {
0321 err = PTR_ERR(priv->ai_reg_base);
0322 goto fail_dma_alloc;
0323 }
0324
0325 err = snd_pcm_new(card, "N64 Audio", 0, 1, 0, &pcm);
0326 if (err < 0)
0327 goto fail_dma_alloc;
0328
0329 pcm->private_data = priv;
0330 strcpy(pcm->name, "N64 Audio");
0331
0332 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &n64audio_pcm_ops);
0333 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, card->dev, 0, 0);
0334
0335 strcpy(card->driver, "N64 Audio");
0336 strcpy(card->shortname, "N64 Audio");
0337 strcpy(card->longname, "N64 Audio");
0338
0339 irq = platform_get_irq(pdev, 0);
0340 if (irq < 0) {
0341 err = -EINVAL;
0342 goto fail_dma_alloc;
0343 }
0344 if (devm_request_irq(&pdev->dev, irq, n64audio_isr,
0345 IRQF_SHARED, "N64 Audio", priv)) {
0346 err = -EBUSY;
0347 goto fail_dma_alloc;
0348 }
0349
0350 err = snd_card_register(card);
0351 if (err < 0)
0352 goto fail_dma_alloc;
0353
0354 return 0;
0355
0356 fail_dma_alloc:
0357 dma_free_coherent(card->dev, 32 * 1024, priv->ring_base, priv->ring_base_dma);
0358
0359 fail_card:
0360 snd_card_free(card);
0361 return err;
0362 }
0363
0364 static struct platform_driver n64audio_driver = {
0365 .driver = {
0366 .name = "n64audio",
0367 },
0368 };
0369
0370 static int __init n64audio_init(void)
0371 {
0372 return platform_driver_probe(&n64audio_driver, n64audio_probe);
0373 }
0374
0375 module_init(n64audio_init);