11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29dcaa7b2SRafael Ignacio Zurita /*
39dcaa7b2SRafael Ignacio Zurita * sh_dac_audio.c - SuperH DAC audio driver for ALSA
49dcaa7b2SRafael Ignacio Zurita *
59dcaa7b2SRafael Ignacio Zurita * Copyright (c) 2009 by Rafael Ignacio Zurita <rizurita@yahoo.com>
69dcaa7b2SRafael Ignacio Zurita *
79dcaa7b2SRafael Ignacio Zurita * Based on sh_dac_audio.c (Copyright (C) 2004, 2005 by Andriy Skulysh)
89dcaa7b2SRafael Ignacio Zurita */
99dcaa7b2SRafael Ignacio Zurita
109dcaa7b2SRafael Ignacio Zurita #include <linux/hrtimer.h>
119dcaa7b2SRafael Ignacio Zurita #include <linux/interrupt.h>
129dcaa7b2SRafael Ignacio Zurita #include <linux/io.h>
139dcaa7b2SRafael Ignacio Zurita #include <linux/platform_device.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
15da155d5bSPaul Gortmaker #include <linux/module.h>
169dcaa7b2SRafael Ignacio Zurita #include <sound/core.h>
179dcaa7b2SRafael Ignacio Zurita #include <sound/initval.h>
189dcaa7b2SRafael Ignacio Zurita #include <sound/pcm.h>
199dcaa7b2SRafael Ignacio Zurita #include <sound/sh_dac_audio.h>
209dcaa7b2SRafael Ignacio Zurita #include <asm/clock.h>
219dcaa7b2SRafael Ignacio Zurita #include <asm/hd64461.h>
229dcaa7b2SRafael Ignacio Zurita #include <mach/hp6xx.h>
239dcaa7b2SRafael Ignacio Zurita #include <cpu/dac.h>
249dcaa7b2SRafael Ignacio Zurita
259dcaa7b2SRafael Ignacio Zurita MODULE_AUTHOR("Rafael Ignacio Zurita <rizurita@yahoo.com>");
269dcaa7b2SRafael Ignacio Zurita MODULE_DESCRIPTION("SuperH DAC audio driver");
279dcaa7b2SRafael Ignacio Zurita MODULE_LICENSE("GPL");
289dcaa7b2SRafael Ignacio Zurita
299dcaa7b2SRafael Ignacio Zurita /* Module Parameters */
309dcaa7b2SRafael Ignacio Zurita static int index = SNDRV_DEFAULT_IDX1;
319dcaa7b2SRafael Ignacio Zurita static char *id = SNDRV_DEFAULT_STR1;
329dcaa7b2SRafael Ignacio Zurita module_param(index, int, 0444);
339dcaa7b2SRafael Ignacio Zurita MODULE_PARM_DESC(index, "Index value for SuperH DAC audio.");
349dcaa7b2SRafael Ignacio Zurita module_param(id, charp, 0444);
359dcaa7b2SRafael Ignacio Zurita MODULE_PARM_DESC(id, "ID string for SuperH DAC audio.");
369dcaa7b2SRafael Ignacio Zurita
379dcaa7b2SRafael Ignacio Zurita /* main struct */
389dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac {
399dcaa7b2SRafael Ignacio Zurita struct snd_card *card;
409dcaa7b2SRafael Ignacio Zurita struct snd_pcm_substream *substream;
419dcaa7b2SRafael Ignacio Zurita struct hrtimer hrtimer;
429dcaa7b2SRafael Ignacio Zurita ktime_t wakeups_per_second;
439dcaa7b2SRafael Ignacio Zurita
449dcaa7b2SRafael Ignacio Zurita int rate;
459dcaa7b2SRafael Ignacio Zurita int empty;
469dcaa7b2SRafael Ignacio Zurita char *data_buffer, *buffer_begin, *buffer_end;
479dcaa7b2SRafael Ignacio Zurita int processed; /* bytes proccesed, to compare with period_size */
489dcaa7b2SRafael Ignacio Zurita int buffer_size;
499dcaa7b2SRafael Ignacio Zurita struct dac_audio_pdata *pdata;
509dcaa7b2SRafael Ignacio Zurita };
519dcaa7b2SRafael Ignacio Zurita
529dcaa7b2SRafael Ignacio Zurita
dac_audio_start_timer(struct snd_sh_dac * chip)539dcaa7b2SRafael Ignacio Zurita static void dac_audio_start_timer(struct snd_sh_dac *chip)
549dcaa7b2SRafael Ignacio Zurita {
559dcaa7b2SRafael Ignacio Zurita hrtimer_start(&chip->hrtimer, chip->wakeups_per_second,
569dcaa7b2SRafael Ignacio Zurita HRTIMER_MODE_REL);
579dcaa7b2SRafael Ignacio Zurita }
589dcaa7b2SRafael Ignacio Zurita
dac_audio_stop_timer(struct snd_sh_dac * chip)599dcaa7b2SRafael Ignacio Zurita static void dac_audio_stop_timer(struct snd_sh_dac *chip)
609dcaa7b2SRafael Ignacio Zurita {
619dcaa7b2SRafael Ignacio Zurita hrtimer_cancel(&chip->hrtimer);
629dcaa7b2SRafael Ignacio Zurita }
639dcaa7b2SRafael Ignacio Zurita
dac_audio_reset(struct snd_sh_dac * chip)649dcaa7b2SRafael Ignacio Zurita static void dac_audio_reset(struct snd_sh_dac *chip)
659dcaa7b2SRafael Ignacio Zurita {
669dcaa7b2SRafael Ignacio Zurita dac_audio_stop_timer(chip);
679dcaa7b2SRafael Ignacio Zurita chip->buffer_begin = chip->buffer_end = chip->data_buffer;
689dcaa7b2SRafael Ignacio Zurita chip->processed = 0;
699dcaa7b2SRafael Ignacio Zurita chip->empty = 1;
709dcaa7b2SRafael Ignacio Zurita }
719dcaa7b2SRafael Ignacio Zurita
dac_audio_set_rate(struct snd_sh_dac * chip)729dcaa7b2SRafael Ignacio Zurita static void dac_audio_set_rate(struct snd_sh_dac *chip)
739dcaa7b2SRafael Ignacio Zurita {
748b0e1953SThomas Gleixner chip->wakeups_per_second = 1000000000 / chip->rate;
759dcaa7b2SRafael Ignacio Zurita }
769dcaa7b2SRafael Ignacio Zurita
779dcaa7b2SRafael Ignacio Zurita
789dcaa7b2SRafael Ignacio Zurita /* PCM INTERFACE */
799dcaa7b2SRafael Ignacio Zurita
80cd196fe2SBhumika Goyal static const struct snd_pcm_hardware snd_sh_dac_pcm_hw = {
819dcaa7b2SRafael Ignacio Zurita .info = (SNDRV_PCM_INFO_MMAP |
829dcaa7b2SRafael Ignacio Zurita SNDRV_PCM_INFO_MMAP_VALID |
839dcaa7b2SRafael Ignacio Zurita SNDRV_PCM_INFO_INTERLEAVED |
849dcaa7b2SRafael Ignacio Zurita SNDRV_PCM_INFO_HALF_DUPLEX),
859dcaa7b2SRafael Ignacio Zurita .formats = SNDRV_PCM_FMTBIT_U8,
869dcaa7b2SRafael Ignacio Zurita .rates = SNDRV_PCM_RATE_8000,
879dcaa7b2SRafael Ignacio Zurita .rate_min = 8000,
889dcaa7b2SRafael Ignacio Zurita .rate_max = 8000,
899dcaa7b2SRafael Ignacio Zurita .channels_min = 1,
909dcaa7b2SRafael Ignacio Zurita .channels_max = 1,
919dcaa7b2SRafael Ignacio Zurita .buffer_bytes_max = (48*1024),
929dcaa7b2SRafael Ignacio Zurita .period_bytes_min = 1,
939dcaa7b2SRafael Ignacio Zurita .period_bytes_max = (48*1024),
949dcaa7b2SRafael Ignacio Zurita .periods_min = 1,
959dcaa7b2SRafael Ignacio Zurita .periods_max = 1024,
969dcaa7b2SRafael Ignacio Zurita };
979dcaa7b2SRafael Ignacio Zurita
snd_sh_dac_pcm_open(struct snd_pcm_substream * substream)989dcaa7b2SRafael Ignacio Zurita static int snd_sh_dac_pcm_open(struct snd_pcm_substream *substream)
999dcaa7b2SRafael Ignacio Zurita {
1009dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1019dcaa7b2SRafael Ignacio Zurita struct snd_pcm_runtime *runtime = substream->runtime;
1029dcaa7b2SRafael Ignacio Zurita
1039dcaa7b2SRafael Ignacio Zurita runtime->hw = snd_sh_dac_pcm_hw;
1049dcaa7b2SRafael Ignacio Zurita
1059dcaa7b2SRafael Ignacio Zurita chip->substream = substream;
1069dcaa7b2SRafael Ignacio Zurita chip->buffer_begin = chip->buffer_end = chip->data_buffer;
1079dcaa7b2SRafael Ignacio Zurita chip->processed = 0;
1089dcaa7b2SRafael Ignacio Zurita chip->empty = 1;
1099dcaa7b2SRafael Ignacio Zurita
1109dcaa7b2SRafael Ignacio Zurita chip->pdata->start(chip->pdata);
1119dcaa7b2SRafael Ignacio Zurita
1129dcaa7b2SRafael Ignacio Zurita return 0;
1139dcaa7b2SRafael Ignacio Zurita }
1149dcaa7b2SRafael Ignacio Zurita
snd_sh_dac_pcm_close(struct snd_pcm_substream * substream)1159dcaa7b2SRafael Ignacio Zurita static int snd_sh_dac_pcm_close(struct snd_pcm_substream *substream)
1169dcaa7b2SRafael Ignacio Zurita {
1179dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1189dcaa7b2SRafael Ignacio Zurita
1199dcaa7b2SRafael Ignacio Zurita chip->substream = NULL;
1209dcaa7b2SRafael Ignacio Zurita
1219dcaa7b2SRafael Ignacio Zurita dac_audio_stop_timer(chip);
1229dcaa7b2SRafael Ignacio Zurita chip->pdata->stop(chip->pdata);
1239dcaa7b2SRafael Ignacio Zurita
1249dcaa7b2SRafael Ignacio Zurita return 0;
1259dcaa7b2SRafael Ignacio Zurita }
1269dcaa7b2SRafael Ignacio Zurita
snd_sh_dac_pcm_prepare(struct snd_pcm_substream * substream)1279dcaa7b2SRafael Ignacio Zurita static int snd_sh_dac_pcm_prepare(struct snd_pcm_substream *substream)
1289dcaa7b2SRafael Ignacio Zurita {
1299dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1309dcaa7b2SRafael Ignacio Zurita struct snd_pcm_runtime *runtime = chip->substream->runtime;
1319dcaa7b2SRafael Ignacio Zurita
1329dcaa7b2SRafael Ignacio Zurita chip->buffer_size = runtime->buffer_size;
1339dcaa7b2SRafael Ignacio Zurita memset(chip->data_buffer, 0, chip->pdata->buffer_size);
1349dcaa7b2SRafael Ignacio Zurita
1359dcaa7b2SRafael Ignacio Zurita return 0;
1369dcaa7b2SRafael Ignacio Zurita }
1379dcaa7b2SRafael Ignacio Zurita
snd_sh_dac_pcm_trigger(struct snd_pcm_substream * substream,int cmd)1389dcaa7b2SRafael Ignacio Zurita static int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1399dcaa7b2SRafael Ignacio Zurita {
1409dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1419dcaa7b2SRafael Ignacio Zurita
1429dcaa7b2SRafael Ignacio Zurita switch (cmd) {
1439dcaa7b2SRafael Ignacio Zurita case SNDRV_PCM_TRIGGER_START:
1449dcaa7b2SRafael Ignacio Zurita dac_audio_start_timer(chip);
1459dcaa7b2SRafael Ignacio Zurita break;
1469dcaa7b2SRafael Ignacio Zurita case SNDRV_PCM_TRIGGER_STOP:
1479dcaa7b2SRafael Ignacio Zurita chip->buffer_begin = chip->buffer_end = chip->data_buffer;
1489dcaa7b2SRafael Ignacio Zurita chip->processed = 0;
1499dcaa7b2SRafael Ignacio Zurita chip->empty = 1;
1509dcaa7b2SRafael Ignacio Zurita dac_audio_stop_timer(chip);
1519dcaa7b2SRafael Ignacio Zurita break;
1529dcaa7b2SRafael Ignacio Zurita default:
1539dcaa7b2SRafael Ignacio Zurita return -EINVAL;
1549dcaa7b2SRafael Ignacio Zurita }
1559dcaa7b2SRafael Ignacio Zurita
1569dcaa7b2SRafael Ignacio Zurita return 0;
1579dcaa7b2SRafael Ignacio Zurita }
1589dcaa7b2SRafael Ignacio Zurita
snd_sh_dac_pcm_copy(struct snd_pcm_substream * substream,int channel,unsigned long pos,struct iov_iter * src,unsigned long count)1591cc2f8baSTakashi Iwai static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream,
1601cc2f8baSTakashi Iwai int channel, unsigned long pos,
1612f432f47STakashi Iwai struct iov_iter *src, unsigned long count)
1629dcaa7b2SRafael Ignacio Zurita {
1639dcaa7b2SRafael Ignacio Zurita /* channel is not used (interleaved data) */
1649dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1659dcaa7b2SRafael Ignacio Zurita
166*0098f6a6STakashi Iwai if (copy_from_iter(chip->data_buffer + pos, count, src) != count)
1671cc2f8baSTakashi Iwai return -EFAULT;
1681cc2f8baSTakashi Iwai chip->buffer_end = chip->data_buffer + pos + count;
1699dcaa7b2SRafael Ignacio Zurita
1701cc2f8baSTakashi Iwai if (chip->empty) {
1711cc2f8baSTakashi Iwai chip->empty = 0;
1721cc2f8baSTakashi Iwai dac_audio_start_timer(chip);
1731cc2f8baSTakashi Iwai }
1741cc2f8baSTakashi Iwai
1759dcaa7b2SRafael Ignacio Zurita return 0;
1761cc2f8baSTakashi Iwai }
1779dcaa7b2SRafael Ignacio Zurita
snd_sh_dac_pcm_silence(struct snd_pcm_substream * substream,int channel,unsigned long pos,unsigned long count)1789dcaa7b2SRafael Ignacio Zurita static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream,
1791cc2f8baSTakashi Iwai int channel, unsigned long pos,
1801cc2f8baSTakashi Iwai unsigned long count)
1819dcaa7b2SRafael Ignacio Zurita {
1829dcaa7b2SRafael Ignacio Zurita /* channel is not used (interleaved data) */
1839dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1849dcaa7b2SRafael Ignacio Zurita
1857dbf2af8STakashi Iwai memset(chip->data_buffer + pos, 0, count);
1861cc2f8baSTakashi Iwai chip->buffer_end = chip->data_buffer + pos + count;
1879dcaa7b2SRafael Ignacio Zurita
1889dcaa7b2SRafael Ignacio Zurita if (chip->empty) {
1899dcaa7b2SRafael Ignacio Zurita chip->empty = 0;
1909dcaa7b2SRafael Ignacio Zurita dac_audio_start_timer(chip);
1919dcaa7b2SRafael Ignacio Zurita }
1929dcaa7b2SRafael Ignacio Zurita
1939dcaa7b2SRafael Ignacio Zurita return 0;
1949dcaa7b2SRafael Ignacio Zurita }
1959dcaa7b2SRafael Ignacio Zurita
1969dcaa7b2SRafael Ignacio Zurita static
snd_sh_dac_pcm_pointer(struct snd_pcm_substream * substream)1979dcaa7b2SRafael Ignacio Zurita snd_pcm_uframes_t snd_sh_dac_pcm_pointer(struct snd_pcm_substream *substream)
1989dcaa7b2SRafael Ignacio Zurita {
1999dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
2009dcaa7b2SRafael Ignacio Zurita int pointer = chip->buffer_begin - chip->data_buffer;
2019dcaa7b2SRafael Ignacio Zurita
2029dcaa7b2SRafael Ignacio Zurita return pointer;
2039dcaa7b2SRafael Ignacio Zurita }
2049dcaa7b2SRafael Ignacio Zurita
2059dcaa7b2SRafael Ignacio Zurita /* pcm ops */
20646a085a3SArvind Yadav static const struct snd_pcm_ops snd_sh_dac_pcm_ops = {
2079dcaa7b2SRafael Ignacio Zurita .open = snd_sh_dac_pcm_open,
2089dcaa7b2SRafael Ignacio Zurita .close = snd_sh_dac_pcm_close,
2099dcaa7b2SRafael Ignacio Zurita .prepare = snd_sh_dac_pcm_prepare,
2109dcaa7b2SRafael Ignacio Zurita .trigger = snd_sh_dac_pcm_trigger,
2119dcaa7b2SRafael Ignacio Zurita .pointer = snd_sh_dac_pcm_pointer,
2122f432f47STakashi Iwai .copy = snd_sh_dac_pcm_copy,
2131cc2f8baSTakashi Iwai .fill_silence = snd_sh_dac_pcm_silence,
2149dcaa7b2SRafael Ignacio Zurita };
2159dcaa7b2SRafael Ignacio Zurita
snd_sh_dac_pcm(struct snd_sh_dac * chip,int device)216e74033a8SBill Pemberton static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device)
2179dcaa7b2SRafael Ignacio Zurita {
2189dcaa7b2SRafael Ignacio Zurita int err;
2199dcaa7b2SRafael Ignacio Zurita struct snd_pcm *pcm;
2209dcaa7b2SRafael Ignacio Zurita
2219dcaa7b2SRafael Ignacio Zurita /* device should be always 0 for us */
2229dcaa7b2SRafael Ignacio Zurita err = snd_pcm_new(chip->card, "SH_DAC PCM", device, 1, 0, &pcm);
2239dcaa7b2SRafael Ignacio Zurita if (err < 0)
2249dcaa7b2SRafael Ignacio Zurita return err;
2259dcaa7b2SRafael Ignacio Zurita
2269dcaa7b2SRafael Ignacio Zurita pcm->private_data = chip;
2279dcaa7b2SRafael Ignacio Zurita strcpy(pcm->name, "SH_DAC PCM");
2289dcaa7b2SRafael Ignacio Zurita snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sh_dac_pcm_ops);
2299dcaa7b2SRafael Ignacio Zurita
2309dcaa7b2SRafael Ignacio Zurita /* buffer size=48K */
23150cdf3a0STakashi Iwai snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
23250cdf3a0STakashi Iwai NULL, 48 * 1024, 48 * 1024);
2339dcaa7b2SRafael Ignacio Zurita
2349dcaa7b2SRafael Ignacio Zurita return 0;
2359dcaa7b2SRafael Ignacio Zurita }
2369dcaa7b2SRafael Ignacio Zurita /* END OF PCM INTERFACE */
2379dcaa7b2SRafael Ignacio Zurita
2389dcaa7b2SRafael Ignacio Zurita
2399dcaa7b2SRafael Ignacio Zurita /* driver .remove -- destructor */
snd_sh_dac_remove(struct platform_device * devptr)240a0f4aa0aSUwe Kleine-König static void snd_sh_dac_remove(struct platform_device *devptr)
2419dcaa7b2SRafael Ignacio Zurita {
2429dcaa7b2SRafael Ignacio Zurita snd_card_free(platform_get_drvdata(devptr));
2439dcaa7b2SRafael Ignacio Zurita }
2449dcaa7b2SRafael Ignacio Zurita
2459dcaa7b2SRafael Ignacio Zurita /* free -- it has been defined by create */
snd_sh_dac_free(struct snd_sh_dac * chip)2469dcaa7b2SRafael Ignacio Zurita static int snd_sh_dac_free(struct snd_sh_dac *chip)
2479dcaa7b2SRafael Ignacio Zurita {
2489dcaa7b2SRafael Ignacio Zurita /* release the data */
2499dcaa7b2SRafael Ignacio Zurita kfree(chip->data_buffer);
2509dcaa7b2SRafael Ignacio Zurita kfree(chip);
2519dcaa7b2SRafael Ignacio Zurita
2529dcaa7b2SRafael Ignacio Zurita return 0;
2539dcaa7b2SRafael Ignacio Zurita }
2549dcaa7b2SRafael Ignacio Zurita
snd_sh_dac_dev_free(struct snd_device * device)2559dcaa7b2SRafael Ignacio Zurita static int snd_sh_dac_dev_free(struct snd_device *device)
2569dcaa7b2SRafael Ignacio Zurita {
2579dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = device->device_data;
2589dcaa7b2SRafael Ignacio Zurita
2599dcaa7b2SRafael Ignacio Zurita return snd_sh_dac_free(chip);
2609dcaa7b2SRafael Ignacio Zurita }
2619dcaa7b2SRafael Ignacio Zurita
sh_dac_audio_timer(struct hrtimer * handle)2629dcaa7b2SRafael Ignacio Zurita static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
2639dcaa7b2SRafael Ignacio Zurita {
2649dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip = container_of(handle, struct snd_sh_dac,
2659dcaa7b2SRafael Ignacio Zurita hrtimer);
2669dcaa7b2SRafael Ignacio Zurita struct snd_pcm_runtime *runtime = chip->substream->runtime;
2679dcaa7b2SRafael Ignacio Zurita ssize_t b_ps = frames_to_bytes(runtime, runtime->period_size);
2689dcaa7b2SRafael Ignacio Zurita
2699dcaa7b2SRafael Ignacio Zurita if (!chip->empty) {
2709dcaa7b2SRafael Ignacio Zurita sh_dac_output(*chip->buffer_begin, chip->pdata->channel);
2719dcaa7b2SRafael Ignacio Zurita chip->buffer_begin++;
2729dcaa7b2SRafael Ignacio Zurita
2739dcaa7b2SRafael Ignacio Zurita chip->processed++;
2749dcaa7b2SRafael Ignacio Zurita if (chip->processed >= b_ps) {
2759dcaa7b2SRafael Ignacio Zurita chip->processed -= b_ps;
2769dcaa7b2SRafael Ignacio Zurita snd_pcm_period_elapsed(chip->substream);
2779dcaa7b2SRafael Ignacio Zurita }
2789dcaa7b2SRafael Ignacio Zurita
2799dcaa7b2SRafael Ignacio Zurita if (chip->buffer_begin == (chip->data_buffer +
2809dcaa7b2SRafael Ignacio Zurita chip->buffer_size - 1))
2819dcaa7b2SRafael Ignacio Zurita chip->buffer_begin = chip->data_buffer;
2829dcaa7b2SRafael Ignacio Zurita
2839dcaa7b2SRafael Ignacio Zurita if (chip->buffer_begin == chip->buffer_end)
2849dcaa7b2SRafael Ignacio Zurita chip->empty = 1;
2859dcaa7b2SRafael Ignacio Zurita
2869dcaa7b2SRafael Ignacio Zurita }
2879dcaa7b2SRafael Ignacio Zurita
2889dcaa7b2SRafael Ignacio Zurita if (!chip->empty)
2899dcaa7b2SRafael Ignacio Zurita hrtimer_start(&chip->hrtimer, chip->wakeups_per_second,
2909dcaa7b2SRafael Ignacio Zurita HRTIMER_MODE_REL);
2919dcaa7b2SRafael Ignacio Zurita
2929dcaa7b2SRafael Ignacio Zurita return HRTIMER_NORESTART;
2939dcaa7b2SRafael Ignacio Zurita }
2949dcaa7b2SRafael Ignacio Zurita
2959dcaa7b2SRafael Ignacio Zurita /* create -- chip-specific constructor for the cards components */
snd_sh_dac_create(struct snd_card * card,struct platform_device * devptr,struct snd_sh_dac ** rchip)296e74033a8SBill Pemberton static int snd_sh_dac_create(struct snd_card *card,
2979dcaa7b2SRafael Ignacio Zurita struct platform_device *devptr,
2989dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac **rchip)
2999dcaa7b2SRafael Ignacio Zurita {
3009dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip;
3019dcaa7b2SRafael Ignacio Zurita int err;
3029dcaa7b2SRafael Ignacio Zurita
30352b136d2STakashi Iwai static const struct snd_device_ops ops = {
3049dcaa7b2SRafael Ignacio Zurita .dev_free = snd_sh_dac_dev_free,
3059dcaa7b2SRafael Ignacio Zurita };
3069dcaa7b2SRafael Ignacio Zurita
3079dcaa7b2SRafael Ignacio Zurita *rchip = NULL;
3089dcaa7b2SRafael Ignacio Zurita
3099dcaa7b2SRafael Ignacio Zurita chip = kzalloc(sizeof(*chip), GFP_KERNEL);
3109dcaa7b2SRafael Ignacio Zurita if (chip == NULL)
3119dcaa7b2SRafael Ignacio Zurita return -ENOMEM;
3129dcaa7b2SRafael Ignacio Zurita
3139dcaa7b2SRafael Ignacio Zurita chip->card = card;
3149dcaa7b2SRafael Ignacio Zurita
3159dcaa7b2SRafael Ignacio Zurita hrtimer_init(&chip->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
3169dcaa7b2SRafael Ignacio Zurita chip->hrtimer.function = sh_dac_audio_timer;
3179dcaa7b2SRafael Ignacio Zurita
3189dcaa7b2SRafael Ignacio Zurita dac_audio_reset(chip);
3199dcaa7b2SRafael Ignacio Zurita chip->rate = 8000;
3209dcaa7b2SRafael Ignacio Zurita dac_audio_set_rate(chip);
3219dcaa7b2SRafael Ignacio Zurita
3229dcaa7b2SRafael Ignacio Zurita chip->pdata = devptr->dev.platform_data;
3239dcaa7b2SRafael Ignacio Zurita
3249dcaa7b2SRafael Ignacio Zurita chip->data_buffer = kmalloc(chip->pdata->buffer_size, GFP_KERNEL);
3259dcaa7b2SRafael Ignacio Zurita if (chip->data_buffer == NULL) {
3269dcaa7b2SRafael Ignacio Zurita kfree(chip);
3279dcaa7b2SRafael Ignacio Zurita return -ENOMEM;
3289dcaa7b2SRafael Ignacio Zurita }
3299dcaa7b2SRafael Ignacio Zurita
3309dcaa7b2SRafael Ignacio Zurita err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
3319dcaa7b2SRafael Ignacio Zurita if (err < 0) {
3329dcaa7b2SRafael Ignacio Zurita snd_sh_dac_free(chip);
3339dcaa7b2SRafael Ignacio Zurita return err;
3349dcaa7b2SRafael Ignacio Zurita }
3359dcaa7b2SRafael Ignacio Zurita
3369dcaa7b2SRafael Ignacio Zurita *rchip = chip;
3379dcaa7b2SRafael Ignacio Zurita
3389dcaa7b2SRafael Ignacio Zurita return 0;
3399dcaa7b2SRafael Ignacio Zurita }
3409dcaa7b2SRafael Ignacio Zurita
3419dcaa7b2SRafael Ignacio Zurita /* driver .probe -- constructor */
snd_sh_dac_probe(struct platform_device * devptr)342e74033a8SBill Pemberton static int snd_sh_dac_probe(struct platform_device *devptr)
3439dcaa7b2SRafael Ignacio Zurita {
3449dcaa7b2SRafael Ignacio Zurita struct snd_sh_dac *chip;
3459dcaa7b2SRafael Ignacio Zurita struct snd_card *card;
3469dcaa7b2SRafael Ignacio Zurita int err;
3479dcaa7b2SRafael Ignacio Zurita
348e7182ac5STakashi Iwai err = snd_card_new(&devptr->dev, index, id, THIS_MODULE, 0, &card);
3499dcaa7b2SRafael Ignacio Zurita if (err < 0) {
3509dcaa7b2SRafael Ignacio Zurita snd_printk(KERN_ERR "cannot allocate the card\n");
3519dcaa7b2SRafael Ignacio Zurita return err;
3529dcaa7b2SRafael Ignacio Zurita }
3539dcaa7b2SRafael Ignacio Zurita
3549dcaa7b2SRafael Ignacio Zurita err = snd_sh_dac_create(card, devptr, &chip);
3559dcaa7b2SRafael Ignacio Zurita if (err < 0)
3569dcaa7b2SRafael Ignacio Zurita goto probe_error;
3579dcaa7b2SRafael Ignacio Zurita
3589dcaa7b2SRafael Ignacio Zurita err = snd_sh_dac_pcm(chip, 0);
3599dcaa7b2SRafael Ignacio Zurita if (err < 0)
3609dcaa7b2SRafael Ignacio Zurita goto probe_error;
3619dcaa7b2SRafael Ignacio Zurita
3629dcaa7b2SRafael Ignacio Zurita strcpy(card->driver, "snd_sh_dac");
3639dcaa7b2SRafael Ignacio Zurita strcpy(card->shortname, "SuperH DAC audio driver");
3649dcaa7b2SRafael Ignacio Zurita printk(KERN_INFO "%s %s", card->longname, card->shortname);
3659dcaa7b2SRafael Ignacio Zurita
3669dcaa7b2SRafael Ignacio Zurita err = snd_card_register(card);
3679dcaa7b2SRafael Ignacio Zurita if (err < 0)
3689dcaa7b2SRafael Ignacio Zurita goto probe_error;
3699dcaa7b2SRafael Ignacio Zurita
370c054c8a0STakashi Iwai snd_printk(KERN_INFO "ALSA driver for SuperH DAC audio");
3719dcaa7b2SRafael Ignacio Zurita
3729dcaa7b2SRafael Ignacio Zurita platform_set_drvdata(devptr, card);
3739dcaa7b2SRafael Ignacio Zurita return 0;
3749dcaa7b2SRafael Ignacio Zurita
3759dcaa7b2SRafael Ignacio Zurita probe_error:
3769dcaa7b2SRafael Ignacio Zurita snd_card_free(card);
3779dcaa7b2SRafael Ignacio Zurita return err;
3789dcaa7b2SRafael Ignacio Zurita }
3799dcaa7b2SRafael Ignacio Zurita
3809dcaa7b2SRafael Ignacio Zurita /*
3819dcaa7b2SRafael Ignacio Zurita * "driver" definition
3829dcaa7b2SRafael Ignacio Zurita */
383d4c69838SPaul Mundt static struct platform_driver sh_dac_driver = {
3849dcaa7b2SRafael Ignacio Zurita .probe = snd_sh_dac_probe,
385a0f4aa0aSUwe Kleine-König .remove_new = snd_sh_dac_remove,
3869dcaa7b2SRafael Ignacio Zurita .driver = {
3879dcaa7b2SRafael Ignacio Zurita .name = "dac_audio",
3889dcaa7b2SRafael Ignacio Zurita },
3899dcaa7b2SRafael Ignacio Zurita };
3909dcaa7b2SRafael Ignacio Zurita
391d4c69838SPaul Mundt module_platform_driver(sh_dac_driver);
392