1a77bf709SSimon Glass /*
2a77bf709SSimon Glass * Copyright (C) 2012 Samsung Electronics
3a77bf709SSimon Glass * R. Chandrasekar <rcsekar@samsung.com>
4a77bf709SSimon Glass *
5a77bf709SSimon Glass * SPDX-License-Identifier: GPL-2.0+
6a77bf709SSimon Glass */
7a77bf709SSimon Glass
8a77bf709SSimon Glass #include <malloc.h>
9a77bf709SSimon Glass #include <common.h>
10a77bf709SSimon Glass #include <asm/io.h>
11*0e00a84cSMasahiro Yamada #include <linux/libfdt.h>
12a77bf709SSimon Glass #include <fdtdec.h>
13a77bf709SSimon Glass #include <i2c.h>
14a77bf709SSimon Glass #include <i2s.h>
15a77bf709SSimon Glass #include <sound.h>
16a77bf709SSimon Glass #include <asm/arch/sound.h>
17a77bf709SSimon Glass #include "wm8994.h"
18a77bf709SSimon Glass #include "max98095.h"
19a77bf709SSimon Glass
20a77bf709SSimon Glass /* defines */
21a77bf709SSimon Glass #define SOUND_400_HZ 400
22a77bf709SSimon Glass #define SOUND_BITS_IN_BYTE 8
23a77bf709SSimon Glass
24a77bf709SSimon Glass static struct i2stx_info g_i2stx_pri;
25a77bf709SSimon Glass
26a77bf709SSimon Glass /*
27a77bf709SSimon Glass * get_sound_i2s_values gets values for i2s parameters
28a77bf709SSimon Glass *
29a77bf709SSimon Glass * @param i2stx_info i2s transmitter transfer param structure
30a77bf709SSimon Glass * @param blob FDT blob if enabled else NULL
31a77bf709SSimon Glass */
get_sound_i2s_values(struct i2stx_info * i2s,const void * blob)32a77bf709SSimon Glass static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob)
33a77bf709SSimon Glass {
34a77bf709SSimon Glass int node;
35a77bf709SSimon Glass int error = 0;
36a77bf709SSimon Glass int base;
37a77bf709SSimon Glass
38a77bf709SSimon Glass node = fdt_path_offset(blob, "i2s");
39a77bf709SSimon Glass if (node <= 0) {
40a77bf709SSimon Glass debug("EXYNOS_SOUND: No node for sound in device tree\n");
41a77bf709SSimon Glass return -1;
42a77bf709SSimon Glass }
43a77bf709SSimon Glass
44a77bf709SSimon Glass /*
45a77bf709SSimon Glass * Get the pre-defined sound specific values from FDT.
46a77bf709SSimon Glass * All of these are expected to be correct otherwise
47a77bf709SSimon Glass * wrong register values in i2s setup parameters
48a77bf709SSimon Glass * may result in no sound play.
49a77bf709SSimon Glass */
50a77bf709SSimon Glass base = fdtdec_get_addr(blob, node, "reg");
51a77bf709SSimon Glass if (base == FDT_ADDR_T_NONE) {
52a77bf709SSimon Glass debug("%s: Missing i2s base\n", __func__);
53a77bf709SSimon Glass return -1;
54a77bf709SSimon Glass }
55a77bf709SSimon Glass i2s->base_address = base;
56a77bf709SSimon Glass
57a77bf709SSimon Glass i2s->audio_pll_clk = fdtdec_get_int(blob,
58a77bf709SSimon Glass node, "samsung,i2s-epll-clock-frequency", -1);
59a77bf709SSimon Glass error |= i2s->audio_pll_clk;
60a77bf709SSimon Glass debug("audio_pll_clk = %d\n", i2s->audio_pll_clk);
61a77bf709SSimon Glass i2s->samplingrate = fdtdec_get_int(blob,
62a77bf709SSimon Glass node, "samsung,i2s-sampling-rate", -1);
63a77bf709SSimon Glass error |= i2s->samplingrate;
64a77bf709SSimon Glass debug("samplingrate = %d\n", i2s->samplingrate);
65a77bf709SSimon Glass i2s->bitspersample = fdtdec_get_int(blob,
66a77bf709SSimon Glass node, "samsung,i2s-bits-per-sample", -1);
67a77bf709SSimon Glass error |= i2s->bitspersample;
68a77bf709SSimon Glass debug("bitspersample = %d\n", i2s->bitspersample);
69a77bf709SSimon Glass i2s->channels = fdtdec_get_int(blob,
70a77bf709SSimon Glass node, "samsung,i2s-channels", -1);
71a77bf709SSimon Glass error |= i2s->channels;
72a77bf709SSimon Glass debug("channels = %d\n", i2s->channels);
73a77bf709SSimon Glass i2s->rfs = fdtdec_get_int(blob,
74a77bf709SSimon Glass node, "samsung,i2s-lr-clk-framesize", -1);
75a77bf709SSimon Glass error |= i2s->rfs;
76a77bf709SSimon Glass debug("rfs = %d\n", i2s->rfs);
77a77bf709SSimon Glass i2s->bfs = fdtdec_get_int(blob,
78a77bf709SSimon Glass node, "samsung,i2s-bit-clk-framesize", -1);
79a77bf709SSimon Glass error |= i2s->bfs;
80a77bf709SSimon Glass debug("bfs = %d\n", i2s->bfs);
81a77bf709SSimon Glass
82a77bf709SSimon Glass i2s->id = fdtdec_get_int(blob, node, "samsung,i2s-id", -1);
83a77bf709SSimon Glass error |= i2s->id;
84a77bf709SSimon Glass debug("id = %d\n", i2s->id);
85a77bf709SSimon Glass
86a77bf709SSimon Glass if (error == -1) {
87a77bf709SSimon Glass debug("fail to get sound i2s node properties\n");
88a77bf709SSimon Glass return -1;
89a77bf709SSimon Glass }
90a77bf709SSimon Glass
91a77bf709SSimon Glass return 0;
92a77bf709SSimon Glass }
93a77bf709SSimon Glass
94a77bf709SSimon Glass /*
95a77bf709SSimon Glass * Init codec
96a77bf709SSimon Glass *
97a77bf709SSimon Glass * @param blob FDT blob
98a77bf709SSimon Glass * @param pi2s_tx i2s parameters required by codec
99a77bf709SSimon Glass * @return int value, 0 for success
100a77bf709SSimon Glass */
codec_init(const void * blob,struct i2stx_info * pi2s_tx)101a77bf709SSimon Glass static int codec_init(const void *blob, struct i2stx_info *pi2s_tx)
102a77bf709SSimon Glass {
103a77bf709SSimon Glass int ret;
104a77bf709SSimon Glass const char *codectype;
105a77bf709SSimon Glass int node;
106a77bf709SSimon Glass
107a77bf709SSimon Glass /* Get the node from FDT for sound */
108a77bf709SSimon Glass node = fdt_path_offset(blob, "i2s");
109a77bf709SSimon Glass if (node <= 0) {
110a77bf709SSimon Glass debug("EXYNOS_SOUND: No node for sound in device tree\n");
111a77bf709SSimon Glass debug("node = %d\n", node);
112a77bf709SSimon Glass return -1;
113a77bf709SSimon Glass }
114a77bf709SSimon Glass
115a77bf709SSimon Glass /*
116a77bf709SSimon Glass * Get the pre-defined sound codec specific values from FDT.
117a77bf709SSimon Glass * All of these are expected to be correct otherwise sound
118a77bf709SSimon Glass * can not be played
119a77bf709SSimon Glass */
120a77bf709SSimon Glass codectype = fdt_getprop(blob, node, "samsung,codec-type", NULL);
121a77bf709SSimon Glass debug("device = %s\n", codectype);
122a77bf709SSimon Glass if (!strcmp(codectype, "wm8994")) {
123a77bf709SSimon Glass /* Check the codec type and initialise the same */
124a77bf709SSimon Glass ret = wm8994_init(blob, pi2s_tx->id + 1,
125a77bf709SSimon Glass pi2s_tx->samplingrate,
126a77bf709SSimon Glass (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
127a77bf709SSimon Glass pi2s_tx->bitspersample, pi2s_tx->channels);
128a77bf709SSimon Glass } else if (!strcmp(codectype, "max98095")) {
129a77bf709SSimon Glass ret = max98095_init(blob, pi2s_tx->id + 1,
130a77bf709SSimon Glass pi2s_tx->samplingrate,
131a77bf709SSimon Glass (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
132a77bf709SSimon Glass pi2s_tx->bitspersample);
133a77bf709SSimon Glass } else {
134a77bf709SSimon Glass debug("%s: Unknown codec type %s\n", __func__, codectype);
135a77bf709SSimon Glass return -1;
136a77bf709SSimon Glass }
137a77bf709SSimon Glass
138a77bf709SSimon Glass if (ret) {
139a77bf709SSimon Glass debug("%s: Codec init failed\n", __func__);
140a77bf709SSimon Glass return -1;
141a77bf709SSimon Glass }
142a77bf709SSimon Glass
143a77bf709SSimon Glass return 0;
144a77bf709SSimon Glass }
145a77bf709SSimon Glass
sound_init(const void * blob)146a77bf709SSimon Glass int sound_init(const void *blob)
147a77bf709SSimon Glass {
148a77bf709SSimon Glass int ret;
149a77bf709SSimon Glass struct i2stx_info *pi2s_tx = &g_i2stx_pri;
150a77bf709SSimon Glass
151a77bf709SSimon Glass /* Get the I2S Values */
152a77bf709SSimon Glass if (get_sound_i2s_values(pi2s_tx, blob) < 0) {
153a77bf709SSimon Glass debug(" FDT I2S values failed\n");
154a77bf709SSimon Glass return -1;
155a77bf709SSimon Glass }
156a77bf709SSimon Glass
157a77bf709SSimon Glass if (codec_init(blob, pi2s_tx) < 0) {
158a77bf709SSimon Glass debug(" Codec init failed\n");
159a77bf709SSimon Glass return -1;
160a77bf709SSimon Glass }
161a77bf709SSimon Glass
162a77bf709SSimon Glass ret = i2s_tx_init(pi2s_tx);
163a77bf709SSimon Glass if (ret) {
164a77bf709SSimon Glass debug("%s: Failed to init i2c transmit: ret=%d\n", __func__,
165a77bf709SSimon Glass ret);
166a77bf709SSimon Glass return ret;
167a77bf709SSimon Glass }
168a77bf709SSimon Glass
169a77bf709SSimon Glass
170a77bf709SSimon Glass return ret;
171a77bf709SSimon Glass }
172a77bf709SSimon Glass
sound_play(uint32_t msec,uint32_t frequency)173a77bf709SSimon Glass int sound_play(uint32_t msec, uint32_t frequency)
174a77bf709SSimon Glass {
175a77bf709SSimon Glass unsigned int *data;
176a77bf709SSimon Glass unsigned long data_size;
177a77bf709SSimon Glass unsigned int ret = 0;
178a77bf709SSimon Glass
179a77bf709SSimon Glass /*Buffer length computation */
180a77bf709SSimon Glass data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels;
181a77bf709SSimon Glass data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE);
182a77bf709SSimon Glass data = malloc(data_size);
183a77bf709SSimon Glass
184a77bf709SSimon Glass if (data == NULL) {
185a77bf709SSimon Glass debug("%s: malloc failed\n", __func__);
186a77bf709SSimon Glass return -1;
187a77bf709SSimon Glass }
188a77bf709SSimon Glass
189a77bf709SSimon Glass sound_create_square_wave((unsigned short *)data,
190a77bf709SSimon Glass data_size / sizeof(unsigned short),
191a77bf709SSimon Glass frequency);
192a77bf709SSimon Glass
193a77bf709SSimon Glass while (msec >= 1000) {
194a77bf709SSimon Glass ret = i2s_transfer_tx_data(&g_i2stx_pri, data,
195a77bf709SSimon Glass (data_size / sizeof(int)));
196a77bf709SSimon Glass msec -= 1000;
197a77bf709SSimon Glass }
198a77bf709SSimon Glass if (msec) {
199a77bf709SSimon Glass unsigned long size =
200a77bf709SSimon Glass (data_size * msec) / (sizeof(int) * 1000);
201a77bf709SSimon Glass
202a77bf709SSimon Glass ret = i2s_transfer_tx_data(&g_i2stx_pri, data, size);
203a77bf709SSimon Glass }
204a77bf709SSimon Glass
205a77bf709SSimon Glass free(data);
206a77bf709SSimon Glass
207a77bf709SSimon Glass return ret;
208a77bf709SSimon Glass }
209