| /* |
| * max98095.c -- MAX98095 ALSA SoC Audio driver |
| * |
| * Copyright 2013 Google Inc. All rights reserved. |
| * Copyright 2011 Maxim Integrated Products |
| * |
| * Modified for uboot by R. Chandrasekar (rcsekar@samsung.com) |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #include <stdio.h> |
| |
| #include "base/algorithm.h" |
| #include "base/xalloc.h" |
| #include "drivers/bus/i2c/i2c.h" |
| #include "drivers/sound/max98095.h" |
| |
| static int max98095_i2c_write(Max98095Codec *codec, uint8_t reg, uint8_t data) |
| { |
| return i2c_write8(codec->i2c, codec->chip, reg, data); |
| } |
| |
| static int max98095_i2c_read(Max98095Codec *codec, uint8_t reg, uint8_t *data) |
| { |
| return i2c_read8(codec->i2c, codec->chip, reg, data); |
| } |
| |
| static int max98095_update_bits(Max98095Codec *codec, uint8_t reg, |
| uint8_t mask, uint8_t value) |
| { |
| uint8_t old; |
| if (max98095_i2c_read(codec, reg, &old)) |
| return 1; |
| uint8_t new = (old & ~mask) | (value & mask); |
| if (old != new && max98095_i2c_write(codec, reg, new)) |
| return 1; |
| |
| return 0; |
| } |
| |
| static int max98095_hw_params(Max98095Codec *codec) |
| { |
| switch (codec->bits_per_sample) { |
| case 16: |
| if (max98095_update_bits(codec, M98095_02A_DAI1_FORMAT, |
| M98095_DAI_WS, 0)) |
| return 1; |
| if (max98095_update_bits(codec, M98095_034_DAI2_FORMAT, |
| M98095_DAI_WS, 0)) |
| return 1; |
| break; |
| case 24: |
| if (max98095_update_bits(codec, M98095_02A_DAI1_FORMAT, |
| M98095_DAI_WS, M98095_DAI_WS)) |
| return 1; |
| if (max98095_update_bits(codec, M98095_034_DAI2_FORMAT, |
| M98095_DAI_WS, M98095_DAI_WS)) |
| return 1; |
| break; |
| default: |
| printf("%s: Illegal bits per sample %d.\n", __func__, |
| codec->bits_per_sample); |
| return 1; |
| } |
| |
| // Index 0 is reserved. |
| static const int rate_table[] = { |
| 0, 8000, 11025, 16000, 22050, 24000, |
| 32000, 44100, 48000, 88200, 96000 |
| }; |
| static const int table_size = ARRAY_SIZE(rate_table); |
| |
| uint8_t index = table_size; |
| for (int i = 0; i < table_size; i++) { |
| if (rate_table[i] >= codec->sample_rate) { |
| index = i; |
| break; |
| } |
| } |
| if (index == table_size) { |
| printf("%s: Failed to set sample rate %d.\n", __func__, |
| codec->sample_rate); |
| return 1; |
| } |
| |
| if (max98095_update_bits(codec, M98095_027_DAI1_CLKMODE, |
| M98095_CLKMODE_MASK, index)) |
| return 1; |
| |
| if (max98095_update_bits(codec, M98095_031_DAI2_CLKMODE, |
| M98095_CLKMODE_MASK, index)) |
| return 1; |
| |
| /* Update sample rate mode */ |
| int rate = (codec->sample_rate < 50000) ? 0 : M98095_DAI_DHF; |
| |
| if (max98095_update_bits(codec, M98095_02E_DAI1_FILTERS, |
| M98095_DAI_DHF, rate)) |
| return 1; |
| |
| if (max98095_update_bits(codec, M98095_038_DAI2_FILTERS, |
| M98095_DAI_DHF, rate)) |
| return 1; |
| |
| return 0; |
| } |
| |
| // Configures audio interface system clock for the selected frequency. |
| static int max98095_set_sysclk(Max98095Codec *codec) |
| { |
| int freq = codec->lr_frame_size * codec->sample_rate; |
| uint8_t mclksel = (codec->master_clock == 2) ? 1 : 0; |
| |
| /* |
| * Setup clocks for slave mode, and using the PLL |
| * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) |
| * 0x02 (when master clk is 20MHz to 40MHz).. |
| * 0x03 (when master clk is 40MHz to 60MHz).. |
| */ |
| if (freq >= 10 * MHz && freq < 20 * MHz) { |
| mclksel |= M98095_PSCLK_DIV1; |
| } else if (freq >= 20 * MHz && freq < 40 * MHz) { |
| mclksel |= M98095_PSCLK_DIV2; |
| } else if (freq >= 40 * MHz && freq < 60 * MHz) { |
| mclksel |= M98095_PSCLK_DIV4; |
| } else { |
| printf("%s: Invalid master clock frequency\n", __func__); |
| return 1; |
| } |
| |
| if (max98095_i2c_write(codec, M98095_026_SYS_CLK, mclksel)) |
| return 1; |
| |
| printf("%s: Clock at %uHz on MCLK%d\n", __func__, freq, |
| codec->master_clock); |
| |
| return 0; |
| } |
| |
| // Sets Max98095 I2S format. |
| static int max98095_set_fmt(Max98095Codec *codec) |
| { |
| // Slave mode PLL. |
| if (max98095_i2c_write(codec, M98095_028_DAI1_CLKCFG_HI, 0x80) || |
| max98095_i2c_write(codec, M98095_029_DAI1_CLKCFG_LO, 0x00)) |
| return 1; |
| |
| if (max98095_update_bits(codec, M98095_02A_DAI1_FORMAT, |
| M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI | |
| M98095_DAI_WCI, M98095_DAI_DLY)) |
| return 1; |
| |
| if (max98095_i2c_write(codec, M98095_02B_DAI1_CLOCK, M98095_DAI_BSEL64)) |
| return 1; |
| |
| if (max98095_i2c_write(codec, M98095_032_DAI2_CLKCFG_HI, 0x80) || |
| max98095_i2c_write(codec, M98095_033_DAI2_CLKCFG_LO, 0x00)) |
| return 1; |
| |
| if (max98095_update_bits(codec, M98095_034_DAI2_FORMAT, |
| M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI | |
| M98095_DAI_WCI, M98095_DAI_DLY)) |
| return 1; |
| |
| if (max98095_i2c_write(codec, M98095_035_DAI2_CLOCK, M98095_DAI_BSEL64)) |
| return 1; |
| |
| return 0; |
| } |
| |
| // Resets the audio codec. |
| static int max98095_reset(Max98095Codec *codec) |
| { |
| // Gracefully reset the DSP core and the codec hardware in a proper |
| // sequence. |
| if (max98095_i2c_write(codec, M98095_00F_HOST_CFG, 0) || |
| max98095_i2c_write(codec, M98095_097_PWR_SYS, 0)) |
| return 1; |
| |
| // Reset to hardware default for registers, as there is not a soft |
| // reset hardware control register. |
| for (int i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) |
| if (max98095_i2c_write(codec, i, 0)) |
| return 1; |
| |
| return 0; |
| } |
| |
| // Intialize max98095 codec device. |
| static int max98095_device_init(Max98095Codec *codec) |
| { |
| // Reset the codec, the DSP core, and disable all interrupts. |
| if (max98095_reset(codec)) |
| return 1; |
| |
| uint8_t id; |
| if (max98095_i2c_read(codec, M98095_0FF_REV_ID, &id)) |
| return 1; |
| printf("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A'); |
| |
| int res = 0; |
| res |= max98095_i2c_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); |
| |
| // Initialize registers to hardware default configuring audio |
| // interface 1 and 2 to DAC. |
| res |= max98095_i2c_write(codec, M98095_048_MIX_DAC_LR, |
| M98095_DAI1L_TO_DACL | M98095_DAI1R_TO_DACR | |
| M98095_DAI2M_TO_DACL | M98095_DAI2M_TO_DACR); |
| |
| res |= max98095_i2c_write(codec, M98095_092_PWR_EN_OUT, |
| M98095_SPK_SPREADSPECTRUM); |
| res |= max98095_i2c_write(codec, M98095_045_CFG_DSP, M98095_DSPNORMAL); |
| res |= max98095_i2c_write(codec, M98095_04E_CFG_HP, M98095_HPNORMAL); |
| |
| res |= max98095_i2c_write(codec, M98095_02C_DAI1_IOCFG, |
| M98095_S1NORMAL | M98095_SDATA); |
| |
| res |= max98095_i2c_write(codec, M98095_036_DAI2_IOCFG, |
| M98095_S2NORMAL | M98095_SDATA); |
| |
| res |= max98095_i2c_write(codec, M98095_040_DAI3_IOCFG, |
| M98095_S3NORMAL | M98095_SDATA); |
| |
| // Take the codec out of the shut down. |
| res |= max98095_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN, |
| M98095_SHDNRUN); |
| // Route DACL and DACR output to HO and speakers. |
| res |= max98095_i2c_write(codec, M98095_050_MIX_SPK_LEFT, 0x01); // DACL |
| res |= max98095_i2c_write(codec, M98095_051_MIX_SPK_RIGHT, 0x01);// DACR |
| res |= max98095_i2c_write(codec, M98095_04C_MIX_HP_LEFT, 0x01); // DACL |
| res |= max98095_i2c_write(codec, M98095_04D_MIX_HP_RIGHT, 0x01); // DACR |
| |
| // Power enable. |
| res |= max98095_i2c_write(codec, M98095_091_PWR_EN_OUT, 0xF3); |
| |
| // Set volume. |
| res |= max98095_i2c_write(codec, M98095_064_LVL_HP_L, 15); |
| res |= max98095_i2c_write(codec, M98095_065_LVL_HP_R, 15); |
| res |= max98095_i2c_write(codec, M98095_067_LVL_SPK_L, 16); |
| res |= max98095_i2c_write(codec, M98095_068_LVL_SPK_R, 16); |
| |
| // Enable DAIs. |
| res |= max98095_i2c_write(codec, M98095_093_BIAS_CTRL, 0x30); |
| res |= max98095_i2c_write(codec, M98095_096_PWR_DAC_CK, 0x07); |
| |
| return res; |
| } |
| |
| static int max98095_enable(SoundRouteComponentOps *me) |
| { |
| Max98095Codec *codec = container_of(me, Max98095Codec, component.ops); |
| |
| return max98095_device_init(codec) || max98095_set_sysclk(codec) || |
| max98095_hw_params(codec) || max98095_set_fmt(codec); |
| } |
| |
| Max98095Codec *new_max98095_codec(I2cOps *i2c, uint8_t chip, |
| int bits_per_sample, int sample_rate, |
| int lr_frame_size, uint8_t master_clock) |
| { |
| Max98095Codec *codec = xzalloc(sizeof(*codec)); |
| |
| codec->component.ops.enable = &max98095_enable; |
| |
| codec->i2c = i2c; |
| codec->chip = chip; |
| |
| codec->bits_per_sample = bits_per_sample; |
| codec->sample_rate = sample_rate; |
| codec->lr_frame_size = lr_frame_size; |
| |
| codec->master_clock = master_clock; |
| return codec; |
| } |