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