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