diff options
author | Shengjiu Wang <shengjiu.wang@nxp.com> | 2018-09-14 13:09:40 +0800 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:34:02 +0800 |
commit | 03d09e1c2efe017ab37fcdf3c4a1d0867cf51b91 (patch) | |
tree | 7a11e8a71dc5aeafb2a12304a6d21f9250f62e04 /sound/soc/codecs/rpmsg_ak4497.c | |
parent | 1c9d42ea9787ffdb767e5d7d3d8b0e33315e3270 (diff) |
MLK-19581-1: ASoC: rpmsg_ak4497: support ak4497 over rpmsg
The difference of rpmsg_ak4497 and ak4497 driver is first one
will send command through rpmsg, second one send command through
i2c.
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
(cherry picked from commit 337f70c4ea5278db28abe1e6eaefbf2d0082aec5)
Diffstat (limited to 'sound/soc/codecs/rpmsg_ak4497.c')
-rw-r--r-- | sound/soc/codecs/rpmsg_ak4497.c | 1135 |
1 files changed, 1135 insertions, 0 deletions
diff --git a/sound/soc/codecs/rpmsg_ak4497.c b/sound/soc/codecs/rpmsg_ak4497.c new file mode 100644 index 000000000000..80b8362eec93 --- /dev/null +++ b/sound/soc/codecs/rpmsg_ak4497.c @@ -0,0 +1,1135 @@ +/* + * ak4497.c -- audio driver for AK4497 + * + * Copyright (C) 2016 Asahi Kasei Microdevices Corporation + * Copyright (C) 2017, NXP + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/pcm_params.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <sound/pcm_params.h> +#include <linux/pm_runtime.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include "../fsl/fsl_rpmsg_i2s.h" + +#include "ak4497.h" + +//#define AK4497_DEBUG //used at debug mode +#define AK4497_NUM_SUPPLIES 2 +static const char *ak4497_supply_names[AK4497_NUM_SUPPLIES] = { + "DVDD", + "AVDD", +}; + +/* AK4497 Codec Private Data */ +struct rpmsg_ak4497_priv { + struct regmap *regmap; + int fs1; /* Sampling Frequency */ + int nBickFreq; /* 0: 48fs for 24bit, 1: 64fs or more for 32bit */ + int nTdmSds; + int pdn_gpio; + int mute_gpio; + int fmt; + struct regulator_bulk_data supplies[AK4497_NUM_SUPPLIES]; + struct fsl_rpmsg_i2s *rpmsg_i2s; + int audioindex; + struct platform_device *pdev; +}; + +/* ak4497 register cache & default register settings */ +static const struct reg_default ak4497_reg[] = { + { AK4497_00_CONTROL1, 0x0C}, + { AK4497_01_CONTROL2, 0x22}, + { AK4497_02_CONTROL3, 0x00}, + { AK4497_03_LCHATT, 0xFF}, + { AK4497_04_RCHATT, 0xFF}, + { AK4497_05_CONTROL4, 0x00}, + { AK4497_06_DSD1, 0x00}, + { AK4497_07_CONTROL5, 0x00}, + { AK4497_08_SOUNDCONTROL, 0x00}, + { AK4497_09_DSD2, 0x00}, + { AK4497_0A_CONTROL7, 0x04}, + { AK4497_0B_CONTROL8, 0x00}, + { AK4497_0C_RESERVED, 0x00}, + { AK4497_0D_RESERVED, 0x00}, + { AK4497_0E_RESERVED, 0x00}, + { AK4497_0F_RESERVED, 0x00}, + { AK4497_10_RESERVED, 0x00}, + { AK4497_11_RESERVED, 0x00}, + { AK4497_12_RESERVED, 0x00}, + { AK4497_13_RESERVED, 0x00}, + { AK4497_14_RESERVED, 0x00}, + { AK4497_15_DFSREAD, 0x00}, +}; + +/* Volume control: + * from -127 to 0 dB in 0.5 dB steps (mute instead of -127.5 dB) + */ +static DECLARE_TLV_DB_SCALE(latt_tlv, -12750, 50, 0); +static DECLARE_TLV_DB_SCALE(ratt_tlv, -12750, 50, 0); + +static const char * const ak4497_ecs_select_texts[] = {"768kHz", "384kHz"}; + +static const char * const ak4497_dem_select_texts[] = { + "44.1kHz", "OFF", "48kHz", "32kHz"}; +static const char * const ak4497_dzfm_select_texts[] = { + "Separated", "ANDed"}; + +static const char * const ak4497_sellr_select_texts[] = { + "Rch", "Lch"}; +static const char * const ak4497_dckb_select_texts[] = { + "Falling", "Rising"}; +static const char * const ak4497_dcks_select_texts[] = { + "512fs", "768fs"}; + +static const char * const ak4497_dsdd_select_texts[] = { + "Normal", "Volume Bypass"}; + +static const char * const ak4497_sc_select_texts[] = { + "Setting 1", "Setting 2", "Setting 3"}; +static const char * const ak4497_dsdf_select_texts[] = { + "50kHz", "150kHz"}; +static const char * const ak4497_dsd_input_path_select[] = { + "16_17_19pin", "3_4_5pin"}; +static const char * const ak4497_ats_select_texts[] = { + "4080/fs", "2040/fs", "510/fs", "255/fs"}; + +static const struct soc_enum ak4497_dac_enum[] = { + SOC_ENUM_SINGLE(AK4497_00_CONTROL1, 5, + ARRAY_SIZE(ak4497_ecs_select_texts), + ak4497_ecs_select_texts), + SOC_ENUM_SINGLE(AK4497_01_CONTROL2, 1, + ARRAY_SIZE(ak4497_dem_select_texts), + ak4497_dem_select_texts), + SOC_ENUM_SINGLE(AK4497_01_CONTROL2, 6, + ARRAY_SIZE(ak4497_dzfm_select_texts), + ak4497_dzfm_select_texts), + SOC_ENUM_SINGLE(AK4497_02_CONTROL3, 1, + ARRAY_SIZE(ak4497_sellr_select_texts), + ak4497_sellr_select_texts), + SOC_ENUM_SINGLE(AK4497_02_CONTROL3, 4, + ARRAY_SIZE(ak4497_dckb_select_texts), + ak4497_dckb_select_texts), + SOC_ENUM_SINGLE(AK4497_02_CONTROL3, 5, + ARRAY_SIZE(ak4497_dcks_select_texts), + ak4497_dcks_select_texts), + SOC_ENUM_SINGLE(AK4497_06_DSD1, 1, + ARRAY_SIZE(ak4497_dsdd_select_texts), + ak4497_dsdd_select_texts), + SOC_ENUM_SINGLE(AK4497_08_SOUNDCONTROL, 0, + ARRAY_SIZE(ak4497_sc_select_texts), + ak4497_sc_select_texts), + SOC_ENUM_SINGLE(AK4497_09_DSD2, 1, + ARRAY_SIZE(ak4497_dsdf_select_texts), + ak4497_dsdf_select_texts), + SOC_ENUM_SINGLE(AK4497_09_DSD2, 2, + ARRAY_SIZE(ak4497_dsd_input_path_select), + ak4497_dsd_input_path_select), + SOC_ENUM_SINGLE(AK4497_0B_CONTROL8, 6, + ARRAY_SIZE(ak4497_ats_select_texts), + ak4497_ats_select_texts), +}; + +static const char * const ak4497_dsdsel_select_texts[] = { + "64fs", "128fs", "256fs", "512fs"}; +static const char * const ak4497_bickfreq_select[] = {"48fs", "64fs"}; + +static const char * const ak4497_tdm_sds_select[] = { + "L1R1", "TDM128_L1R1", "TDM128_L2R2", + "TDM256_L1R1", "TDM256_L2R2", "TDM256_L3R3", "TDM256_L4R4", + "TDM512_L1R1", "TDM512_L2R2", "TDM512_L3R3", "TDM512_L4R4", + "TDM512_L5R5", "TDM512_L6R6", "TDM512_L7R7", "TDM512_L8R8", +}; + +static const char * const ak4497_adfs_select[] = { + "Normal Speed Mode", "Double Speed Mode", "Quad Speed Mode", + "Quad Speed Mode", "Oct Speed Mode", "Hex Speed Mode", "Oct Speed Mode", + "Hex Speed Mode" +}; + +static const struct soc_enum ak4497_dac_enum2[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4497_dsdsel_select_texts), + ak4497_dsdsel_select_texts), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4497_bickfreq_select), + ak4497_bickfreq_select), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4497_tdm_sds_select), + ak4497_tdm_sds_select), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4497_adfs_select), + ak4497_adfs_select) +}; + +static int ak4497_read(struct snd_soc_codec *codec, unsigned int reg, + unsigned int *val) +{ + int ret; + + ret = snd_soc_component_read(&codec->component, reg, val); + if (ret < 0) + dev_err(codec->dev, "Register %u read failed, ret=%d.\n", reg, ret); + + return ret; +} + +static int ak4497_get_dsdsel(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + unsigned int dsdsel0, dsdsel1; + + ak4497_read(codec, AK4497_06_DSD1, &dsdsel0); + dsdsel0 &= AK4497_DSDSEL0; + + ak4497_read(codec, AK4497_09_DSD2, &dsdsel1); + dsdsel1 &= AK4497_DSDSEL1; + + ucontrol->value.enumerated.item[0] = ((dsdsel1 << 1) | dsdsel0); + + return 0; +} + +static int ak4497_set_dsdsel(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + unsigned int dsdsel = ucontrol->value.enumerated.item[0]; + + switch (dsdsel) { + case 0: /* 2.8224MHz */ + snd_soc_update_bits(codec, AK4497_06_DSD1, 0x01, 0x00); + snd_soc_update_bits(codec, AK4497_09_DSD2, 0x01, 0x00); + break; + case 1: /* 5.6448MHz */ + snd_soc_update_bits(codec, AK4497_06_DSD1, 0x01, 0x01); + snd_soc_update_bits(codec, AK4497_09_DSD2, 0x01, 0x00); + break; + case 2: /* 11.2896MHz */ + snd_soc_update_bits(codec, AK4497_06_DSD1, 0x01, 0x00); + snd_soc_update_bits(codec, AK4497_09_DSD2, 0x01, 0x01); + break; + case 3: /* 22.5792MHz */ + snd_soc_update_bits(codec, AK4497_06_DSD1, 0x01, 0x01); + snd_soc_update_bits(codec, AK4497_09_DSD2, 0x01, 0x01); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ak4497_get_bickfs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = ak4497->nBickFreq; + + return 0; +} + +static int ak4497_set_bickfs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + + ak4497->nBickFreq = ucontrol->value.enumerated.item[0]; + + return 0; +} + +static int ak4497_get_tdmsds(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = ak4497->nTdmSds; + + return 0; +} + +static int ak4497_set_tdmsds(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + int regA, regB; + + ak4497->nTdmSds = ucontrol->value.enumerated.item[0]; + + if (ak4497->nTdmSds == 0) + regB = 0; /* SDS0 bit = 0 */ + else + regB = (1 & (ak4497->nTdmSds - 1)); /* SDS0 bit = 1 */ + + switch (ak4497->nTdmSds) { + case 0: + regA = 0; /* Normal */ + break; + case 1: + case 2: + regA = 4; /* TDM128 TDM1-0bits = 1 */ + break; + case 3: + case 4: + regA = 8; /* TDM128 TDM1-0bits = 2 */ + break; + case 5: + case 6: + regA = 9; /* TDM128 TDM1-0bits = 2 */ + break; + case 7: + case 8: + regA = 0xC; /* TDM128 TDM1-0bits = 3 */ + break; + case 9: + case 10: + regA = 0xD; /* TDM128 TDM1-0bits = 3 */ + break; + case 11: + case 12: + regA = 0xE; /* TDM128 TDM1-0bits = 3 */ + break; + case 13: + case 14: + regA = 0xF; /* TDM128 TDM1-0bits = 3 */ + break; + default: + regA = 0; + regB = 0; + break; + } + + regA <<= 4; + regB <<= 4; + + snd_soc_update_bits(codec, AK4497_0A_CONTROL7, 0xF0, regA); + snd_soc_update_bits(codec, AK4497_0B_CONTROL8, 0x10, regB); + + return 0; +} + +static int ak4497_get_adfs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + unsigned int nADFSbit; + + ak4497_read(codec, AK4497_15_DFSREAD, &nADFSbit); + nADFSbit &= 0x7; + + ucontrol->value.enumerated.item[0] = nADFSbit; + + return 0; +} + +static int ak4497_set_adfs(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("AK4497 : ADFS is read only\n"); + + return 0; +} + +static const char * const gain_control_texts[] = { + "2.8_2.8Vpp", "2.8_2.5Vpp", "2.5_2.5Vpp", "3.75_3.75Vpp", "3.75_2.5Vpp" +}; + +static const unsigned int gain_control_values[] = { + 0, 1, 2, 4, 5 +}; + +static const struct soc_enum ak4497_gain_control_enum = + SOC_VALUE_ENUM_SINGLE(AK4497_07_CONTROL5, 1, 7, + ARRAY_SIZE(gain_control_texts), + gain_control_texts, + gain_control_values); + +#ifdef AK4497_DEBUG + +static const char * const test_reg_select[] = { + "read AK4497 Reg 00:0B", + "read AK4497 Reg 15" +}; + +static const struct soc_enum ak4497_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(test_reg_select), test_reg_select), +}; + +static int nTestRegNo; + +static int get_test_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* Get the current output routing */ + ucontrol->value.enumerated.item[0] = nTestRegNo; + + return 0; +} + +static int set_test_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + u32 currMode = ucontrol->value.enumerated.item[0]; + int i, regs, rege; + unsigned int value; + + nTestRegNo = currMode; + + if (nTestRegNo == 0) { + regs = 0x00; + rege = 0x0B; + } else { + regs = 0x15; + rege = 0x15; + } + + for (i = regs; i <= rege; i++) { + ak4497_read(codec, i, &value); + pr_debug("***AK4497 Addr,Reg=(%x, %x)\n", i, value); + } + + return 0; +} +#endif + +static const struct snd_kcontrol_new ak4497_snd_controls[] = { + SOC_SINGLE_TLV("AK4497 Lch Digital Volume", + AK4497_03_LCHATT, 0, 0xFF, 0, latt_tlv), + SOC_SINGLE_TLV("AK4497 Rch Digital Volume", + AK4497_04_RCHATT, 0, 0xFF, 0, ratt_tlv), + + SOC_ENUM("AK4497 EX DF I/F clock", ak4497_dac_enum[0]), + SOC_ENUM("AK4497 De-emphasis Response", ak4497_dac_enum[1]), + SOC_ENUM("AK4497 Data Zero Detect Mode", ak4497_dac_enum[2]), + SOC_ENUM("AK4497 Data Selection at Mono Mode", ak4497_dac_enum[3]), + + SOC_ENUM("AK4497 Polarity of DCLK", ak4497_dac_enum[4]), + SOC_ENUM("AK4497 DCKL Frequency", ak4497_dac_enum[5]), + + SOC_ENUM("AK4497 DDSD Play Back Path", ak4497_dac_enum[6]), + SOC_ENUM("AK4497 Sound control", ak4497_dac_enum[7]), + SOC_ENUM("AK4497 Cut Off of DSD Filter", ak4497_dac_enum[8]), + + SOC_ENUM_EXT("AK4497 DSD Data Stream", ak4497_dac_enum2[0], + ak4497_get_dsdsel, ak4497_set_dsdsel), + SOC_ENUM_EXT("AK4497 BICK Frequency Select", ak4497_dac_enum2[1], + ak4497_get_bickfs, ak4497_set_bickfs), + SOC_ENUM_EXT("AK4497 TDM Data Select", ak4497_dac_enum2[2], + ak4497_get_tdmsds, ak4497_set_tdmsds), + + SOC_SINGLE("AK4497 External Digital Filter", AK4497_00_CONTROL1, + 6, 1, 0), + SOC_SINGLE("AK4497 MCLK Frequency Auto Setting", AK4497_00_CONTROL1, + 7, 1, 0), + SOC_SINGLE("AK4497 MCLK FS Auto Detect", AK4497_00_CONTROL1, 4, 1, 0), + + SOC_SINGLE("AK4497 Soft Mute Control", AK4497_01_CONTROL2, 0, 1, 0), + SOC_SINGLE("AK4497 Short delay filter", AK4497_01_CONTROL2, 5, 1, 0), + SOC_SINGLE("AK4497 Data Zero Detect Enable", AK4497_01_CONTROL2, + 7, 1, 0), + SOC_SINGLE("AK4497 Slow Roll-off Filter", AK4497_02_CONTROL3, 0, 1, 0), + SOC_SINGLE("AK4497 Invering Enable of DZF", AK4497_02_CONTROL3, + 4, 1, 0), + SOC_SINGLE("AK4497 Mono Mode", AK4497_02_CONTROL3, 3, 1, 0), + SOC_SINGLE("AK4497 Super Slow Roll-off Filter", AK4497_05_CONTROL4, + 0, 1, 0), + SOC_SINGLE("AK4497 AOUTR Phase Inverting", AK4497_05_CONTROL4, + 6, 1, 0), + SOC_SINGLE("AK4497 AOUTL Phase Inverting", AK4497_05_CONTROL4, + 7, 1, 0), + SOC_SINGLE("AK4497 DSD Mute Release", AK4497_06_DSD1, 3, 1, 0), + SOC_SINGLE("AK4497 DSD Mute Control Hold", AK4497_06_DSD1, 4, 1, 0), + SOC_SINGLE("AK4497 DSDR is detected", AK4497_06_DSD1, 5, 1, 0), + SOC_SINGLE("AK4497 DSDL is detected", AK4497_06_DSD1, 6, 1, 0), + SOC_SINGLE("AK4497 DSD Data Mute", AK4497_06_DSD1, 7, 1, 0), + SOC_SINGLE("AK4497 Synchronization Control", AK4497_07_CONTROL5, + 0, 1, 0), + + SOC_ENUM("AK4497 Output Level", ak4497_gain_control_enum), + SOC_SINGLE("AK4497 High Sonud Quality Mode", AK4497_08_SOUNDCONTROL, + 2, 1, 0), + SOC_SINGLE("AK4497 Heavy Load Mode", AK4497_08_SOUNDCONTROL, 3, 1, 0), + SOC_ENUM("AK4497 DSD Data Input Pin", ak4497_dac_enum[9]), + SOC_SINGLE("AK4497 Daisy Chain", AK4497_0B_CONTROL8, 1, 1, 0), + SOC_ENUM("AK4497 ATT Transit Time", ak4497_dac_enum[10]), + + SOC_ENUM_EXT("AK4497 Read FS Auto Detect Mode", ak4497_dac_enum2[3], + ak4497_get_adfs, ak4497_set_adfs), + +#ifdef AK4497_DEBUG + SOC_ENUM_EXT("Reg Read", ak4497_enum[0], get_test_reg, set_test_reg), +#endif + +}; + +static const char * const ak4497_dac_enable_texts[] = {"Off", "On"}; + +static SOC_ENUM_SINGLE_VIRT_DECL(ak4497_dac_enable_enum, + ak4497_dac_enable_texts); + +static const struct snd_kcontrol_new ak4497_dac_enable_control = + SOC_DAPM_ENUM("DAC Switch", ak4497_dac_enable_enum); + +/* ak4497 dapm widgets */ +static const struct snd_soc_dapm_widget ak4497_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("AK4497 SDTI", "Playback", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_DAC("AK4497 DAC", NULL, AK4497_0A_CONTROL7, 2, 0), + + SND_SOC_DAPM_MUX("AK4497 DAC Enable", SND_SOC_NOPM, + 0, 0, &ak4497_dac_enable_control), + + SND_SOC_DAPM_OUTPUT("AK4497 AOUT"), + +}; + +static const struct snd_soc_dapm_route ak4497_intercon[] = { + {"AK4497 DAC", NULL, "AK4497 SDTI"}, + {"AK4497 DAC Enable", "On", "AK4497 DAC"}, + {"AK4497 AOUT", NULL, "AK4497 DAC Enable"}, +}; + +static int ak4497_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + snd_pcm_format_t pcm_format = params_format(params); + + unsigned int dfs, dfs2, dsdsel0, dsdsel1, format; + int nfs1; + bool is_dsd = false; + int dsd_bclk; + + if (pcm_format == SNDRV_PCM_FORMAT_DSD_U8 || + pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE || + pcm_format == SNDRV_PCM_FORMAT_DSD_U16_BE || + pcm_format == SNDRV_PCM_FORMAT_DSD_U32_LE || + pcm_format == SNDRV_PCM_FORMAT_DSD_U32_BE) + is_dsd = true; + + nfs1 = params_rate(params); + ak4497->fs1 = nfs1; + + ak4497_read(codec, AK4497_01_CONTROL2, &dfs); + dfs &= ~AK4497_DFS; + + ak4497_read(codec, AK4497_05_CONTROL4, &dfs2); + dfs2 &= ~AK4497_DFS2; + + ak4497_read(codec, AK4497_06_DSD1, &dsdsel0); + dsdsel0 &= ~AK4497_DSDSEL0; + + ak4497_read(codec, AK4497_09_DSD2, &dsdsel1); + dsdsel1 &= ~AK4497_DSDSEL1; + + if (!is_dsd) { + switch (nfs1) { + case 8000: + case 11025: + case 16000: + case 22050: + case 32000: + case 44100: + case 48000: + dfs |= AK4497_DFS_48KHZ; + dfs2 |= AK4497_DFS2_48KHZ; + break; + case 88200: + case 96000: + dfs |= AK4497_DFS_96KHZ; + dfs2 |= AK4497_DFS2_48KHZ; + break; + case 176400: + case 192000: + dfs |= AK4497_DFS_192KHZ; + dfs2 |= AK4497_DFS2_48KHZ; + break; + case 352800: + case 384000: + dfs |= AK4497_DFS_384KHZ; + dfs2 |= AK4497_DFS2_384KHZ; + break; + case 705600: + case 768000: + dfs |= AK4497_DFS_768KHZ; + dfs2 |= AK4497_DFS2_384KHZ; + break; + default: + return -EINVAL; + } + } else { + dsd_bclk = params_rate(params) * + params_physical_width(params); + + switch (dsd_bclk) { + case 2822400: + dsdsel0 |= AK4497_DSDSEL0_2MHZ; + dsdsel1 |= AK4497_DSDSEL1_2MHZ; + break; + case 5644800: + dsdsel0 |= AK4497_DSDSEL0_5MHZ; + dsdsel1 |= AK4497_DSDSEL1_5MHZ; + break; + case 11289600: + dsdsel0 |= AK4497_DSDSEL0_11MHZ; + dsdsel1 |= AK4497_DSDSEL1_11MHZ; + break; + case 22579200: + dsdsel0 |= AK4497_DSDSEL0_22MHZ; + dsdsel1 |= AK4497_DSDSEL1_22MHZ; + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, AK4497_06_DSD1, dsdsel0); + snd_soc_write(codec, AK4497_09_DSD2, dsdsel1); + } + + snd_soc_write(codec, AK4497_01_CONTROL2, dfs); + snd_soc_write(codec, AK4497_05_CONTROL4, dfs2); + + ak4497_read(codec, AK4497_00_CONTROL1, &format); + format &= ~AK4497_DIF; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + if (ak4497->fmt == SND_SOC_DAIFMT_I2S) + format |= AK4497_DIF_24BIT_I2S; + else + format |= AK4497_DIF_16BIT_LSB; + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + if (ak4497->fmt == SND_SOC_DAIFMT_I2S) + format |= AK4497_DIF_32BIT_I2S; + else if (ak4497->fmt == SND_SOC_DAIFMT_LEFT_J) + format |= AK4497_DIF_32BIT_MSB; + else if (ak4497->fmt == SND_SOC_DAIFMT_RIGHT_J) + format |= AK4497_DIF_32BIT_LSB; + else + return -EINVAL; + break; + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, AK4497_00_CONTROL1, format); + + return 0; +} + +static int ak4497_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + return 0; +} + +static int ak4497_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + unsigned int format, format2; + + /* set master/slave audio interface */ + ak4497_read(codec, AK4497_00_CONTROL1, &format); + format &= ~AK4497_DIF; + + ak4497_read(codec, AK4497_02_CONTROL3, &format2); + format2 &= ~AK4497_DIF_DSD; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + default: + dev_err(codec->dev, "Clock mode unsupported"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ak4497->fmt = SND_SOC_DAIFMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + ak4497->fmt = SND_SOC_DAIFMT_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + ak4497->fmt = SND_SOC_DAIFMT_RIGHT_J; + break; + case SND_SOC_DAIFMT_PDM: + format2 |= AK4497_DIF_DSD_MODE; + break; + default: + return -EINVAL; + } + + /* set format */ + snd_soc_write(codec, AK4497_00_CONTROL1, format); + snd_soc_write(codec, AK4497_02_CONTROL3, format2); + + return 0; +} + +static bool ak4497_volatile(struct device *dev, unsigned int reg) +{ + int ret; + +#ifdef AK4497_DEBUG + ret = 1; +#else + switch (reg) { + case AK4497_15_DFSREAD: + ret = 1; + break; + default: + ret = 0; + break; + } +#endif + return ret; +} + +static int ak4497_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + case SND_SOC_BIAS_STANDBY: + /* RSTN bit = 1 */ + snd_soc_update_bits(codec, AK4497_00_CONTROL1, 0x01, 0x01); + break; + case SND_SOC_BIAS_OFF: + /* RSTN bit = 0 */ + snd_soc_update_bits(codec, AK4497_00_CONTROL1, 0x01, 0x00); + break; + } + + return 0; +} + +static int ak4497_set_dai_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + int nfs, ndt; + + nfs = ak4497->fs1; + + if (mute) { /* SMUTE: 1 , MUTE */ + snd_soc_update_bits(codec, AK4497_01_CONTROL2, 0x01, 0x01); + ndt = 7424000 / nfs; + mdelay(ndt); + + /* External Mute ON */ + if (gpio_is_valid(ak4497->mute_gpio)) + gpio_set_value_cansleep(ak4497->mute_gpio, 1); + } else { /* SMUTE: 0, NORMAL operation */ + + /* External Mute OFF */ + if (gpio_is_valid(ak4497->mute_gpio)) + gpio_set_value_cansleep(ak4497->mute_gpio, 0); + snd_soc_update_bits(codec, AK4497_01_CONTROL2, 0x01, 0x00); + } + + return 0; +} + +#define AK4497_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define AK4497_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE |\ + SNDRV_PCM_FMTBIT_DSD_U8 |\ + SNDRV_PCM_FMTBIT_DSD_U16_LE |\ + SNDRV_PCM_FMTBIT_DSD_U32_LE) + +static const unsigned int ak4497_rates[] = { + 8000, 11025, 16000, 22050, + 32000, 44100, 48000, 88200, + 96000, 176400, 192000, 352800, + 384000, 705600, 768000, 1411200, + 2822400, +}; + +static const struct snd_pcm_hw_constraint_list ak4497_rate_constraints = { + .count = ARRAY_SIZE(ak4497_rates), + .list = ak4497_rates, +}; + +static int ak4497_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { + int ret; + + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &ak4497_rate_constraints); + + return ret; +} + +static struct snd_soc_dai_ops ak4497_dai_ops = { + .startup = ak4497_startup, + .hw_params = ak4497_hw_params, + .set_sysclk = ak4497_set_dai_sysclk, + .set_fmt = ak4497_set_dai_fmt, + .digital_mute = ak4497_set_dai_mute, +}; + +struct snd_soc_dai_driver rpmsg_ak4497_dai[] = { + { + .name = "rpmsg-ak4497-aif", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = AK4497_FORMATS, + }, + .ops = &ak4497_dai_ops, + }, +}; + +static int ak4497_init_reg(struct snd_soc_codec *codec) +{ + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + /* External Mute ON */ + if (gpio_is_valid(ak4497->mute_gpio)) + gpio_set_value_cansleep(ak4497->mute_gpio, 1); + + if (gpio_is_valid(ak4497->pdn_gpio)) { + gpio_set_value_cansleep(ak4497->pdn_gpio, 0); + usleep_range(1000, 2000); + gpio_set_value_cansleep(ak4497->pdn_gpio, 1); + usleep_range(1000, 2000); + } + + /* ak4497_set_bias_level(codec, SND_SOC_BIAS_STANDBY); */ + + /* SYNCE bit = 1 */ + ret = snd_soc_update_bits(codec, AK4497_07_CONTROL5, 0x01, 0x01); + if (ret) + return ret; + + /* HLOAD bit = 1, SC2 bit = 1 */ + ret = snd_soc_update_bits(codec, AK4497_08_SOUNDCONTROL, 0x0F, 0x0C); + if (ret) + return ret; + + return ret; +} + +static int ak4497_parse_dt(struct rpmsg_ak4497_priv *ak4497) +{ + struct device *dev; + struct device_node *np; + + dev = &(ak4497->pdev->dev); + np = dev->of_node; + + ak4497->pdn_gpio = -1; + ak4497->mute_gpio = -1; + + if (!np) + return 0; + + ak4497->pdn_gpio = of_get_named_gpio(np, "ak4497,pdn-gpio", 0); + if (ak4497->pdn_gpio < 0) + ak4497->pdn_gpio = -1; + + if (!gpio_is_valid(ak4497->pdn_gpio)) { + dev_err(dev, "ak4497 pdn pin(%u) is invalid\n", + ak4497->pdn_gpio); + ak4497->pdn_gpio = -1; + } + + ak4497->mute_gpio = of_get_named_gpio(np, "ak4497,mute-gpio", 0); + if (ak4497->mute_gpio < 0) + ak4497->mute_gpio = -1; + + if (!gpio_is_valid(ak4497->mute_gpio)) { + dev_err(dev, "ak4497 mute_gpio(%u) is invalid\n", + ak4497->mute_gpio); + ak4497->mute_gpio = -1; + } + + return 0; +} + +static int ak4497_probe(struct snd_soc_codec *codec) +{ + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + ret = ak4497_parse_dt(ak4497); + if (ret) + return ret; + + if (gpio_is_valid(ak4497->pdn_gpio)) { + ret = gpio_request(ak4497->pdn_gpio, "ak4497 pdn"); + if (ret) + return ret; + gpio_direction_output(ak4497->pdn_gpio, 0); + } + if (gpio_is_valid(ak4497->mute_gpio)) { + ret = gpio_request(ak4497->mute_gpio, "ak4497 mute"); + if (ret) + return ret; + gpio_direction_output(ak4497->mute_gpio, 0); + } + + ret = ak4497_init_reg(codec); + if (ret) + return ret; + + ak4497->fs1 = 48000; + ak4497->nBickFreq = 1; + ak4497->nTdmSds = 0; + + return ret; +} + +static int ak4497_remove(struct snd_soc_codec *codec) +{ + struct rpmsg_ak4497_priv *ak4497 = snd_soc_codec_get_drvdata(codec); + + ak4497_set_bias_level(codec, SND_SOC_BIAS_OFF); + if (gpio_is_valid(ak4497->pdn_gpio)) { + gpio_set_value_cansleep(ak4497->pdn_gpio, 0); + gpio_free(ak4497->pdn_gpio); + } + if (gpio_is_valid(ak4497->mute_gpio)) + gpio_free(ak4497->mute_gpio); + + return 0; +} + +#ifdef CONFIG_PM +static int ak4497_runtime_suspend(struct device *dev) +{ + struct rpmsg_ak4497_priv *ak4497 = dev_get_drvdata(dev); + + regcache_cache_only(ak4497->regmap, true); + + if (gpio_is_valid(ak4497->pdn_gpio)) { + gpio_set_value_cansleep(ak4497->pdn_gpio, 0); + usleep_range(1000, 2000); + } + + if (gpio_is_valid(ak4497->mute_gpio)) + gpio_free(ak4497->mute_gpio); + + return 0; +} + +static int ak4497_runtime_resume(struct device *dev) +{ + struct rpmsg_ak4497_priv *ak4497 = dev_get_drvdata(dev); + + /* External Mute ON */ + if (gpio_is_valid(ak4497->mute_gpio)) + gpio_set_value_cansleep(ak4497->mute_gpio, 1); + + if (gpio_is_valid(ak4497->pdn_gpio)) { + gpio_set_value_cansleep(ak4497->pdn_gpio, 1); + usleep_range(1000, 2000); + } + + regcache_cache_only(ak4497->regmap, false); + regcache_mark_dirty(ak4497->regmap); + + return regcache_sync(ak4497->regmap); +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops ak4497_pm = { + SET_RUNTIME_PM_OPS(ak4497_runtime_suspend, ak4497_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) +}; + +struct snd_soc_codec_driver rpmsg_codec_dev_ak4497 = { + .probe = ak4497_probe, + .remove = ak4497_remove, + + .idle_bias_off = true, + .set_bias_level = ak4497_set_bias_level, + + .component_driver = { + .controls = ak4497_snd_controls, + .num_controls = ARRAY_SIZE(ak4497_snd_controls), + .dapm_widgets = ak4497_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4497_dapm_widgets), + .dapm_routes = ak4497_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4497_intercon), + }, +}; + +static int rpmsg_ak4497_read(void *context, unsigned int reg, unsigned int *val) +{ + struct rpmsg_ak4497_priv *ak4497 = context; + struct fsl_rpmsg_i2s *rpmsg_i2s = ak4497->rpmsg_i2s; + struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info; + struct i2s_rpmsg_s *rpmsg = &i2s_info->rpmsg[GET_CODEC_VALUE].send_msg; + int err, reg_val; + + mutex_lock(&i2s_info->i2c_lock); + rpmsg->param.audioindex = ak4497->audioindex; + rpmsg->param.buffer_addr = reg; + rpmsg->header.cmd = GET_CODEC_VALUE; + err = i2s_info->send_message(&i2s_info->rpmsg[GET_CODEC_VALUE], i2s_info); + reg_val = i2s_info->rpmsg[GET_CODEC_VALUE].recv_msg.param.reg_data; + mutex_unlock(&i2s_info->i2c_lock); + if (err) + return -EIO; + + *val = reg_val; + return 0; +} + +static int rpmsg_ak4497_write(void *context, unsigned int reg, unsigned int val) +{ + struct rpmsg_ak4497_priv *ak4497 = context; + struct fsl_rpmsg_i2s *rpmsg_i2s = ak4497->rpmsg_i2s; + struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info; + struct i2s_rpmsg_s *rpmsg = &i2s_info->rpmsg[SET_CODEC_VALUE].send_msg; + int err; + + mutex_lock(&i2s_info->i2c_lock); + rpmsg->param.audioindex = ak4497->audioindex; + rpmsg->param.buffer_addr = reg; + rpmsg->param.buffer_size = val; + rpmsg->header.cmd = SET_CODEC_VALUE; + err = i2s_info->send_message(&i2s_info->rpmsg[SET_CODEC_VALUE], i2s_info); + mutex_unlock(&i2s_info->i2c_lock); + if (err) + return -EIO; + + return 0; +} + +static const struct regmap_config rpmsg_ak4497_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = AK4497_MAX_REGISTERS, + .volatile_reg = ak4497_volatile, + + .reg_defaults = ak4497_reg, + .num_reg_defaults = ARRAY_SIZE(ak4497_reg), + .cache_type = REGCACHE_RBTREE, + + .reg_read = rpmsg_ak4497_read, + .reg_write = rpmsg_ak4497_write, +}; + +static int rpmsg_ak4497_codec_probe(struct platform_device *pdev) +{ + struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(pdev->dev.parent); + struct fsl_rpmsg_codec *pdata = pdev->dev.platform_data; + struct rpmsg_ak4497_priv *ak4497; + int ret = 0; + int i; + + ak4497 = devm_kzalloc(&pdev->dev, + sizeof(struct rpmsg_ak4497_priv), GFP_KERNEL); + if (ak4497 == NULL) + return -ENOMEM; + + ak4497->rpmsg_i2s = rpmsg_i2s; + ak4497->pdev = pdev; + + ak4497->regmap = devm_regmap_init(&pdev->dev, NULL, ak4497, &rpmsg_ak4497_regmap); + if (IS_ERR(ak4497->regmap)) + return PTR_ERR(ak4497->regmap); + + if (pdata) + ak4497->audioindex = pdata->audioindex; + + dev_set_drvdata(&pdev->dev, ak4497); + + for (i = 0; i < ARRAY_SIZE(ak4497->supplies); i++) + ak4497->supplies[i].supply = ak4497_supply_names[i]; + + ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(ak4497->supplies), + ak4497->supplies); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(ak4497->supplies), + ak4497->supplies); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + ret = snd_soc_register_codec(&pdev->dev, &rpmsg_codec_dev_ak4497, + &rpmsg_ak4497_dai[0], ARRAY_SIZE(rpmsg_ak4497_dai)); + if (ret < 0) + return ret; + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int rpmsg_ak4497_codec_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static struct platform_driver rpmsg_ak4497_codec_driver = { + .driver = { + .name = RPMSG_CODEC_DRV_NAME_AK4497, + .pm = &ak4497_pm, + }, + .probe = rpmsg_ak4497_codec_probe, + .remove = rpmsg_ak4497_codec_remove, +}; + +module_platform_driver(rpmsg_ak4497_codec_driver); + +MODULE_AUTHOR("Junichi Wakasugi <wakasugi.jb@om.asahi-kasei.co.jp>"); +MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>"); +MODULE_DESCRIPTION("ASoC ak4497 codec driver"); +MODULE_LICENSE("GPL"); |