uboot/drivers/sound/sound-i2s.c
<<
>>
Prefs
   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
  24static 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 */
  32static 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 */
 101static 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
 146int 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
 173int 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}
 209