18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * sh_dac_audio.c - SuperH DAC audio driver for ALSA
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2009 by Rafael Ignacio Zurita <rizurita@yahoo.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Based on sh_dac_audio.c (Copyright (C) 2004, 2005 by Andriy Skulysh)
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/io.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <sound/core.h>
178c2ecf20Sopenharmony_ci#include <sound/initval.h>
188c2ecf20Sopenharmony_ci#include <sound/pcm.h>
198c2ecf20Sopenharmony_ci#include <sound/sh_dac_audio.h>
208c2ecf20Sopenharmony_ci#include <asm/clock.h>
218c2ecf20Sopenharmony_ci#include <asm/hd64461.h>
228c2ecf20Sopenharmony_ci#include <mach/hp6xx.h>
238c2ecf20Sopenharmony_ci#include <cpu/dac.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Rafael Ignacio Zurita <rizurita@yahoo.com>");
268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SuperH DAC audio driver");
278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
288c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{SuperH DAC audio support}}");
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* Module Parameters */
318c2ecf20Sopenharmony_cistatic int index = SNDRV_DEFAULT_IDX1;
328c2ecf20Sopenharmony_cistatic char *id = SNDRV_DEFAULT_STR1;
338c2ecf20Sopenharmony_cimodule_param(index, int, 0444);
348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for SuperH DAC audio.");
358c2ecf20Sopenharmony_cimodule_param(id, charp, 0444);
368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for SuperH DAC audio.");
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* main struct */
398c2ecf20Sopenharmony_cistruct snd_sh_dac {
408c2ecf20Sopenharmony_ci	struct snd_card *card;
418c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
428c2ecf20Sopenharmony_ci	struct hrtimer hrtimer;
438c2ecf20Sopenharmony_ci	ktime_t wakeups_per_second;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	int rate;
468c2ecf20Sopenharmony_ci	int empty;
478c2ecf20Sopenharmony_ci	char *data_buffer, *buffer_begin, *buffer_end;
488c2ecf20Sopenharmony_ci	int processed; /* bytes proccesed, to compare with period_size */
498c2ecf20Sopenharmony_ci	int buffer_size;
508c2ecf20Sopenharmony_ci	struct dac_audio_pdata *pdata;
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic void dac_audio_start_timer(struct snd_sh_dac *chip)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	hrtimer_start(&chip->hrtimer, chip->wakeups_per_second,
578c2ecf20Sopenharmony_ci		      HRTIMER_MODE_REL);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic void dac_audio_stop_timer(struct snd_sh_dac *chip)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	hrtimer_cancel(&chip->hrtimer);
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic void dac_audio_reset(struct snd_sh_dac *chip)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	dac_audio_stop_timer(chip);
688c2ecf20Sopenharmony_ci	chip->buffer_begin = chip->buffer_end = chip->data_buffer;
698c2ecf20Sopenharmony_ci	chip->processed = 0;
708c2ecf20Sopenharmony_ci	chip->empty = 1;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void dac_audio_set_rate(struct snd_sh_dac *chip)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	chip->wakeups_per_second = 1000000000 / chip->rate;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/* PCM INTERFACE */
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_sh_dac_pcm_hw = {
828c2ecf20Sopenharmony_ci	.info			= (SNDRV_PCM_INFO_MMAP |
838c2ecf20Sopenharmony_ci					SNDRV_PCM_INFO_MMAP_VALID |
848c2ecf20Sopenharmony_ci					SNDRV_PCM_INFO_INTERLEAVED |
858c2ecf20Sopenharmony_ci					SNDRV_PCM_INFO_HALF_DUPLEX),
868c2ecf20Sopenharmony_ci	.formats		= SNDRV_PCM_FMTBIT_U8,
878c2ecf20Sopenharmony_ci	.rates			= SNDRV_PCM_RATE_8000,
888c2ecf20Sopenharmony_ci	.rate_min		= 8000,
898c2ecf20Sopenharmony_ci	.rate_max		= 8000,
908c2ecf20Sopenharmony_ci	.channels_min		= 1,
918c2ecf20Sopenharmony_ci	.channels_max		= 1,
928c2ecf20Sopenharmony_ci	.buffer_bytes_max	= (48*1024),
938c2ecf20Sopenharmony_ci	.period_bytes_min	= 1,
948c2ecf20Sopenharmony_ci	.period_bytes_max	= (48*1024),
958c2ecf20Sopenharmony_ci	.periods_min		= 1,
968c2ecf20Sopenharmony_ci	.periods_max		= 1024,
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic int snd_sh_dac_pcm_open(struct snd_pcm_substream *substream)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1028c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	runtime->hw = snd_sh_dac_pcm_hw;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	chip->substream = substream;
1078c2ecf20Sopenharmony_ci	chip->buffer_begin = chip->buffer_end = chip->data_buffer;
1088c2ecf20Sopenharmony_ci	chip->processed = 0;
1098c2ecf20Sopenharmony_ci	chip->empty = 1;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	chip->pdata->start(chip->pdata);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return 0;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic int snd_sh_dac_pcm_close(struct snd_pcm_substream *substream)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	chip->substream = NULL;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	dac_audio_stop_timer(chip);
1238c2ecf20Sopenharmony_ci	chip->pdata->stop(chip->pdata);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	return 0;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic int snd_sh_dac_pcm_prepare(struct snd_pcm_substream *substream)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1318c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = chip->substream->runtime;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	chip->buffer_size = runtime->buffer_size;
1348c2ecf20Sopenharmony_ci	memset(chip->data_buffer, 0, chip->pdata->buffer_size);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	switch (cmd) {
1448c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
1458c2ecf20Sopenharmony_ci		dac_audio_start_timer(chip);
1468c2ecf20Sopenharmony_ci		break;
1478c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
1488c2ecf20Sopenharmony_ci		chip->buffer_begin = chip->buffer_end = chip->data_buffer;
1498c2ecf20Sopenharmony_ci		chip->processed = 0;
1508c2ecf20Sopenharmony_ci		chip->empty = 1;
1518c2ecf20Sopenharmony_ci		dac_audio_stop_timer(chip);
1528c2ecf20Sopenharmony_ci		break;
1538c2ecf20Sopenharmony_ci	default:
1548c2ecf20Sopenharmony_ci		 return -EINVAL;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	return 0;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream,
1618c2ecf20Sopenharmony_ci			       int channel, unsigned long pos,
1628c2ecf20Sopenharmony_ci			       void __user *src, unsigned long count)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	/* channel is not used (interleaved data) */
1658c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (copy_from_user_toio(chip->data_buffer + pos, src, count))
1688c2ecf20Sopenharmony_ci		return -EFAULT;
1698c2ecf20Sopenharmony_ci	chip->buffer_end = chip->data_buffer + pos + count;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (chip->empty) {
1728c2ecf20Sopenharmony_ci		chip->empty = 0;
1738c2ecf20Sopenharmony_ci		dac_audio_start_timer(chip);
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	return 0;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int snd_sh_dac_pcm_copy_kernel(struct snd_pcm_substream *substream,
1808c2ecf20Sopenharmony_ci				      int channel, unsigned long pos,
1818c2ecf20Sopenharmony_ci				      void *src, unsigned long count)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	/* channel is not used (interleaved data) */
1848c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	memcpy_toio(chip->data_buffer + pos, src, count);
1878c2ecf20Sopenharmony_ci	chip->buffer_end = chip->data_buffer + pos + count;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (chip->empty) {
1908c2ecf20Sopenharmony_ci		chip->empty = 0;
1918c2ecf20Sopenharmony_ci		dac_audio_start_timer(chip);
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream,
1988c2ecf20Sopenharmony_ci				  int channel, unsigned long pos,
1998c2ecf20Sopenharmony_ci				  unsigned long count)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	/* channel is not used (interleaved data) */
2028c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	memset_io(chip->data_buffer + pos, 0, count);
2058c2ecf20Sopenharmony_ci	chip->buffer_end = chip->data_buffer + pos + count;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (chip->empty) {
2088c2ecf20Sopenharmony_ci		chip->empty = 0;
2098c2ecf20Sopenharmony_ci		dac_audio_start_timer(chip);
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic
2168c2ecf20Sopenharmony_cisnd_pcm_uframes_t snd_sh_dac_pcm_pointer(struct snd_pcm_substream *substream)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = snd_pcm_substream_chip(substream);
2198c2ecf20Sopenharmony_ci	int pointer = chip->buffer_begin - chip->data_buffer;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return pointer;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/* pcm ops */
2258c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_sh_dac_pcm_ops = {
2268c2ecf20Sopenharmony_ci	.open		= snd_sh_dac_pcm_open,
2278c2ecf20Sopenharmony_ci	.close		= snd_sh_dac_pcm_close,
2288c2ecf20Sopenharmony_ci	.prepare	= snd_sh_dac_pcm_prepare,
2298c2ecf20Sopenharmony_ci	.trigger	= snd_sh_dac_pcm_trigger,
2308c2ecf20Sopenharmony_ci	.pointer	= snd_sh_dac_pcm_pointer,
2318c2ecf20Sopenharmony_ci	.copy_user	= snd_sh_dac_pcm_copy,
2328c2ecf20Sopenharmony_ci	.copy_kernel	= snd_sh_dac_pcm_copy_kernel,
2338c2ecf20Sopenharmony_ci	.fill_silence	= snd_sh_dac_pcm_silence,
2348c2ecf20Sopenharmony_ci	.mmap		= snd_pcm_lib_mmap_iomem,
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	int err;
2408c2ecf20Sopenharmony_ci	struct snd_pcm *pcm;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* device should be always 0 for us */
2438c2ecf20Sopenharmony_ci	err = snd_pcm_new(chip->card, "SH_DAC PCM", device, 1, 0, &pcm);
2448c2ecf20Sopenharmony_ci	if (err < 0)
2458c2ecf20Sopenharmony_ci		return err;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	pcm->private_data = chip;
2488c2ecf20Sopenharmony_ci	strcpy(pcm->name, "SH_DAC PCM");
2498c2ecf20Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sh_dac_pcm_ops);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* buffer size=48K */
2528c2ecf20Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
2538c2ecf20Sopenharmony_ci				       NULL, 48 * 1024, 48 * 1024);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci/* END OF PCM INTERFACE */
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/* driver .remove  --  destructor */
2618c2ecf20Sopenharmony_cistatic int snd_sh_dac_remove(struct platform_device *devptr)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	snd_card_free(platform_get_drvdata(devptr));
2648c2ecf20Sopenharmony_ci	return 0;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci/* free -- it has been defined by create */
2688c2ecf20Sopenharmony_cistatic int snd_sh_dac_free(struct snd_sh_dac *chip)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	/* release the data */
2718c2ecf20Sopenharmony_ci	kfree(chip->data_buffer);
2728c2ecf20Sopenharmony_ci	kfree(chip);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return 0;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic int snd_sh_dac_dev_free(struct snd_device *device)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = device->device_data;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return snd_sh_dac_free(chip);
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip = container_of(handle, struct snd_sh_dac,
2878c2ecf20Sopenharmony_ci					       hrtimer);
2888c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = chip->substream->runtime;
2898c2ecf20Sopenharmony_ci	ssize_t b_ps = frames_to_bytes(runtime, runtime->period_size);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (!chip->empty) {
2928c2ecf20Sopenharmony_ci		sh_dac_output(*chip->buffer_begin, chip->pdata->channel);
2938c2ecf20Sopenharmony_ci		chip->buffer_begin++;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		chip->processed++;
2968c2ecf20Sopenharmony_ci		if (chip->processed >= b_ps) {
2978c2ecf20Sopenharmony_ci			chip->processed -= b_ps;
2988c2ecf20Sopenharmony_ci			snd_pcm_period_elapsed(chip->substream);
2998c2ecf20Sopenharmony_ci		}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		if (chip->buffer_begin == (chip->data_buffer +
3028c2ecf20Sopenharmony_ci					   chip->buffer_size - 1))
3038c2ecf20Sopenharmony_ci			chip->buffer_begin = chip->data_buffer;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci		if (chip->buffer_begin == chip->buffer_end)
3068c2ecf20Sopenharmony_ci			chip->empty = 1;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (!chip->empty)
3118c2ecf20Sopenharmony_ci		hrtimer_start(&chip->hrtimer, chip->wakeups_per_second,
3128c2ecf20Sopenharmony_ci			      HRTIMER_MODE_REL);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return HRTIMER_NORESTART;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/* create  --  chip-specific constructor for the cards components */
3188c2ecf20Sopenharmony_cistatic int snd_sh_dac_create(struct snd_card *card,
3198c2ecf20Sopenharmony_ci			     struct platform_device *devptr,
3208c2ecf20Sopenharmony_ci			     struct snd_sh_dac **rchip)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip;
3238c2ecf20Sopenharmony_ci	int err;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	static const struct snd_device_ops ops = {
3268c2ecf20Sopenharmony_ci		   .dev_free = snd_sh_dac_dev_free,
3278c2ecf20Sopenharmony_ci	};
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	*rchip = NULL;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
3328c2ecf20Sopenharmony_ci	if (chip == NULL)
3338c2ecf20Sopenharmony_ci		return -ENOMEM;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	chip->card = card;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	hrtimer_init(&chip->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
3388c2ecf20Sopenharmony_ci	chip->hrtimer.function = sh_dac_audio_timer;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	dac_audio_reset(chip);
3418c2ecf20Sopenharmony_ci	chip->rate = 8000;
3428c2ecf20Sopenharmony_ci	dac_audio_set_rate(chip);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	chip->pdata = devptr->dev.platform_data;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	chip->data_buffer = kmalloc(chip->pdata->buffer_size, GFP_KERNEL);
3478c2ecf20Sopenharmony_ci	if (chip->data_buffer == NULL) {
3488c2ecf20Sopenharmony_ci		kfree(chip);
3498c2ecf20Sopenharmony_ci		return -ENOMEM;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
3538c2ecf20Sopenharmony_ci	if (err < 0) {
3548c2ecf20Sopenharmony_ci		snd_sh_dac_free(chip);
3558c2ecf20Sopenharmony_ci		return err;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	*rchip = chip;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return 0;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci/* driver .probe  --  constructor */
3648c2ecf20Sopenharmony_cistatic int snd_sh_dac_probe(struct platform_device *devptr)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct snd_sh_dac *chip;
3678c2ecf20Sopenharmony_ci	struct snd_card *card;
3688c2ecf20Sopenharmony_ci	int err;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	err = snd_card_new(&devptr->dev, index, id, THIS_MODULE, 0, &card);
3718c2ecf20Sopenharmony_ci	if (err < 0) {
3728c2ecf20Sopenharmony_ci			snd_printk(KERN_ERR "cannot allocate the card\n");
3738c2ecf20Sopenharmony_ci			return err;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	err = snd_sh_dac_create(card, devptr, &chip);
3778c2ecf20Sopenharmony_ci	if (err < 0)
3788c2ecf20Sopenharmony_ci		goto probe_error;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	err = snd_sh_dac_pcm(chip, 0);
3818c2ecf20Sopenharmony_ci	if (err < 0)
3828c2ecf20Sopenharmony_ci		goto probe_error;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	strcpy(card->driver, "snd_sh_dac");
3858c2ecf20Sopenharmony_ci	strcpy(card->shortname, "SuperH DAC audio driver");
3868c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s %s", card->longname, card->shortname);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	err = snd_card_register(card);
3898c2ecf20Sopenharmony_ci	if (err < 0)
3908c2ecf20Sopenharmony_ci		goto probe_error;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	snd_printk(KERN_INFO "ALSA driver for SuperH DAC audio");
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	platform_set_drvdata(devptr, card);
3958c2ecf20Sopenharmony_ci	return 0;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ciprobe_error:
3988c2ecf20Sopenharmony_ci	snd_card_free(card);
3998c2ecf20Sopenharmony_ci	return err;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci/*
4038c2ecf20Sopenharmony_ci * "driver" definition
4048c2ecf20Sopenharmony_ci */
4058c2ecf20Sopenharmony_cistatic struct platform_driver sh_dac_driver = {
4068c2ecf20Sopenharmony_ci	.probe	= snd_sh_dac_probe,
4078c2ecf20Sopenharmony_ci	.remove = snd_sh_dac_remove,
4088c2ecf20Sopenharmony_ci	.driver = {
4098c2ecf20Sopenharmony_ci		.name = "dac_audio",
4108c2ecf20Sopenharmony_ci	},
4118c2ecf20Sopenharmony_ci};
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cimodule_platform_driver(sh_dac_driver);
414