1111 lines
30 KiB
C
1111 lines
30 KiB
C
/*
|
|
* 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 "rpmsg_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_component *component, unsigned int reg,
|
|
unsigned int *val)
|
|
{
|
|
int ret;
|
|
|
|
ret = snd_soc_component_read(component, reg, val);
|
|
if (ret < 0)
|
|
dev_err(component->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_component *component = snd_soc_kcontrol_component(kcontrol);
|
|
unsigned int dsdsel0, dsdsel1;
|
|
|
|
ak4497_read(component, AK4497_06_DSD1, &dsdsel0);
|
|
dsdsel0 &= AK4497_DSDSEL0;
|
|
|
|
ak4497_read(component, 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_component *component = snd_soc_kcontrol_component(kcontrol);
|
|
unsigned int dsdsel = ucontrol->value.enumerated.item[0];
|
|
|
|
switch (dsdsel) {
|
|
case 0: /* 2.8224MHz */
|
|
snd_soc_component_update_bits(component, AK4497_06_DSD1, 0x01, 0x00);
|
|
snd_soc_component_update_bits(component, AK4497_09_DSD2, 0x01, 0x00);
|
|
break;
|
|
case 1: /* 5.6448MHz */
|
|
snd_soc_component_update_bits(component, AK4497_06_DSD1, 0x01, 0x01);
|
|
snd_soc_component_update_bits(component, AK4497_09_DSD2, 0x01, 0x00);
|
|
break;
|
|
case 2: /* 11.2896MHz */
|
|
snd_soc_component_update_bits(component, AK4497_06_DSD1, 0x01, 0x00);
|
|
snd_soc_component_update_bits(component, AK4497_09_DSD2, 0x01, 0x01);
|
|
break;
|
|
case 3: /* 22.5792MHz */
|
|
snd_soc_component_update_bits(component, AK4497_06_DSD1, 0x01, 0x01);
|
|
snd_soc_component_update_bits(component, 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_component *component = snd_soc_kcontrol_component(kcontrol);
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
|
|
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_component *component = snd_soc_kcontrol_component(kcontrol);
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
|
|
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_component *component = snd_soc_kcontrol_component(kcontrol);
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
|
|
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_component *component = snd_soc_kcontrol_component(kcontrol);
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
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_component_update_bits(component, AK4497_0A_CONTROL7, 0xF0, regA);
|
|
snd_soc_component_update_bits(component, 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_component *component = snd_soc_kcontrol_component(kcontrol);
|
|
unsigned int nADFSbit;
|
|
|
|
ak4497_read(component, 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_component *component = snd_soc_kcontrol_component(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(component, 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_component *component = dai->component;
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
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(component, AK4497_01_CONTROL2, &dfs);
|
|
dfs &= ~AK4497_DFS;
|
|
|
|
ak4497_read(component, AK4497_05_CONTROL4, &dfs2);
|
|
dfs2 &= ~AK4497_DFS2;
|
|
|
|
ak4497_read(component, AK4497_06_DSD1, &dsdsel0);
|
|
dsdsel0 &= ~AK4497_DSDSEL0;
|
|
|
|
ak4497_read(component, 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_component_write(component, AK4497_06_DSD1, dsdsel0);
|
|
snd_soc_component_write(component, AK4497_09_DSD2, dsdsel1);
|
|
}
|
|
|
|
snd_soc_component_write(component, AK4497_01_CONTROL2, dfs);
|
|
snd_soc_component_write(component, AK4497_05_CONTROL4, dfs2);
|
|
|
|
ak4497_read(component, 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_component_write(component, 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_component *component = dai->component;
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
unsigned int format, format2;
|
|
|
|
/* set master/slave audio interface */
|
|
ak4497_read(component, AK4497_00_CONTROL1, &format);
|
|
format &= ~AK4497_DIF;
|
|
|
|
ak4497_read(component, 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(component->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_component_write(component, AK4497_00_CONTROL1, format);
|
|
snd_soc_component_write(component, 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_component *component,
|
|
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_component_update_bits(component, AK4497_00_CONTROL1, 0x01, 0x01);
|
|
break;
|
|
case SND_SOC_BIAS_OFF:
|
|
/* RSTN bit = 0 */
|
|
snd_soc_component_update_bits(component, AK4497_00_CONTROL1, 0x01, 0x00);
|
|
break;
|
|
}
|
|
|
|
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,
|
|
};
|
|
|
|
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_component *component)
|
|
{
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
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_component_update_bits(component, AK4497_07_CONTROL5, 0x01, 0x01);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* HLOAD bit = 1, SC2 bit = 1 */
|
|
ret = snd_soc_component_update_bits(component, 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_component *component)
|
|
{
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
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);
|
|
}
|
|
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(component), "AK4497 AOUT");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(component), "Playback");
|
|
|
|
ret = ak4497_init_reg(component);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ak4497->fs1 = 48000;
|
|
ak4497->nBickFreq = 1;
|
|
ak4497->nTdmSds = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void ak4497_remove(struct snd_soc_component *component)
|
|
{
|
|
struct rpmsg_ak4497_priv *ak4497 = snd_soc_component_get_drvdata(component);
|
|
|
|
ak4497_set_bias_level(component, 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);
|
|
|
|
}
|
|
|
|
#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_component_driver rpmsg_codec_dev_ak4497 = {
|
|
.probe = ak4497_probe,
|
|
.remove = ak4497_remove,
|
|
|
|
.set_bias_level = ak4497_set_bias_level,
|
|
.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),
|
|
.suspend_bias_off = 1,
|
|
.idle_bias_on = 1,
|
|
.use_pmdown_time = 1,
|
|
.endianness = 1,
|
|
.non_legacy_dai_naming = 1,
|
|
};
|
|
|
|
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 = devm_snd_soc_register_component(&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)
|
|
{
|
|
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");
|