183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2a2d8e0a7SRajeshwari Shinde /* 3a2d8e0a7SRajeshwari Shinde * Copyright (C) 2012 Samsung Electronics 4a2d8e0a7SRajeshwari Shinde * R. Chandrasekar <rcsekar@samsung.com> 5a2d8e0a7SRajeshwari Shinde */ 6150c5afeSSimon Glass #include <common.h> 7a2d8e0a7SRajeshwari Shinde #include <asm/arch/clk.h> 8a2d8e0a7SRajeshwari Shinde #include <asm/arch/cpu.h> 9a2d8e0a7SRajeshwari Shinde #include <asm/gpio.h> 10a2d8e0a7SRajeshwari Shinde #include <asm/io.h> 11a2d8e0a7SRajeshwari Shinde #include <div64.h> 126647c7acSRajeshwari Shinde #include <fdtdec.h> 13a2d8e0a7SRajeshwari Shinde #include <i2c.h> 14a2d8e0a7SRajeshwari Shinde #include <i2s.h> 15a2d8e0a7SRajeshwari Shinde #include <sound.h> 166647c7acSRajeshwari Shinde #include <asm/arch/sound.h> 17a2d8e0a7SRajeshwari Shinde #include "wm8994.h" 18a2d8e0a7SRajeshwari Shinde #include "wm8994_registers.h" 19a2d8e0a7SRajeshwari Shinde 20a2d8e0a7SRajeshwari Shinde /* defines for wm8994 system clock selection */ 21a2d8e0a7SRajeshwari Shinde #define SEL_MCLK1 0x00 22a2d8e0a7SRajeshwari Shinde #define SEL_MCLK2 0x08 23a2d8e0a7SRajeshwari Shinde #define SEL_FLL1 0x10 24a2d8e0a7SRajeshwari Shinde #define SEL_FLL2 0x18 25a2d8e0a7SRajeshwari Shinde 26a2d8e0a7SRajeshwari Shinde /* fll config to configure fll */ 27a2d8e0a7SRajeshwari Shinde struct wm8994_fll_config { 28a2d8e0a7SRajeshwari Shinde int src; /* Source */ 29a2d8e0a7SRajeshwari Shinde int in; /* Input frequency in Hz */ 30a2d8e0a7SRajeshwari Shinde int out; /* output frequency in Hz */ 31a2d8e0a7SRajeshwari Shinde }; 32a2d8e0a7SRajeshwari Shinde 33a2d8e0a7SRajeshwari Shinde /* codec private data */ 34a2d8e0a7SRajeshwari Shinde struct wm8994_priv { 35a2d8e0a7SRajeshwari Shinde enum wm8994_type type; /* codec type of wolfson */ 36a2d8e0a7SRajeshwari Shinde int revision; /* Revision */ 37a2d8e0a7SRajeshwari Shinde int sysclk[WM8994_MAX_AIF]; /* System clock frequency in Hz */ 38a2d8e0a7SRajeshwari Shinde int mclk[WM8994_MAX_AIF]; /* master clock frequency in Hz */ 39a2d8e0a7SRajeshwari Shinde int aifclk[WM8994_MAX_AIF]; /* audio interface clock in Hz */ 40a2d8e0a7SRajeshwari Shinde struct wm8994_fll_config fll[2]; /* fll config to configure fll */ 41a2d8e0a7SRajeshwari Shinde }; 42a2d8e0a7SRajeshwari Shinde 43a2d8e0a7SRajeshwari Shinde /* wm 8994 supported sampling rate values */ 44a2d8e0a7SRajeshwari Shinde static unsigned int src_rate[] = { 45a2d8e0a7SRajeshwari Shinde 8000, 11025, 12000, 16000, 22050, 24000, 46a2d8e0a7SRajeshwari Shinde 32000, 44100, 48000, 88200, 96000 47a2d8e0a7SRajeshwari Shinde }; 48a2d8e0a7SRajeshwari Shinde 49a2d8e0a7SRajeshwari Shinde /* op clock divisions */ 50a2d8e0a7SRajeshwari Shinde static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; 51a2d8e0a7SRajeshwari Shinde 52a2d8e0a7SRajeshwari Shinde /* lr clock frame size ratio */ 53a2d8e0a7SRajeshwari Shinde static int fs_ratios[] = { 54a2d8e0a7SRajeshwari Shinde 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536 55a2d8e0a7SRajeshwari Shinde }; 56a2d8e0a7SRajeshwari Shinde 57a2d8e0a7SRajeshwari Shinde /* bit clock divisors */ 58a2d8e0a7SRajeshwari Shinde static int bclk_divs[] = { 59a2d8e0a7SRajeshwari Shinde 10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480, 60a2d8e0a7SRajeshwari Shinde 640, 880, 960, 1280, 1760, 1920 61a2d8e0a7SRajeshwari Shinde }; 62a2d8e0a7SRajeshwari Shinde 63a2d8e0a7SRajeshwari Shinde static struct wm8994_priv g_wm8994_info; 64a2d8e0a7SRajeshwari Shinde static unsigned char g_wm8994_i2c_dev_addr; 656647c7acSRajeshwari Shinde static struct sound_codec_info g_codec_info; 66a2d8e0a7SRajeshwari Shinde 67a2d8e0a7SRajeshwari Shinde /* 68a2d8e0a7SRajeshwari Shinde * Initialise I2C for wm 8994 69a2d8e0a7SRajeshwari Shinde * 70a2d8e0a7SRajeshwari Shinde * @param bus no i2c bus number in which wm8994 is connected 71a2d8e0a7SRajeshwari Shinde */ 72a2d8e0a7SRajeshwari Shinde static void wm8994_i2c_init(int bus_no) 73a2d8e0a7SRajeshwari Shinde { 74a2d8e0a7SRajeshwari Shinde i2c_set_bus_num(bus_no); 75a2d8e0a7SRajeshwari Shinde } 76a2d8e0a7SRajeshwari Shinde 77a2d8e0a7SRajeshwari Shinde /* 78a2d8e0a7SRajeshwari Shinde * Writes value to a device register through i2c 79a2d8e0a7SRajeshwari Shinde * 80107ab83eSSimon Glass * @param priv Private data for driver 81a2d8e0a7SRajeshwari Shinde * @param reg reg number to be write 82a2d8e0a7SRajeshwari Shinde * @param data data to be writen to the above registor 83a2d8e0a7SRajeshwari Shinde * 84a2d8e0a7SRajeshwari Shinde * @return int value 1 for change, 0 for no change or negative error code. 85a2d8e0a7SRajeshwari Shinde */ 86107ab83eSSimon Glass static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg, 87107ab83eSSimon Glass unsigned short data) 88a2d8e0a7SRajeshwari Shinde { 89a2d8e0a7SRajeshwari Shinde unsigned char val[2]; 90a2d8e0a7SRajeshwari Shinde 91a2d8e0a7SRajeshwari Shinde val[0] = (unsigned char)((data >> 8) & 0xff); 92a2d8e0a7SRajeshwari Shinde val[1] = (unsigned char)(data & 0xff); 93a2d8e0a7SRajeshwari Shinde debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data); 94a2d8e0a7SRajeshwari Shinde 95a2d8e0a7SRajeshwari Shinde return i2c_write(g_wm8994_i2c_dev_addr, reg, 2, val, 2); 96a2d8e0a7SRajeshwari Shinde } 97a2d8e0a7SRajeshwari Shinde 98a2d8e0a7SRajeshwari Shinde /* 99a2d8e0a7SRajeshwari Shinde * Read a value from a device register through i2c 100a2d8e0a7SRajeshwari Shinde * 101107ab83eSSimon Glass * @param priv Private data for driver 102a2d8e0a7SRajeshwari Shinde * @param reg reg number to be read 103a2d8e0a7SRajeshwari Shinde * @param data address of read data to be stored 104a2d8e0a7SRajeshwari Shinde * 105a2d8e0a7SRajeshwari Shinde * @return int value 0 for success, -1 in case of error. 106a2d8e0a7SRajeshwari Shinde */ 107107ab83eSSimon Glass static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg, 108107ab83eSSimon Glass unsigned short *data) 109a2d8e0a7SRajeshwari Shinde { 110a2d8e0a7SRajeshwari Shinde unsigned char val[2]; 111a2d8e0a7SRajeshwari Shinde int ret; 112a2d8e0a7SRajeshwari Shinde 113a2d8e0a7SRajeshwari Shinde ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2); 114a2d8e0a7SRajeshwari Shinde if (ret != 0) { 115a2d8e0a7SRajeshwari Shinde debug("%s: Error while reading register %#04x\n", 116a2d8e0a7SRajeshwari Shinde __func__, reg); 117a2d8e0a7SRajeshwari Shinde return -1; 118a2d8e0a7SRajeshwari Shinde } 119a2d8e0a7SRajeshwari Shinde 120a2d8e0a7SRajeshwari Shinde *data = val[0]; 121a2d8e0a7SRajeshwari Shinde *data <<= 8; 122a2d8e0a7SRajeshwari Shinde *data |= val[1]; 123a2d8e0a7SRajeshwari Shinde 124a2d8e0a7SRajeshwari Shinde return 0; 125a2d8e0a7SRajeshwari Shinde } 126a2d8e0a7SRajeshwari Shinde 127a2d8e0a7SRajeshwari Shinde /* 128a2d8e0a7SRajeshwari Shinde * update device register bits through i2c 129a2d8e0a7SRajeshwari Shinde * 130107ab83eSSimon Glass * @param priv Private data for driver 131a2d8e0a7SRajeshwari Shinde * @param reg codec register 132a2d8e0a7SRajeshwari Shinde * @param mask register mask 133a2d8e0a7SRajeshwari Shinde * @param value new value 134a2d8e0a7SRajeshwari Shinde * 135a2d8e0a7SRajeshwari Shinde * @return int value 1 if change in the register value, 136a2d8e0a7SRajeshwari Shinde * 0 for no change or negative error code. 137a2d8e0a7SRajeshwari Shinde */ 138107ab83eSSimon Glass static int wm8994_bic_or(struct wm8994_priv *priv, unsigned int reg, 139107ab83eSSimon Glass unsigned short mask, unsigned short value) 140a2d8e0a7SRajeshwari Shinde { 141a2d8e0a7SRajeshwari Shinde int change , ret = 0; 142a2d8e0a7SRajeshwari Shinde unsigned short old, new; 143a2d8e0a7SRajeshwari Shinde 144107ab83eSSimon Glass if (wm8994_i2c_read(priv, reg, &old) != 0) 145a2d8e0a7SRajeshwari Shinde return -1; 146a2d8e0a7SRajeshwari Shinde new = (old & ~mask) | (value & mask); 147a2d8e0a7SRajeshwari Shinde change = (old != new) ? 1 : 0; 148a2d8e0a7SRajeshwari Shinde if (change) 149107ab83eSSimon Glass ret = wm8994_i2c_write(priv, reg, new); 150a2d8e0a7SRajeshwari Shinde if (ret < 0) 151a2d8e0a7SRajeshwari Shinde return ret; 152a2d8e0a7SRajeshwari Shinde 153a2d8e0a7SRajeshwari Shinde return change; 154a2d8e0a7SRajeshwari Shinde } 155a2d8e0a7SRajeshwari Shinde 156a2d8e0a7SRajeshwari Shinde /* 157a2d8e0a7SRajeshwari Shinde * Sets i2s set format 158a2d8e0a7SRajeshwari Shinde * 159107ab83eSSimon Glass * @param priv wm8994 information 160a2d8e0a7SRajeshwari Shinde * @param aif_id Interface ID 161a2d8e0a7SRajeshwari Shinde * @param fmt i2S format 162a2d8e0a7SRajeshwari Shinde * 163a2d8e0a7SRajeshwari Shinde * @return -1 for error and 0 Success. 164a2d8e0a7SRajeshwari Shinde */ 165107ab83eSSimon Glass static int wm8994_set_fmt(struct wm8994_priv *priv, int aif_id, uint fmt) 166a2d8e0a7SRajeshwari Shinde { 167a2d8e0a7SRajeshwari Shinde int ms_reg; 168a2d8e0a7SRajeshwari Shinde int aif_reg; 169a2d8e0a7SRajeshwari Shinde int ms = 0; 170a2d8e0a7SRajeshwari Shinde int aif = 0; 171a2d8e0a7SRajeshwari Shinde int aif_clk = 0; 172a2d8e0a7SRajeshwari Shinde int error = 0; 173a2d8e0a7SRajeshwari Shinde 174a2d8e0a7SRajeshwari Shinde switch (aif_id) { 175a2d8e0a7SRajeshwari Shinde case 1: 176a2d8e0a7SRajeshwari Shinde ms_reg = WM8994_AIF1_MASTER_SLAVE; 177a2d8e0a7SRajeshwari Shinde aif_reg = WM8994_AIF1_CONTROL_1; 178a2d8e0a7SRajeshwari Shinde aif_clk = WM8994_AIF1_CLOCKING_1; 179a2d8e0a7SRajeshwari Shinde break; 180a2d8e0a7SRajeshwari Shinde case 2: 181a2d8e0a7SRajeshwari Shinde ms_reg = WM8994_AIF2_MASTER_SLAVE; 182a2d8e0a7SRajeshwari Shinde aif_reg = WM8994_AIF2_CONTROL_1; 183a2d8e0a7SRajeshwari Shinde aif_clk = WM8994_AIF2_CLOCKING_1; 184a2d8e0a7SRajeshwari Shinde break; 185a2d8e0a7SRajeshwari Shinde default: 186a2d8e0a7SRajeshwari Shinde debug("%s: Invalid audio interface selection\n", __func__); 187a2d8e0a7SRajeshwari Shinde return -1; 188a2d8e0a7SRajeshwari Shinde } 189a2d8e0a7SRajeshwari Shinde 190a2d8e0a7SRajeshwari Shinde switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 191a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_CBS_CFS: 192a2d8e0a7SRajeshwari Shinde break; 193a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_CBM_CFM: 194a2d8e0a7SRajeshwari Shinde ms = WM8994_AIF1_MSTR; 195a2d8e0a7SRajeshwari Shinde break; 196a2d8e0a7SRajeshwari Shinde default: 197a2d8e0a7SRajeshwari Shinde debug("%s: Invalid i2s master selection\n", __func__); 198a2d8e0a7SRajeshwari Shinde return -1; 199a2d8e0a7SRajeshwari Shinde } 200a2d8e0a7SRajeshwari Shinde 201a2d8e0a7SRajeshwari Shinde switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 202a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_DSP_B: 203a2d8e0a7SRajeshwari Shinde aif |= WM8994_AIF1_LRCLK_INV; 204a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_DSP_A: 205a2d8e0a7SRajeshwari Shinde aif |= 0x18; 206a2d8e0a7SRajeshwari Shinde break; 207a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_I2S: 208a2d8e0a7SRajeshwari Shinde aif |= 0x10; 209a2d8e0a7SRajeshwari Shinde break; 210a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_RIGHT_J: 211a2d8e0a7SRajeshwari Shinde break; 212a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_LEFT_J: 213a2d8e0a7SRajeshwari Shinde aif |= 0x8; 214a2d8e0a7SRajeshwari Shinde break; 215a2d8e0a7SRajeshwari Shinde default: 216a2d8e0a7SRajeshwari Shinde debug("%s: Invalid i2s format selection\n", __func__); 217a2d8e0a7SRajeshwari Shinde return -1; 218a2d8e0a7SRajeshwari Shinde } 219a2d8e0a7SRajeshwari Shinde 220a2d8e0a7SRajeshwari Shinde switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 221a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_DSP_A: 222a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_DSP_B: 223a2d8e0a7SRajeshwari Shinde /* frame inversion not valid for DSP modes */ 224a2d8e0a7SRajeshwari Shinde switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 225a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_NB_NF: 226a2d8e0a7SRajeshwari Shinde break; 227a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_IB_NF: 228a2d8e0a7SRajeshwari Shinde aif |= WM8994_AIF1_BCLK_INV; 229a2d8e0a7SRajeshwari Shinde break; 230a2d8e0a7SRajeshwari Shinde default: 231a2d8e0a7SRajeshwari Shinde debug("%s: Invalid i2s frame inverse selection\n", 232a2d8e0a7SRajeshwari Shinde __func__); 233a2d8e0a7SRajeshwari Shinde return -1; 234a2d8e0a7SRajeshwari Shinde } 235a2d8e0a7SRajeshwari Shinde break; 236a2d8e0a7SRajeshwari Shinde 237a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_I2S: 238a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_RIGHT_J: 239a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_LEFT_J: 240a2d8e0a7SRajeshwari Shinde switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 241a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_NB_NF: 242a2d8e0a7SRajeshwari Shinde break; 243a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_IB_IF: 244a2d8e0a7SRajeshwari Shinde aif |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; 245a2d8e0a7SRajeshwari Shinde break; 246a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_IB_NF: 247a2d8e0a7SRajeshwari Shinde aif |= WM8994_AIF1_BCLK_INV; 248a2d8e0a7SRajeshwari Shinde break; 249a2d8e0a7SRajeshwari Shinde case SND_SOC_DAIFMT_NB_IF: 250a2d8e0a7SRajeshwari Shinde aif |= WM8994_AIF1_LRCLK_INV; 251a2d8e0a7SRajeshwari Shinde break; 252a2d8e0a7SRajeshwari Shinde default: 253a2d8e0a7SRajeshwari Shinde debug("%s: Invalid i2s clock polarity selection\n", 254a2d8e0a7SRajeshwari Shinde __func__); 255a2d8e0a7SRajeshwari Shinde return -1; 256a2d8e0a7SRajeshwari Shinde } 257a2d8e0a7SRajeshwari Shinde break; 258a2d8e0a7SRajeshwari Shinde default: 259a2d8e0a7SRajeshwari Shinde debug("%s: Invalid i2s format selection\n", __func__); 260a2d8e0a7SRajeshwari Shinde return -1; 261a2d8e0a7SRajeshwari Shinde } 262a2d8e0a7SRajeshwari Shinde 263107ab83eSSimon Glass error = wm8994_bic_or(priv, aif_reg, WM8994_AIF1_BCLK_INV | 264107ab83eSSimon Glass WM8994_AIF1_LRCLK_INV_MASK | 265107ab83eSSimon Glass WM8994_AIF1_FMT_MASK, aif); 266a2d8e0a7SRajeshwari Shinde 267107ab83eSSimon Glass error |= wm8994_bic_or(priv, ms_reg, WM8994_AIF1_MSTR_MASK, ms); 268107ab83eSSimon Glass error |= wm8994_bic_or(priv, aif_clk, WM8994_AIF1CLK_ENA_MASK, 269a2d8e0a7SRajeshwari Shinde WM8994_AIF1CLK_ENA); 270a2d8e0a7SRajeshwari Shinde if (error < 0) { 271a2d8e0a7SRajeshwari Shinde debug("%s: codec register access error\n", __func__); 272a2d8e0a7SRajeshwari Shinde return -1; 273a2d8e0a7SRajeshwari Shinde } 274a2d8e0a7SRajeshwari Shinde 275a2d8e0a7SRajeshwari Shinde return 0; 276a2d8e0a7SRajeshwari Shinde } 277a2d8e0a7SRajeshwari Shinde 278a2d8e0a7SRajeshwari Shinde /* 279a2d8e0a7SRajeshwari Shinde * Sets hw params FOR WM8994 280a2d8e0a7SRajeshwari Shinde * 281107ab83eSSimon Glass * @param priv wm8994 information pointer 282a2d8e0a7SRajeshwari Shinde * @param aif_id Audio interface ID 283a2d8e0a7SRajeshwari Shinde * @param sampling_rate Sampling rate 284a2d8e0a7SRajeshwari Shinde * @param bits_per_sample Bits per sample 285a2d8e0a7SRajeshwari Shinde * @param Channels Channels in the given audio input 286a2d8e0a7SRajeshwari Shinde * 287a2d8e0a7SRajeshwari Shinde * @return -1 for error and 0 Success. 288a2d8e0a7SRajeshwari Shinde */ 289107ab83eSSimon Glass static int wm8994_hw_params(struct wm8994_priv *priv, int aif_id, 290107ab83eSSimon Glass uint sampling_rate, uint bits_per_sample, 291107ab83eSSimon Glass uint channels) 292a2d8e0a7SRajeshwari Shinde { 293a2d8e0a7SRajeshwari Shinde int aif1_reg; 294a2d8e0a7SRajeshwari Shinde int aif2_reg; 295a2d8e0a7SRajeshwari Shinde int bclk_reg; 296a2d8e0a7SRajeshwari Shinde int bclk = 0; 297a2d8e0a7SRajeshwari Shinde int rate_reg; 298a2d8e0a7SRajeshwari Shinde int aif1 = 0; 299a2d8e0a7SRajeshwari Shinde int aif2 = 0; 300a2d8e0a7SRajeshwari Shinde int rate_val = 0; 301a2d8e0a7SRajeshwari Shinde int id = aif_id - 1; 302a2d8e0a7SRajeshwari Shinde int i, cur_val, best_val, bclk_rate, best; 303a2d8e0a7SRajeshwari Shinde unsigned short reg_data; 304a2d8e0a7SRajeshwari Shinde int ret = 0; 305a2d8e0a7SRajeshwari Shinde 306a2d8e0a7SRajeshwari Shinde switch (aif_id) { 307a2d8e0a7SRajeshwari Shinde case 1: 308a2d8e0a7SRajeshwari Shinde aif1_reg = WM8994_AIF1_CONTROL_1; 309a2d8e0a7SRajeshwari Shinde aif2_reg = WM8994_AIF1_CONTROL_2; 310a2d8e0a7SRajeshwari Shinde bclk_reg = WM8994_AIF1_BCLK; 311a2d8e0a7SRajeshwari Shinde rate_reg = WM8994_AIF1_RATE; 312a2d8e0a7SRajeshwari Shinde break; 313a2d8e0a7SRajeshwari Shinde case 2: 314a2d8e0a7SRajeshwari Shinde aif1_reg = WM8994_AIF2_CONTROL_1; 315a2d8e0a7SRajeshwari Shinde aif2_reg = WM8994_AIF2_CONTROL_2; 316a2d8e0a7SRajeshwari Shinde bclk_reg = WM8994_AIF2_BCLK; 317a2d8e0a7SRajeshwari Shinde rate_reg = WM8994_AIF2_RATE; 318a2d8e0a7SRajeshwari Shinde break; 319a2d8e0a7SRajeshwari Shinde default: 320a2d8e0a7SRajeshwari Shinde return -1; 321a2d8e0a7SRajeshwari Shinde } 322a2d8e0a7SRajeshwari Shinde 323a2d8e0a7SRajeshwari Shinde bclk_rate = sampling_rate * 32; 324a2d8e0a7SRajeshwari Shinde switch (bits_per_sample) { 325a2d8e0a7SRajeshwari Shinde case 16: 326a2d8e0a7SRajeshwari Shinde bclk_rate *= 16; 327a2d8e0a7SRajeshwari Shinde break; 328a2d8e0a7SRajeshwari Shinde case 20: 329a2d8e0a7SRajeshwari Shinde bclk_rate *= 20; 330a2d8e0a7SRajeshwari Shinde aif1 |= 0x20; 331a2d8e0a7SRajeshwari Shinde break; 332a2d8e0a7SRajeshwari Shinde case 24: 333a2d8e0a7SRajeshwari Shinde bclk_rate *= 24; 334a2d8e0a7SRajeshwari Shinde aif1 |= 0x40; 335a2d8e0a7SRajeshwari Shinde break; 336a2d8e0a7SRajeshwari Shinde case 32: 337a2d8e0a7SRajeshwari Shinde bclk_rate *= 32; 338a2d8e0a7SRajeshwari Shinde aif1 |= 0x60; 339a2d8e0a7SRajeshwari Shinde break; 340a2d8e0a7SRajeshwari Shinde default: 341a2d8e0a7SRajeshwari Shinde return -1; 342a2d8e0a7SRajeshwari Shinde } 343a2d8e0a7SRajeshwari Shinde 344a2d8e0a7SRajeshwari Shinde /* Try to find an appropriate sample rate; look for an exact match. */ 345a2d8e0a7SRajeshwari Shinde for (i = 0; i < ARRAY_SIZE(src_rate); i++) 346a2d8e0a7SRajeshwari Shinde if (src_rate[i] == sampling_rate) 347a2d8e0a7SRajeshwari Shinde break; 348a2d8e0a7SRajeshwari Shinde 349a2d8e0a7SRajeshwari Shinde if (i == ARRAY_SIZE(src_rate)) { 350a2d8e0a7SRajeshwari Shinde debug("%s: Could not get the best matching samplingrate\n", 351a2d8e0a7SRajeshwari Shinde __func__); 352a2d8e0a7SRajeshwari Shinde return -1; 353a2d8e0a7SRajeshwari Shinde } 354a2d8e0a7SRajeshwari Shinde 355a2d8e0a7SRajeshwari Shinde rate_val |= i << WM8994_AIF1_SR_SHIFT; 356a2d8e0a7SRajeshwari Shinde 357a2d8e0a7SRajeshwari Shinde /* AIFCLK/fs ratio; look for a close match in either direction */ 358a2d8e0a7SRajeshwari Shinde best = 0; 359107ab83eSSimon Glass best_val = abs((fs_ratios[0] * sampling_rate) - priv->aifclk[id]); 360a2d8e0a7SRajeshwari Shinde 361a2d8e0a7SRajeshwari Shinde for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) { 362107ab83eSSimon Glass cur_val = abs(fs_ratios[i] * sampling_rate - priv->aifclk[id]); 363a2d8e0a7SRajeshwari Shinde if (cur_val >= best_val) 364a2d8e0a7SRajeshwari Shinde continue; 365a2d8e0a7SRajeshwari Shinde best = i; 366a2d8e0a7SRajeshwari Shinde best_val = cur_val; 367a2d8e0a7SRajeshwari Shinde } 368a2d8e0a7SRajeshwari Shinde 369a2d8e0a7SRajeshwari Shinde rate_val |= best; 370a2d8e0a7SRajeshwari Shinde 371a2d8e0a7SRajeshwari Shinde /* 372a2d8e0a7SRajeshwari Shinde * We may not get quite the right frequency if using 373a2d8e0a7SRajeshwari Shinde * approximate clocks so look for the closest match that is 374a2d8e0a7SRajeshwari Shinde * higher than the target (we need to ensure that there enough 375a2d8e0a7SRajeshwari Shinde * BCLKs to clock out the samples). 376a2d8e0a7SRajeshwari Shinde */ 377a2d8e0a7SRajeshwari Shinde best = 0; 378a2d8e0a7SRajeshwari Shinde for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { 379107ab83eSSimon Glass cur_val = (priv->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate; 380a2d8e0a7SRajeshwari Shinde if (cur_val < 0) /* BCLK table is sorted */ 381a2d8e0a7SRajeshwari Shinde break; 382a2d8e0a7SRajeshwari Shinde best = i; 383a2d8e0a7SRajeshwari Shinde } 384a2d8e0a7SRajeshwari Shinde 385a2d8e0a7SRajeshwari Shinde if (i == ARRAY_SIZE(bclk_divs)) { 386a2d8e0a7SRajeshwari Shinde debug("%s: Could not get the best matching bclk division\n", 387a2d8e0a7SRajeshwari Shinde __func__); 388a2d8e0a7SRajeshwari Shinde return -1; 389a2d8e0a7SRajeshwari Shinde } 390a2d8e0a7SRajeshwari Shinde 391107ab83eSSimon Glass bclk_rate = priv->aifclk[id] * 10 / bclk_divs[best]; 392a2d8e0a7SRajeshwari Shinde bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT; 393a2d8e0a7SRajeshwari Shinde 394107ab83eSSimon Glass if (wm8994_i2c_read(priv, aif1_reg, ®_data) != 0) { 395a2d8e0a7SRajeshwari Shinde debug("%s: AIF1 register read Failed\n", __func__); 396a2d8e0a7SRajeshwari Shinde return -1; 397a2d8e0a7SRajeshwari Shinde } 398a2d8e0a7SRajeshwari Shinde 399a2d8e0a7SRajeshwari Shinde if ((channels == 1) && ((reg_data & 0x18) == 0x18)) 400a2d8e0a7SRajeshwari Shinde aif2 |= WM8994_AIF1_MONO; 401a2d8e0a7SRajeshwari Shinde 402107ab83eSSimon Glass if (priv->aifclk[id] == 0) { 403a2d8e0a7SRajeshwari Shinde debug("%s:Audio interface clock not set\n", __func__); 404a2d8e0a7SRajeshwari Shinde return -1; 405a2d8e0a7SRajeshwari Shinde } 406a2d8e0a7SRajeshwari Shinde 407107ab83eSSimon Glass ret = wm8994_bic_or(priv, aif1_reg, WM8994_AIF1_WL_MASK, aif1); 408107ab83eSSimon Glass ret |= wm8994_bic_or(priv, aif2_reg, WM8994_AIF1_MONO, aif2); 409107ab83eSSimon Glass ret |= wm8994_bic_or(priv, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, 410107ab83eSSimon Glass bclk); 411107ab83eSSimon Glass ret |= wm8994_bic_or(priv, rate_reg, WM8994_AIF1_SR_MASK | 412a2d8e0a7SRajeshwari Shinde WM8994_AIF1CLK_RATE_MASK, rate_val); 413a2d8e0a7SRajeshwari Shinde 414a2d8e0a7SRajeshwari Shinde debug("rate vale = %x , bclk val= %x\n", rate_val, bclk); 415a2d8e0a7SRajeshwari Shinde 416a2d8e0a7SRajeshwari Shinde if (ret < 0) { 417a2d8e0a7SRajeshwari Shinde debug("%s: codec register access error\n", __func__); 418a2d8e0a7SRajeshwari Shinde return -1; 419a2d8e0a7SRajeshwari Shinde } 420a2d8e0a7SRajeshwari Shinde 421a2d8e0a7SRajeshwari Shinde return 0; 422a2d8e0a7SRajeshwari Shinde } 423a2d8e0a7SRajeshwari Shinde 424a2d8e0a7SRajeshwari Shinde /* 425a2d8e0a7SRajeshwari Shinde * Configures Audio interface Clock 426a2d8e0a7SRajeshwari Shinde * 427107ab83eSSimon Glass * @param priv wm8994 information pointer 428a2d8e0a7SRajeshwari Shinde * @param aif Audio Interface ID 429a2d8e0a7SRajeshwari Shinde * 430a2d8e0a7SRajeshwari Shinde * @return -1 for error and 0 Success. 431a2d8e0a7SRajeshwari Shinde */ 432107ab83eSSimon Glass static int configure_aif_clock(struct wm8994_priv *priv, int aif) 433a2d8e0a7SRajeshwari Shinde { 434a2d8e0a7SRajeshwari Shinde int rate; 435a2d8e0a7SRajeshwari Shinde int reg1 = 0; 436a2d8e0a7SRajeshwari Shinde int offset; 437a2d8e0a7SRajeshwari Shinde int ret; 438a2d8e0a7SRajeshwari Shinde 439a2d8e0a7SRajeshwari Shinde /* AIF(1/0) register adress offset calculated */ 440d981d80dSDani Krishna Mohan if (aif-1) 441a2d8e0a7SRajeshwari Shinde offset = 4; 442a2d8e0a7SRajeshwari Shinde else 443a2d8e0a7SRajeshwari Shinde offset = 0; 444a2d8e0a7SRajeshwari Shinde 445107ab83eSSimon Glass switch (priv->sysclk[aif - 1]) { 446a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_MCLK1: 447a2d8e0a7SRajeshwari Shinde reg1 |= SEL_MCLK1; 448107ab83eSSimon Glass rate = priv->mclk[0]; 449a2d8e0a7SRajeshwari Shinde break; 450a2d8e0a7SRajeshwari Shinde 451a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_MCLK2: 452a2d8e0a7SRajeshwari Shinde reg1 |= SEL_MCLK2; 453107ab83eSSimon Glass rate = priv->mclk[1]; 454a2d8e0a7SRajeshwari Shinde break; 455a2d8e0a7SRajeshwari Shinde 456a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_FLL1: 457a2d8e0a7SRajeshwari Shinde reg1 |= SEL_FLL1; 458107ab83eSSimon Glass rate = priv->fll[0].out; 459a2d8e0a7SRajeshwari Shinde break; 460a2d8e0a7SRajeshwari Shinde 461a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_FLL2: 462a2d8e0a7SRajeshwari Shinde reg1 |= SEL_FLL2; 463107ab83eSSimon Glass rate = priv->fll[1].out; 464a2d8e0a7SRajeshwari Shinde break; 465a2d8e0a7SRajeshwari Shinde 466a2d8e0a7SRajeshwari Shinde default: 467a2d8e0a7SRajeshwari Shinde debug("%s: Invalid input clock selection [%d]\n", 468107ab83eSSimon Glass __func__, priv->sysclk[aif - 1]); 469a2d8e0a7SRajeshwari Shinde return -1; 470a2d8e0a7SRajeshwari Shinde } 471a2d8e0a7SRajeshwari Shinde 472a2d8e0a7SRajeshwari Shinde /* if input clock frequenct is more than 135Mhz then divide */ 473a2d8e0a7SRajeshwari Shinde if (rate >= WM8994_MAX_INPUT_CLK_FREQ) { 474a2d8e0a7SRajeshwari Shinde rate /= 2; 475a2d8e0a7SRajeshwari Shinde reg1 |= WM8994_AIF1CLK_DIV; 476a2d8e0a7SRajeshwari Shinde } 477a2d8e0a7SRajeshwari Shinde 478107ab83eSSimon Glass priv->aifclk[aif - 1] = rate; 479a2d8e0a7SRajeshwari Shinde 480107ab83eSSimon Glass ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_1 + offset, 481a2d8e0a7SRajeshwari Shinde WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV, 482a2d8e0a7SRajeshwari Shinde reg1); 483a2d8e0a7SRajeshwari Shinde 484d981d80dSDani Krishna Mohan if (aif == WM8994_AIF1) 485107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1, 486d981d80dSDani Krishna Mohan WM8994_AIF1DSPCLK_ENA_MASK | WM8994_SYSDSPCLK_ENA_MASK, 487d981d80dSDani Krishna Mohan WM8994_AIF1DSPCLK_ENA | WM8994_SYSDSPCLK_ENA); 488d981d80dSDani Krishna Mohan else if (aif == WM8994_AIF2) 489107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1, 490a2d8e0a7SRajeshwari Shinde WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK | 491a2d8e0a7SRajeshwari Shinde WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC | 492a2d8e0a7SRajeshwari Shinde WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA); 493a2d8e0a7SRajeshwari Shinde 494a2d8e0a7SRajeshwari Shinde if (ret < 0) { 495a2d8e0a7SRajeshwari Shinde debug("%s: codec register access error\n", __func__); 496a2d8e0a7SRajeshwari Shinde return -1; 497a2d8e0a7SRajeshwari Shinde } 498a2d8e0a7SRajeshwari Shinde 499a2d8e0a7SRajeshwari Shinde return 0; 500a2d8e0a7SRajeshwari Shinde } 501a2d8e0a7SRajeshwari Shinde 502a2d8e0a7SRajeshwari Shinde /* 503a2d8e0a7SRajeshwari Shinde * Configures Audio interface for the given frequency 504a2d8e0a7SRajeshwari Shinde * 505107ab83eSSimon Glass * @param priv wm8994 information 506a2d8e0a7SRajeshwari Shinde * @param aif_id Audio Interface 507a2d8e0a7SRajeshwari Shinde * @param clk_id Input Clock ID 508a2d8e0a7SRajeshwari Shinde * @param freq Sampling frequency in Hz 509a2d8e0a7SRajeshwari Shinde * 510a2d8e0a7SRajeshwari Shinde * @return -1 for error and 0 success. 511a2d8e0a7SRajeshwari Shinde */ 512107ab83eSSimon Glass static int wm8994_set_sysclk(struct wm8994_priv *priv, int aif_id, int clk_id, 513107ab83eSSimon Glass unsigned int freq) 514a2d8e0a7SRajeshwari Shinde { 515a2d8e0a7SRajeshwari Shinde int i; 516a2d8e0a7SRajeshwari Shinde int ret = 0; 517a2d8e0a7SRajeshwari Shinde 518107ab83eSSimon Glass priv->sysclk[aif_id - 1] = clk_id; 519a2d8e0a7SRajeshwari Shinde 520a2d8e0a7SRajeshwari Shinde switch (clk_id) { 521a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_MCLK1: 522107ab83eSSimon Glass priv->mclk[0] = freq; 523a2d8e0a7SRajeshwari Shinde if (aif_id == 2) { 524107ab83eSSimon Glass ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_2, 525a2d8e0a7SRajeshwari Shinde WM8994_AIF2DAC_DIV_MASK, 0); 526a2d8e0a7SRajeshwari Shinde } 527a2d8e0a7SRajeshwari Shinde break; 528a2d8e0a7SRajeshwari Shinde 529a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_MCLK2: 530a2d8e0a7SRajeshwari Shinde /* TODO: Set GPIO AF */ 531107ab83eSSimon Glass priv->mclk[1] = freq; 532a2d8e0a7SRajeshwari Shinde break; 533a2d8e0a7SRajeshwari Shinde 534a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_FLL1: 535a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_FLL2: 536a2d8e0a7SRajeshwari Shinde break; 537a2d8e0a7SRajeshwari Shinde 538a2d8e0a7SRajeshwari Shinde case WM8994_SYSCLK_OPCLK: 539a2d8e0a7SRajeshwari Shinde /* 540a2d8e0a7SRajeshwari Shinde * Special case - a division (times 10) is given and 541a2d8e0a7SRajeshwari Shinde * no effect on main clocking. 542a2d8e0a7SRajeshwari Shinde */ 543a2d8e0a7SRajeshwari Shinde if (freq) { 544a2d8e0a7SRajeshwari Shinde for (i = 0; i < ARRAY_SIZE(opclk_divs); i++) 545a2d8e0a7SRajeshwari Shinde if (opclk_divs[i] == freq) 546a2d8e0a7SRajeshwari Shinde break; 547a2d8e0a7SRajeshwari Shinde if (i == ARRAY_SIZE(opclk_divs)) { 548a2d8e0a7SRajeshwari Shinde debug("%s frequency divisor not found\n", 549a2d8e0a7SRajeshwari Shinde __func__); 550a2d8e0a7SRajeshwari Shinde return -1; 551a2d8e0a7SRajeshwari Shinde } 552107ab83eSSimon Glass ret = wm8994_bic_or(priv, WM8994_CLOCKING_2, 553a2d8e0a7SRajeshwari Shinde WM8994_OPCLK_DIV_MASK, i); 554107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2, 555107ab83eSSimon Glass WM8994_OPCLK_ENA, 556107ab83eSSimon Glass WM8994_OPCLK_ENA); 557a2d8e0a7SRajeshwari Shinde } else { 558107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2, 559a2d8e0a7SRajeshwari Shinde WM8994_OPCLK_ENA, 0); 560a2d8e0a7SRajeshwari Shinde } 561a2d8e0a7SRajeshwari Shinde 562a2d8e0a7SRajeshwari Shinde default: 563a2d8e0a7SRajeshwari Shinde debug("%s Invalid input clock selection [%d]\n", 564a2d8e0a7SRajeshwari Shinde __func__, clk_id); 565a2d8e0a7SRajeshwari Shinde return -1; 566a2d8e0a7SRajeshwari Shinde } 567a2d8e0a7SRajeshwari Shinde 568107ab83eSSimon Glass ret |= configure_aif_clock(priv, aif_id); 569a2d8e0a7SRajeshwari Shinde 570a2d8e0a7SRajeshwari Shinde if (ret < 0) { 571a2d8e0a7SRajeshwari Shinde debug("%s: codec register access error\n", __func__); 572a2d8e0a7SRajeshwari Shinde return -1; 573a2d8e0a7SRajeshwari Shinde } 574a2d8e0a7SRajeshwari Shinde 575a2d8e0a7SRajeshwari Shinde return 0; 576a2d8e0a7SRajeshwari Shinde } 577a2d8e0a7SRajeshwari Shinde 578a2d8e0a7SRajeshwari Shinde /* 579a2d8e0a7SRajeshwari Shinde * Initializes Volume for AIF2 to HP path 580a2d8e0a7SRajeshwari Shinde * 581107ab83eSSimon Glass * @param priv wm8994 information 582a2d8e0a7SRajeshwari Shinde * @returns -1 for error and 0 Success. 583a2d8e0a7SRajeshwari Shinde * 584a2d8e0a7SRajeshwari Shinde */ 585107ab83eSSimon Glass static int wm8994_init_volume_aif2_dac1(struct wm8994_priv *priv) 586a2d8e0a7SRajeshwari Shinde { 587a2d8e0a7SRajeshwari Shinde int ret; 588a2d8e0a7SRajeshwari Shinde 589a2d8e0a7SRajeshwari Shinde /* Unmute AIF2DAC */ 590107ab83eSSimon Glass ret = wm8994_bic_or(priv, WM8994_AIF2_DAC_FILTERS_1, 591a2d8e0a7SRajeshwari Shinde WM8994_AIF2DAC_MUTE_MASK, 0); 592a2d8e0a7SRajeshwari Shinde 593a2d8e0a7SRajeshwari Shinde 594107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_LEFT_VOLUME, 595a2d8e0a7SRajeshwari Shinde WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK, 596a2d8e0a7SRajeshwari Shinde WM8994_AIF2DAC_VU | 0xff); 597a2d8e0a7SRajeshwari Shinde 598107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_RIGHT_VOLUME, 599a2d8e0a7SRajeshwari Shinde WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK, 600a2d8e0a7SRajeshwari Shinde WM8994_AIF2DAC_VU | 0xff); 601a2d8e0a7SRajeshwari Shinde 602a2d8e0a7SRajeshwari Shinde 603107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME, 604a2d8e0a7SRajeshwari Shinde WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK | 605a2d8e0a7SRajeshwari Shinde WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0); 606a2d8e0a7SRajeshwari Shinde 607107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME, 608a2d8e0a7SRajeshwari Shinde WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK | 609a2d8e0a7SRajeshwari Shinde WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0); 610a2d8e0a7SRajeshwari Shinde /* Head Phone Volume */ 611107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D); 612107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D); 613a2d8e0a7SRajeshwari Shinde 614a2d8e0a7SRajeshwari Shinde if (ret < 0) { 615a2d8e0a7SRajeshwari Shinde debug("%s: codec register access error\n", __func__); 616a2d8e0a7SRajeshwari Shinde return -1; 617a2d8e0a7SRajeshwari Shinde } 618a2d8e0a7SRajeshwari Shinde 619a2d8e0a7SRajeshwari Shinde return 0; 620a2d8e0a7SRajeshwari Shinde } 621a2d8e0a7SRajeshwari Shinde 622a2d8e0a7SRajeshwari Shinde /* 623d981d80dSDani Krishna Mohan * Initializes Volume for AIF1 to HP path 624d981d80dSDani Krishna Mohan * 625107ab83eSSimon Glass * @param priv wm8994 information 626d981d80dSDani Krishna Mohan * @returns -1 for error and 0 Success. 627d981d80dSDani Krishna Mohan * 628d981d80dSDani Krishna Mohan */ 629107ab83eSSimon Glass static int wm8994_init_volume_aif1_dac1(struct wm8994_priv *priv) 630d981d80dSDani Krishna Mohan { 631d981d80dSDani Krishna Mohan int ret = 0; 632d981d80dSDani Krishna Mohan 633d981d80dSDani Krishna Mohan /* Unmute AIF1DAC */ 634107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_AIF1_DAC_FILTERS_1, 0x0000); 635d981d80dSDani Krishna Mohan 636107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME, 637d981d80dSDani Krishna Mohan WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK | 638d981d80dSDani Krishna Mohan WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0); 639d981d80dSDani Krishna Mohan 640107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME, 641d981d80dSDani Krishna Mohan WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK | 642d981d80dSDani Krishna Mohan WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0); 643d981d80dSDani Krishna Mohan /* Head Phone Volume */ 644107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D); 645107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D); 646d981d80dSDani Krishna Mohan 647d981d80dSDani Krishna Mohan if (ret < 0) { 648d981d80dSDani Krishna Mohan debug("%s: codec register access error\n", __func__); 649d981d80dSDani Krishna Mohan return -1; 650d981d80dSDani Krishna Mohan } 651d981d80dSDani Krishna Mohan 652d981d80dSDani Krishna Mohan return 0; 653d981d80dSDani Krishna Mohan } 654d981d80dSDani Krishna Mohan 655d981d80dSDani Krishna Mohan /* 656a2d8e0a7SRajeshwari Shinde * Intialise wm8994 codec device 657a2d8e0a7SRajeshwari Shinde * 658107ab83eSSimon Glass * @param priv wm8994 information 659a2d8e0a7SRajeshwari Shinde * 660a2d8e0a7SRajeshwari Shinde * @returns -1 for error and 0 Success. 661a2d8e0a7SRajeshwari Shinde */ 662107ab83eSSimon Glass static int wm8994_device_init(struct wm8994_priv *priv, 663d981d80dSDani Krishna Mohan enum en_audio_interface aif_id) 664a2d8e0a7SRajeshwari Shinde { 665a2d8e0a7SRajeshwari Shinde const char *devname; 666a2d8e0a7SRajeshwari Shinde unsigned short reg_data; 667a2d8e0a7SRajeshwari Shinde int ret; 668a2d8e0a7SRajeshwari Shinde 669107ab83eSSimon Glass wm8994_i2c_write(priv, WM8994_SOFTWARE_RESET, WM8994_SW_RESET); 670a2d8e0a7SRajeshwari Shinde 671107ab83eSSimon Glass ret = wm8994_i2c_read(priv, WM8994_SOFTWARE_RESET, ®_data); 672a2d8e0a7SRajeshwari Shinde if (ret < 0) { 673a2d8e0a7SRajeshwari Shinde debug("Failed to read ID register\n"); 674a2d8e0a7SRajeshwari Shinde goto err; 675a2d8e0a7SRajeshwari Shinde } 676a2d8e0a7SRajeshwari Shinde 677a2d8e0a7SRajeshwari Shinde if (reg_data == WM8994_ID) { 678a2d8e0a7SRajeshwari Shinde devname = "WM8994"; 679107ab83eSSimon Glass debug("Device registered as type %d\n", priv->type); 680107ab83eSSimon Glass priv->type = WM8994; 681a2d8e0a7SRajeshwari Shinde } else { 682a2d8e0a7SRajeshwari Shinde debug("Device is not a WM8994, ID is %x\n", ret); 683a2d8e0a7SRajeshwari Shinde ret = -1; 684a2d8e0a7SRajeshwari Shinde goto err; 685a2d8e0a7SRajeshwari Shinde } 686a2d8e0a7SRajeshwari Shinde 687107ab83eSSimon Glass ret = wm8994_i2c_read(priv, WM8994_CHIP_REVISION, ®_data); 688a2d8e0a7SRajeshwari Shinde if (ret < 0) { 689a2d8e0a7SRajeshwari Shinde debug("Failed to read revision register: %d\n", ret); 690a2d8e0a7SRajeshwari Shinde goto err; 691a2d8e0a7SRajeshwari Shinde } 692107ab83eSSimon Glass priv->revision = reg_data; 693107ab83eSSimon Glass debug("%s revision %c\n", devname, 'A' + priv->revision); 694a2d8e0a7SRajeshwari Shinde 695a2d8e0a7SRajeshwari Shinde /* VMID Selection */ 696107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1, 697a2d8e0a7SRajeshwari Shinde WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3); 698a2d8e0a7SRajeshwari Shinde 699a2d8e0a7SRajeshwari Shinde /* Charge Pump Enable */ 700107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK, 701a2d8e0a7SRajeshwari Shinde WM8994_CP_ENA); 702a2d8e0a7SRajeshwari Shinde 703a2d8e0a7SRajeshwari Shinde /* Head Phone Power Enable */ 704107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1, 705a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA); 706a2d8e0a7SRajeshwari Shinde 707107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1, 708a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA); 709a2d8e0a7SRajeshwari Shinde 710d981d80dSDani Krishna Mohan if (aif_id == WM8994_AIF1) { 711107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_2, 712d981d80dSDani Krishna Mohan WM8994_TSHUT_ENA | WM8994_MIXINL_ENA | 713d981d80dSDani Krishna Mohan WM8994_MIXINR_ENA | WM8994_IN2L_ENA | 714d981d80dSDani Krishna Mohan WM8994_IN2R_ENA); 715d981d80dSDani Krishna Mohan 716107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_4, 717d981d80dSDani Krishna Mohan WM8994_ADCL_ENA | WM8994_ADCR_ENA | 718d981d80dSDani Krishna Mohan WM8994_AIF1ADC1R_ENA | 719d981d80dSDani Krishna Mohan WM8994_AIF1ADC1L_ENA); 720d981d80dSDani Krishna Mohan 721d981d80dSDani Krishna Mohan /* Power enable for AIF1 and DAC1 */ 722107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_5, 723d981d80dSDani Krishna Mohan WM8994_AIF1DACL_ENA | 724d981d80dSDani Krishna Mohan WM8994_AIF1DACR_ENA | 725d981d80dSDani Krishna Mohan WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); 726d981d80dSDani Krishna Mohan } else if (aif_id == WM8994_AIF2) { 727a2d8e0a7SRajeshwari Shinde /* Power enable for AIF2 and DAC1 */ 728107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_5, 729a2d8e0a7SRajeshwari Shinde WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK | 730a2d8e0a7SRajeshwari Shinde WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK, 731d981d80dSDani Krishna Mohan WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | 732d981d80dSDani Krishna Mohan WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); 733d981d80dSDani Krishna Mohan } 734a2d8e0a7SRajeshwari Shinde /* Head Phone Initialisation */ 735107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1, 736a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK, 737a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY); 738a2d8e0a7SRajeshwari Shinde 739107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_DC_SERVO_1, 740a2d8e0a7SRajeshwari Shinde WM8994_DCS_ENA_CHAN_0_MASK | 741a2d8e0a7SRajeshwari Shinde WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 | 742a2d8e0a7SRajeshwari Shinde WM8994_DCS_ENA_CHAN_1); 743a2d8e0a7SRajeshwari Shinde 744107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1, 745a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1L_DLY_MASK | 746a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK | 747a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1R_OUTP_MASK | 748a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1L_RMV_SHORT_MASK | 749a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1R_RMV_SHORT_MASK, WM8994_HPOUT1L_DLY | 750a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1R_DLY | WM8994_HPOUT1L_OUTP | 751a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1R_OUTP | WM8994_HPOUT1L_RMV_SHORT | 752a2d8e0a7SRajeshwari Shinde WM8994_HPOUT1R_RMV_SHORT); 753a2d8e0a7SRajeshwari Shinde 754a2d8e0a7SRajeshwari Shinde /* MIXER Config DAC1 to HP */ 755107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_1, 756107ab83eSSimon Glass WM8994_DAC1L_TO_HPOUT1L_MASK, 757107ab83eSSimon Glass WM8994_DAC1L_TO_HPOUT1L); 758a2d8e0a7SRajeshwari Shinde 759107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_2, 760107ab83eSSimon Glass WM8994_DAC1R_TO_HPOUT1R_MASK, 761107ab83eSSimon Glass WM8994_DAC1R_TO_HPOUT1R); 762a2d8e0a7SRajeshwari Shinde 763d981d80dSDani Krishna Mohan if (aif_id == WM8994_AIF1) { 764d981d80dSDani Krishna Mohan /* Routing AIF1 to DAC1 */ 765107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_DAC1_LEFT_MIXER_ROUTING, 766d981d80dSDani Krishna Mohan WM8994_AIF1DAC1L_TO_DAC1L); 767d981d80dSDani Krishna Mohan 768107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING, 769d981d80dSDani Krishna Mohan WM8994_AIF1DAC1R_TO_DAC1R); 770d981d80dSDani Krishna Mohan 771d981d80dSDani Krishna Mohan /* GPIO Settings for AIF1 */ 772107ab83eSSimon Glass ret |= wm8994_i2c_write(priv, WM8994_GPIO_1, 773107ab83eSSimon Glass WM8994_GPIO_DIR_OUTPUT | 774107ab83eSSimon Glass WM8994_GPIO_FUNCTION_I2S_CLK | 775107ab83eSSimon Glass WM8994_GPIO_INPUT_DEBOUNCE); 776d981d80dSDani Krishna Mohan 777107ab83eSSimon Glass ret |= wm8994_init_volume_aif1_dac1(priv); 778d981d80dSDani Krishna Mohan } else if (aif_id == WM8994_AIF2) { 779a2d8e0a7SRajeshwari Shinde /* Routing AIF2 to DAC1 */ 780107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_MIXER_ROUTING, 781a2d8e0a7SRajeshwari Shinde WM8994_AIF2DACL_TO_DAC1L_MASK, 782a2d8e0a7SRajeshwari Shinde WM8994_AIF2DACL_TO_DAC1L); 783a2d8e0a7SRajeshwari Shinde 784107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING, 785a2d8e0a7SRajeshwari Shinde WM8994_AIF2DACR_TO_DAC1R_MASK, 786a2d8e0a7SRajeshwari Shinde WM8994_AIF2DACR_TO_DAC1R); 787a2d8e0a7SRajeshwari Shinde 788a2d8e0a7SRajeshwari Shinde /* GPIO Settings for AIF2 */ 789a2d8e0a7SRajeshwari Shinde /* B CLK */ 790107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_GPIO_3, WM8994_GPIO_DIR_MASK | 791a2d8e0a7SRajeshwari Shinde WM8994_GPIO_FUNCTION_MASK, 792d981d80dSDani Krishna Mohan WM8994_GPIO_DIR_OUTPUT); 793a2d8e0a7SRajeshwari Shinde 794a2d8e0a7SRajeshwari Shinde /* LR CLK */ 795107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_GPIO_4, WM8994_GPIO_DIR_MASK | 796a2d8e0a7SRajeshwari Shinde WM8994_GPIO_FUNCTION_MASK, 797d981d80dSDani Krishna Mohan WM8994_GPIO_DIR_OUTPUT); 798a2d8e0a7SRajeshwari Shinde 799a2d8e0a7SRajeshwari Shinde /* DATA */ 800107ab83eSSimon Glass ret |= wm8994_bic_or(priv, WM8994_GPIO_5, WM8994_GPIO_DIR_MASK | 801a2d8e0a7SRajeshwari Shinde WM8994_GPIO_FUNCTION_MASK, 802d981d80dSDani Krishna Mohan WM8994_GPIO_DIR_OUTPUT); 803a2d8e0a7SRajeshwari Shinde 804107ab83eSSimon Glass ret |= wm8994_init_volume_aif2_dac1(priv); 805d981d80dSDani Krishna Mohan } 806d981d80dSDani Krishna Mohan 807a2d8e0a7SRajeshwari Shinde if (ret < 0) 808a2d8e0a7SRajeshwari Shinde goto err; 809a2d8e0a7SRajeshwari Shinde 810a2d8e0a7SRajeshwari Shinde debug("%s: Codec chip init ok\n", __func__); 811a2d8e0a7SRajeshwari Shinde return 0; 812a2d8e0a7SRajeshwari Shinde err: 813a2d8e0a7SRajeshwari Shinde debug("%s: Codec chip init error\n", __func__); 814a2d8e0a7SRajeshwari Shinde return -1; 815a2d8e0a7SRajeshwari Shinde } 816a2d8e0a7SRajeshwari Shinde 8176647c7acSRajeshwari Shinde /* 8186647c7acSRajeshwari Shinde * Gets fdt values for wm8994 config parameters 8196647c7acSRajeshwari Shinde * 8206647c7acSRajeshwari Shinde * @param pcodec_info codec information structure 8216647c7acSRajeshwari Shinde * @param blob FDT blob 8226647c7acSRajeshwari Shinde * @return int value, 0 for success 8236647c7acSRajeshwari Shinde */ 8246647c7acSRajeshwari Shinde static int get_codec_values(struct sound_codec_info *pcodec_info, 8256647c7acSRajeshwari Shinde const void *blob) 8266647c7acSRajeshwari Shinde { 8276647c7acSRajeshwari Shinde int error = 0; 8286647c7acSRajeshwari Shinde enum fdt_compat_id compat; 8296647c7acSRajeshwari Shinde int node; 8306647c7acSRajeshwari Shinde int parent; 8316647c7acSRajeshwari Shinde 8326647c7acSRajeshwari Shinde /* Get the node from FDT for codec */ 8336647c7acSRajeshwari Shinde node = fdtdec_next_compatible(blob, 0, COMPAT_WOLFSON_WM8994_CODEC); 8346647c7acSRajeshwari Shinde if (node <= 0) { 8356647c7acSRajeshwari Shinde debug("EXYNOS_SOUND: No node for codec in device tree\n"); 8366647c7acSRajeshwari Shinde debug("node = %d\n", node); 8376647c7acSRajeshwari Shinde return -1; 8386647c7acSRajeshwari Shinde } 8396647c7acSRajeshwari Shinde 8406647c7acSRajeshwari Shinde parent = fdt_parent_offset(blob, node); 8416647c7acSRajeshwari Shinde if (parent < 0) { 8426647c7acSRajeshwari Shinde debug("%s: Cannot find node parent\n", __func__); 8436647c7acSRajeshwari Shinde return -1; 8446647c7acSRajeshwari Shinde } 8456647c7acSRajeshwari Shinde 8466647c7acSRajeshwari Shinde compat = fdtdec_lookup(blob, parent); 8476647c7acSRajeshwari Shinde switch (compat) { 8486647c7acSRajeshwari Shinde case COMPAT_SAMSUNG_S3C2440_I2C: 8496647c7acSRajeshwari Shinde pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent); 8506647c7acSRajeshwari Shinde error |= pcodec_info->i2c_bus; 8516647c7acSRajeshwari Shinde debug("i2c bus = %d\n", pcodec_info->i2c_bus); 8526647c7acSRajeshwari Shinde pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node, 8536647c7acSRajeshwari Shinde "reg", 0); 8546647c7acSRajeshwari Shinde error |= pcodec_info->i2c_dev_addr; 8556647c7acSRajeshwari Shinde debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); 8566647c7acSRajeshwari Shinde break; 8576647c7acSRajeshwari Shinde default: 8586647c7acSRajeshwari Shinde debug("%s: Unknown compat id %d\n", __func__, compat); 8596647c7acSRajeshwari Shinde return -1; 8606647c7acSRajeshwari Shinde } 8616647c7acSRajeshwari Shinde 8626647c7acSRajeshwari Shinde if (error == -1) { 8636647c7acSRajeshwari Shinde debug("fail to get wm8994 codec node properties\n"); 8646647c7acSRajeshwari Shinde return -1; 8656647c7acSRajeshwari Shinde } 8666647c7acSRajeshwari Shinde 8676647c7acSRajeshwari Shinde return 0; 8686647c7acSRajeshwari Shinde } 8696647c7acSRajeshwari Shinde 870*54e67e27SSimon Glass static int _wm8994_init(struct wm8994_priv *priv, 871*54e67e27SSimon Glass enum en_audio_interface aif_id, int sampling_rate, 872*54e67e27SSimon Glass int mclk_freq, int bits_per_sample, 873*54e67e27SSimon Glass unsigned int channels) 874*54e67e27SSimon Glass { 875*54e67e27SSimon Glass int ret; 876*54e67e27SSimon Glass 877*54e67e27SSimon Glass ret = wm8994_device_init(priv, aif_id); 878*54e67e27SSimon Glass if (ret < 0) { 879*54e67e27SSimon Glass debug("%s: wm8994 codec chip init failed\n", __func__); 880*54e67e27SSimon Glass return ret; 881*54e67e27SSimon Glass } 882*54e67e27SSimon Glass 883*54e67e27SSimon Glass ret = wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq); 884*54e67e27SSimon Glass if (ret < 0) { 885*54e67e27SSimon Glass debug("%s: wm8994 codec set sys clock failed\n", __func__); 886*54e67e27SSimon Glass return ret; 887*54e67e27SSimon Glass } 888*54e67e27SSimon Glass 889*54e67e27SSimon Glass ret = wm8994_hw_params(priv, aif_id, sampling_rate, bits_per_sample, 890*54e67e27SSimon Glass channels); 891*54e67e27SSimon Glass 892*54e67e27SSimon Glass if (ret == 0) { 893*54e67e27SSimon Glass ret = wm8994_set_fmt(priv, aif_id, SND_SOC_DAIFMT_I2S | 894*54e67e27SSimon Glass SND_SOC_DAIFMT_NB_NF | 895*54e67e27SSimon Glass SND_SOC_DAIFMT_CBS_CFS); 896*54e67e27SSimon Glass } 897*54e67e27SSimon Glass 898*54e67e27SSimon Glass return ret; 899*54e67e27SSimon Glass } 900*54e67e27SSimon Glass 901d981d80dSDani Krishna Mohan /* WM8994 Device Initialisation */ 9026647c7acSRajeshwari Shinde int wm8994_init(const void *blob, enum en_audio_interface aif_id, 903107ab83eSSimon Glass int sampling_rate, int mclk_freq, int bits_per_sample, 904107ab83eSSimon Glass unsigned int channels) 905a2d8e0a7SRajeshwari Shinde { 9066647c7acSRajeshwari Shinde struct sound_codec_info *pcodec_info = &g_codec_info; 9076647c7acSRajeshwari Shinde 9086647c7acSRajeshwari Shinde /* Get the codec Values */ 9096647c7acSRajeshwari Shinde if (get_codec_values(pcodec_info, blob) < 0) { 9106647c7acSRajeshwari Shinde debug("FDT Codec values failed\n"); 9116647c7acSRajeshwari Shinde return -1; 9126647c7acSRajeshwari Shinde } 913a2d8e0a7SRajeshwari Shinde 914a2d8e0a7SRajeshwari Shinde /* shift the device address by 1 for 7 bit addressing */ 915a2d8e0a7SRajeshwari Shinde g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr; 916a2d8e0a7SRajeshwari Shinde wm8994_i2c_init(pcodec_info->i2c_bus); 917a2d8e0a7SRajeshwari Shinde 918*54e67e27SSimon Glass return _wm8994_init(&g_wm8994_info, aif_id, sampling_rate, mclk_freq, 919a2d8e0a7SRajeshwari Shinde bits_per_sample, channels); 920a2d8e0a7SRajeshwari Shinde } 921