2 * Samsung exynos4210 Audio driver
4 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * Vorobiov Stanislav <s.vorobiov@samsung.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "exynos4210_i2s.h"
25 /* #define DEBUG_EXYNOS4210_AUDIO */
27 #ifdef DEBUG_EXYNOS4210_AUDIO
28 #define DPRINTF(fmt, ...) \
30 fprintf(stdout, "AUDIO: [%s:%d] " fmt, __func__, __LINE__, \
34 #define DPRINTF(fmt, ...) do {} while (0)
37 #define AUDIO_MAX_WORDS (4096 / EXYNOS4210_I2S_WORD_LEN)
40 Exynos4210I2SSlave i2s;
43 } Exynos4210AudioState;
45 static void exynos4210_audio_callback(void *opaque, int free_out_bytes)
47 Exynos4210AudioState *s = (Exynos4210AudioState *)opaque;
48 uint8_t buff[AUDIO_MAX_WORDS * EXYNOS4210_I2S_WORD_LEN];
49 int free_out_words = free_out_bytes / EXYNOS4210_I2S_WORD_LEN;
52 if (free_out_words <= 0) {
56 if (free_out_words > AUDIO_MAX_WORDS) {
57 free_out_words = AUDIO_MAX_WORDS;
60 if (!exynos4210_i2s_dma_enabled(qdev_get_parent_bus(&s->i2s.qdev))) {
64 num_words = exynos4210_i2s_dma_get_words_available(
65 qdev_get_parent_bus(&s->i2s.qdev));
67 num_words = MIN(num_words, free_out_words);
69 exynos4210_i2s_dma_read(qdev_get_parent_bus(&s->i2s.qdev),
73 num_words = wm8994_dac_write(s->wm8994,
75 num_words * EXYNOS4210_I2S_WORD_LEN) / EXYNOS4210_I2S_WORD_LEN;
77 exynos4210_i2s_dma_advance(qdev_get_parent_bus(&s->i2s.qdev), num_words);
80 static void exynos4210_audio_dma_enable(Exynos4210I2SSlave *i2s, bool enable)
82 Exynos4210AudioState *s =
83 FROM_EXYNOS4210_I2S_SLAVE(Exynos4210AudioState, i2s);
85 DPRINTF("enter %d\n", enable);
87 wm8994_set_active(s->wm8994, enable);
90 static void exynos4210_audio_reset(DeviceState *dev)
95 static int exynos4210_audio_init(Exynos4210I2SSlave *i2s)
97 Exynos4210AudioState *s =
98 FROM_EXYNOS4210_I2S_SLAVE(Exynos4210AudioState, i2s);
100 wm8994_data_req_set(s->wm8994, exynos4210_audio_callback, s);
105 static const VMStateDescription vmstate_exynos4210_audio = {
106 .name = "exynos4210.audio",
108 .minimum_version_id = 1,
109 .minimum_version_id_old = 1,
110 .fields = (VMStateField[]) {
111 VMSTATE_EXYNOS4210_I2S_SLAVE(i2s, Exynos4210AudioState),
112 VMSTATE_END_OF_LIST()
116 static Property exynos4210_audio_properties[] = {
119 .info = &qdev_prop_ptr,
120 .offset = offsetof(Exynos4210AudioState, wm8994),
122 DEFINE_PROP_END_OF_LIST(),
125 static void exynos4210_audio_class_init(ObjectClass *klass, void *data)
127 DeviceClass *dc = DEVICE_CLASS(klass);
128 Exynos4210I2SSlaveClass *sc = EXYNOS4210_I2S_SLAVE_CLASS(klass);
130 sc->init = exynos4210_audio_init;
131 sc->dma_enable = exynos4210_audio_dma_enable;
132 dc->reset = exynos4210_audio_reset;
133 dc->props = exynos4210_audio_properties;
134 dc->vmsd = &vmstate_exynos4210_audio;
137 static TypeInfo exynos4210_audio_info = {
138 .name = "exynos4210.audio",
139 .parent = TYPE_EXYNOS4210_I2S_SLAVE,
140 .instance_size = sizeof(Exynos4210AudioState),
141 .class_init = exynos4210_audio_class_init,
144 static void exynos4210_audio_register_types(void)
146 type_register_static(&exynos4210_audio_info);
149 type_init(exynos4210_audio_register_types)