| /* |
| * maxim_codec.c -- MAXIM CODEC Common driver |
| * |
| * Copyright 2011 Maxim Integrated Products |
| * |
| * 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 <asm/io.h> |
| #include <common.h> |
| #if !defined(CONFIG_TEGRA) |
| #include <asm/arch/clk.h> |
| #include <asm/arch/cpu.h> |
| #include <asm/arch/power.h> |
| #endif |
| #include <asm/gpio.h> |
| #include <div64.h> |
| #include <fdtdec.h> |
| #include <i2c.h> |
| #include <sound.h> |
| #include "i2s.h" |
| #include "maxim_codec.h" |
| #include "max98095.h" |
| #include "max98090.h" |
| |
| struct sound_codec_info g_codec_info; |
| struct maxim_codec_priv g_maxim_codec_info; |
| static unsigned int g_maxim_codec_i2c_dev_addr; |
| |
| /* |
| * Writes value to a device register through i2c |
| * |
| * @param reg reg number to be write |
| * @param data data to be writen to the above registor |
| * |
| * @return int value 1 for change, 0 for no change or negative error code. |
| */ |
| int maxim_codec_i2c_write(unsigned int reg, unsigned char data) |
| { |
| debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n", |
| __func__, reg, data); |
| |
| return i2c_write(g_maxim_codec_i2c_dev_addr, reg, 1, &data, 1); |
| } |
| |
| /* |
| * Read a value from a device register through i2c |
| * |
| * @param reg reg number to be read |
| * @param data address of read data to be stored |
| * |
| * @return int value 0 for success, -1 in case of error. |
| */ |
| unsigned int maxim_codec_i2c_read(unsigned int reg, unsigned char *data) |
| { |
| int ret; |
| |
| ret = i2c_read(g_maxim_codec_i2c_dev_addr, reg, 1, data, 1); |
| if (ret != 0) { |
| debug("%s: Error while reading register %#04x\n", |
| __func__, reg); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * update device register bits through i2c |
| * |
| * @param reg codec register |
| * @param mask register mask |
| * @param value new value |
| * |
| * @return int value 0 for success, non-zero error code. |
| */ |
| int maxim_codec_update_bits(unsigned int reg, unsigned char mask, |
| unsigned char value) |
| { |
| int change, ret = 0; |
| unsigned char old, new; |
| |
| if (maxim_codec_i2c_read(reg, &old) != 0) |
| return -1; |
| new = (old & ~mask) | (value & mask); |
| change = (old != new) ? 1 : 0; |
| if (change) |
| ret = maxim_codec_i2c_write(reg, new); |
| if (ret < 0) |
| return ret; |
| |
| return change; |
| } |
| |
| static int maxim_codec_do_init(struct sound_codec_info *pcodec_info, |
| int sampling_rate, int mclk_freq, |
| int bits_per_sample) |
| { |
| int ret = 0; |
| |
| #if !defined(CONFIG_TEGRA) |
| /* Enable codec clock */ |
| set_xclkout(); |
| |
| /* shift the device address by 1 for 7 bit addressing */ |
| g_maxim_codec_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1; |
| #else /* TEGRA */ |
| g_maxim_codec_i2c_dev_addr = pcodec_info->i2c_dev_addr; |
| #endif |
| |
| if (pcodec_info->codec_type == CODEC_MAX_98095) { |
| g_maxim_codec_info.devtype = MAX98095; |
| ret = max98095_device_init(&g_maxim_codec_info); |
| } else if (pcodec_info->codec_type == CODEC_MAX_98090) { |
| g_maxim_codec_info.devtype = MAX98090; |
| ret = max98090_device_init(&g_maxim_codec_info); |
| } else { |
| printf("%s: Codec id [%d] not defined\n", __func__, |
| pcodec_info->codec_type); |
| return -1; |
| } |
| |
| if (ret < 0) { |
| debug("%s: maxim codec chip init failed\n", __func__); |
| return ret; |
| } |
| |
| if (pcodec_info->codec_type == CODEC_MAX_98095) { |
| ret = max98095_set_sysclk(&g_maxim_codec_info, mclk_freq); |
| if (ret < 0) { |
| debug("%s: max98095 codec set sys clock failed\n", |
| __func__); |
| return ret; |
| } |
| ret = max98095_hw_params(&g_maxim_codec_info, sampling_rate, |
| bits_per_sample); |
| if (ret == 0) { |
| ret = max98095_set_fmt(&g_maxim_codec_info, |
| SND_SOC_DAIFMT_I2S | |
| SND_SOC_DAIFMT_NB_NF | |
| SND_SOC_DAIFMT_CBS_CFS); |
| } |
| } else if (pcodec_info->codec_type == CODEC_MAX_98090) { |
| ret = max98090_set_sysclk(&g_maxim_codec_info, mclk_freq); |
| if (ret < 0) { |
| debug("%s: max98090 codec set sys clock failed\n", |
| __func__); |
| return ret; |
| } |
| ret = max98090_hw_params(&g_maxim_codec_info, sampling_rate, |
| bits_per_sample); |
| if (ret == 0) { |
| ret = max98090_set_fmt(&g_maxim_codec_info, |
| SND_SOC_DAIFMT_I2S | |
| SND_SOC_DAIFMT_NB_NF | |
| SND_SOC_DAIFMT_CBS_CFS); |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int get_maxim_codec_values(struct sound_codec_info *pcodec_info, |
| const void *blob, const char *codectype) |
| { |
| int error = 0; |
| #ifdef CONFIG_OF_CONTROL |
| enum fdt_compat_id compat; |
| int node; |
| int parent; |
| |
| /* Get the node from FDT for codec */ |
| node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_98095_CODEC); |
| if (node <= 0) { |
| debug("%s: No node for Max98095 codec in device tree\n", |
| __func__); |
| debug("node = %d\n", node); |
| |
| node = fdtdec_next_compatible(blob, 0, |
| COMPAT_MAXIM_98090_CODEC); |
| if (node <= 0) { |
| debug("%s: No node for Max98090 codec in device tree\n", |
| __func__); |
| debug("node = %d\n", node); |
| return -1; |
| } |
| } |
| |
| parent = fdt_parent_offset(blob, node); |
| if (parent < 0) { |
| debug("%s: Cannot find node parent\n", __func__); |
| return -1; |
| } |
| |
| compat = fdtdec_lookup(blob, parent); |
| |
| switch (compat) { |
| case COMPAT_SAMSUNG_S3C2440_I2C: |
| case COMPAT_SAMSUNG_EXYNOS5_I2C: |
| case COMPAT_NVIDIA_TEGRA114_I2C: |
| pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent); |
| error |= pcodec_info->i2c_bus; |
| debug("i2c bus = %d\n", pcodec_info->i2c_bus); |
| pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node, |
| "reg", 0); |
| error |= pcodec_info->i2c_dev_addr; |
| debug("i2c dev addr = %x\n", pcodec_info->i2c_dev_addr); |
| break; |
| default: |
| debug("%s: Unknown compat id %d\n", __func__, compat); |
| return -1; |
| } |
| #else |
| pcodec_info->i2c_bus = MAXIM_AUDIO_I2C_BUS; |
| pcodec_info->i2c_dev_addr = MAXIM_AUDIO_I2C_REG; |
| debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); |
| #endif |
| if (!strcmp(codectype, "max98095")) |
| pcodec_info->codec_type = CODEC_MAX_98095; |
| else if (!strcmp(codectype, "max98090")) |
| pcodec_info->codec_type = CODEC_MAX_98090; |
| |
| if (error == -1) { |
| debug("fail to get max98095 codec node properties\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /* maxim Device Initialisation */ |
| int maxim_codec_init(const void *blob, const char *codectype, int sampling_rate, |
| int mclk_freq, int bits_per_sample) |
| { |
| int ret; |
| int old_bus = i2c_get_bus_num(); |
| struct sound_codec_info *pcodec_info = &g_codec_info; |
| |
| if (get_maxim_codec_values(pcodec_info, blob, codectype) < 0) { |
| printf("FDT Codec values failed\n"); |
| return -1; |
| } |
| |
| i2c_set_bus_num(pcodec_info->i2c_bus); |
| ret = maxim_codec_do_init(pcodec_info, sampling_rate, mclk_freq, |
| bits_per_sample); |
| i2c_set_bus_num(old_bus); |
| |
| return ret; |
| } |