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