123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
- index be872eefa61e..ca5f4e43476b 100644
- --- a/sound/soc/sunxi/sun8i-codec-analog.c
- +++ b/sound/soc/sunxi/sun8i-codec-analog.c
- @@ -19,6 +19,8 @@
- #include <sound/tlv.h>
-
- #include "sun8i-adda-pr-regmap.h"
- +#include <linux/gpio.h>
- +#include <linux/gpio/consumer.h>
-
- /* Codec analog control register offsets and bit fields */
- #define SUN8I_ADDA_HP_VOLC 0x00
- @@ -113,6 +115,81 @@
- #define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6
- #define SUN8I_ADDA_ADC_AP_EN_ADCG 0
-
- +/* Analog control register access bits */
- +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */
- +#define ADDA_PR_RESET BIT(28)
- +#define ADDA_PR_WRITE BIT(24)
- +#define ADDA_PR_ADDR_SHIFT 16
- +#define ADDA_PR_ADDR_MASK GENMASK(4, 0)
- +#define ADDA_PR_DATA_IN_SHIFT 8
- +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0)
- +#define ADDA_PR_DATA_OUT_SHIFT 0
- +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0)
- +
- +/* regmap access bits */
- +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
- +{
- + void __iomem *base = (void __iomem *)context;
- + u32 tmp;
- +
- + /* De-assert reset */
- + writel(readl(base) | ADDA_PR_RESET, base);
- +
- + /* Clear write bit */
- + writel(readl(base) & ~ADDA_PR_WRITE, base);
- +
- + /* Set register address */
- + tmp = readl(base);
- + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
- + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
- + writel(tmp, base);
- +
- + /* Read back value */
- + *val = readl(base) & ADDA_PR_DATA_OUT_MASK;
- +
- + return 0;
- +}
- +
- +static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
- +{
- + void __iomem *base = (void __iomem *)context;
- + u32 tmp;
- +
- + /* De-assert reset */
- + writel(readl(base) | ADDA_PR_RESET, base);
- +
- + /* Set register address */
- + tmp = readl(base);
- + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
- + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
- + writel(tmp, base);
- +
- + /* Set data to write */
- + tmp = readl(base);
- + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
- + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
- + writel(tmp, base);
- +
- + /* Set write bit to signal a write */
- + writel(readl(base) | ADDA_PR_WRITE, base);
- +
- + /* Clear write bit */
- + writel(readl(base) & ~ADDA_PR_WRITE, base);
- +
- + return 0;
- +}
- +
- +static const struct regmap_config adda_pr_regmap_cfg = {
- + .name = "adda-pr",
- + .reg_bits = 5,
- + .reg_stride = 1,
- + .val_bits = 8,
- + .reg_read = adda_reg_read,
- + .reg_write = adda_reg_write,
- + .fast_io = true,
- + .max_register = 24,
- +};
- +
- /* mixer controls */
- static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
- SOC_DAPM_DOUBLE_R("DAC Playback Switch",
- @@ -316,7 +393,7 @@ static const struct snd_soc_dapm_route sun8i_codec_mixer_routes[] = {
- /* headphone specific controls, widgets, and routes */
- static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
- static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
- - SOC_SINGLE_TLV("Headphone Playback Volume",
- + SOC_SINGLE_TLV("Master Playback Volume",
- SUN8I_ADDA_HP_VOLC,
- SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
- sun8i_codec_hp_vol_scale),
- @@ -673,7 +750,7 @@ struct sun8i_codec_analog_quirks {
-
- static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
- .has_headphone = true,
- - .has_hmic = true,
- +// .has_hmic = true,
- .has_linein = true,
- .has_mbias = true,
- .has_mic2 = true,
- @@ -817,10 +894,148 @@ static const struct of_device_id sun8i_codec_analog_of_match[] = {
- };
- MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
-
- +#define SUNXI_HMIC_ENABLE (0x4)
- +#define SUNXI_HMIC_CTL (0x8)
- +#define SUNXI_HMIC_DATA (0xc)
- +
- +/*
- +* SUNXI_HMIC_CTL
- +*HMIC Control Register
- +*CONFIG_ARCH_SUN8IW5:0x1c8
- +*/
- +#define HMIC_M (28)
- +#define HMIC_N (24)
- +#define HMIC_DIRQ (23)
- +#define HMIC_TH1_HYS (21)
- +#define HMIC_EARPHONE_OUT_IRQ_EN (20)
- +#define HMIC_EARPHONE_IN_IRQ_EN (19)
- +#define HMIC_KEY_UP_IRQ_EN (18)
- +#define HMIC_KEY_DOWN_IRQ_EN (17)
- +#define HMIC_DATA_IRQ_EN (16)
- +#define HMIC_DS_SAMP (14)
- +#define HMIC_TH2_HYS (13)
- +#define HMIC_TH2_KEY (8)
- +#define HMIC_SF_SMOOTH_FIL (6)
- +#define KEY_UP_IRQ_PEND (5)
- +#define HMIC_TH1_EARPHONE (0)
- +
- +/*
- +* SUNXI_HMIC_DATA
- +*HMIC Data Register
- +*
- +*CONFIG_ARCH_SUN8IW5:0x1cc
- +*/
- +#define HMIC_EARPHONE_OUT_IRQ_PEND (20)
- +#define HMIC_EARPHONE_IN_IRQ_PEND (19)
- +#define HMIC_KEY_UP_IRQ_PEND (18)
- +#define HMIC_KEY_DOWN_IRQ_PEND (17)
- +#define HMIC_DATA_IRQ_PEND (16)
- +#define HMIC_ADC_DATA (0)
- +
- +#define HP_VOLC (0x00)
- +#define LOMIXSC (0x01)
- +#define ROMIXSC (0x02)
- +#define DAC_PA_SRC (0x03)
- +#define PAEN_HP_CTRL (0x07)
- +#define ADDA_APT2 (0x12)
- +#define MIC1G_MICBIAS_CTRL (0x0B)
- +#define PA_ANTI_POP_REG_CTRL (0x0E)
- +#define PA_SLOPE_SELECT (3)
- +#define PA_ANTI_POP_EN (0)
- +
- +static void __iomem *sun8i_codec_analog_base;
- +static struct gpio_desc * speaker_amplifier_gpio;
- +
- +static int hmic_wrreg_prcm_bits(unsigned short reg, unsigned int mask, unsigned int value)
- +{
- + unsigned int old, new;
- +
- + adda_reg_read(sun8i_codec_analog_base, reg, &old);
- + new = (old & ~mask) | value;
- + adda_reg_write(sun8i_codec_analog_base, reg,new);
- +
- + return 0;
- +}
- +
- +static int hmic_wr_prcm_control(u32 reg, u32 mask, u32 shift, u32 val)
- +{
- + u32 reg_val;
- + reg_val = val << shift;
- + mask = mask << shift;
- + hmic_wrreg_prcm_bits(reg, mask, reg_val);
- + return 0;
- +}
- +
- +static int hmic_wrreg_bits(unsigned short reg, unsigned int mask, unsigned int value)
- +{
- + unsigned int old, new;
- +
- + old = readl(sun8i_codec_analog_base + reg);
- + new = (old & ~mask) | value;
- +
- + writel(new, sun8i_codec_analog_base + reg);
- +
- + return 0;
- +}
- +
- +static int hmic_wr_control(u32 reg, u32 mask, u32 shift, u32 val)
- +{
- + u32 reg_val;
- + reg_val = val << shift;
- + mask = mask << shift;
- + hmic_wrreg_bits(reg, mask, reg_val);
- + return 0;
- +}
- +
- +static irqreturn_t sunxi_codec_analog_irq(int irq, void *dev_id)
- +{
- + u32 tmp;
- +
- + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_KEY_DOWN_IRQ_PEND, 0x1);
- + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_EARPHONE_IN_IRQ_PEND, 0x1);
- + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_KEY_UP_IRQ_PEND, 0x1);
- + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_EARPHONE_OUT_IRQ_PEND, 0x1);
- + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_DATA_IRQ_PEND, 0x1);
- +
- + tmp = readl(sun8i_codec_analog_base + SUNXI_HMIC_DATA);
- + if(tmp & 0x1f)
- + gpiod_set_value(speaker_amplifier_gpio, 0);
- + else
- + gpiod_set_value(speaker_amplifier_gpio, 1);
- +
- + return IRQ_HANDLED;
- +}
- +
- +static void sunxi_hppa_enable(void) {
- + /*fix the resume blaze blaze noise*/
- + hmic_wr_prcm_control(ADDA_APT2, 0x1, PA_SLOPE_SELECT, 0x0);
- + hmic_wr_prcm_control(SUN8I_ADDA_PAEN_HP_CTRL, 0x3, SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL, 0x1);
- + hmic_wr_prcm_control(PA_ANTI_POP_REG_CTRL, 0x7, PA_ANTI_POP_EN, 0x2);
- + usleep_range(100,200);
- + /*enable pa*/
- + hmic_wr_prcm_control(SUN8I_ADDA_PAEN_HP_CTRL, 0x1, SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0x1);
- +}
- +
- +static void sunxi_hbias_enable(void) {
- + /*audio codec hardware bug. the HBIASADCEN bit must be enable in init*/
- + hmic_wr_prcm_control(SUN8I_ADDA_MIC1G_MICBIAS_CTRL, 0x1, SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE, 0x1);
- + hmic_wr_prcm_control(SUN8I_ADDA_MIC1G_MICBIAS_CTRL, 0x1, SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN, 0x1);
- +}
- +
- +static void codec_init_events(void)
- +{
- + /*fix the resume blaze blaze noise*/
- + sunxi_hppa_enable();
- + msleep(450);
- + /*audio codec hardware bug. the HBIASADCEN bit must be enable in init*/
- + sunxi_hbias_enable();
- +}
- +
- static int sun8i_codec_analog_probe(struct platform_device *pdev)
- {
- struct regmap *regmap;
- void __iomem *base;
- + int irq, ret;
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base)) {
- @@ -828,6 +1043,38 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev)
- return PTR_ERR(base);
- }
-
- + sun8i_codec_analog_base = base;
- + speaker_amplifier_gpio = devm_gpiod_get_optional(&pdev->dev, "speaker-amplifier", GPIOD_OUT_HIGH);
- + if (!IS_ERR_OR_NULL(speaker_amplifier_gpio)) {
- +
- + hmic_wr_control(SUNXI_HMIC_CTL, 0xf, HMIC_M, 0x0); /*0xf should be get from hw_debug 28*/
- + hmic_wr_control(SUNXI_HMIC_CTL, 0xf, HMIC_N, 0x0); /*0xf should be get from hw_debug 24 0xf*/
- +// hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DIRQ, 0x1); /*23*/
- + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_EARPHONE_OUT_IRQ_EN, 0x1); /*20*/
- + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_EARPHONE_IN_IRQ_EN, 0x1); /*19*/
- + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_KEY_UP_IRQ_EN, 0x1); /*18*/
- + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_KEY_DOWN_IRQ_EN, 0x1); /*17*/
- + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DATA_IRQ_EN, 0x1); /*16*/
- + hmic_wr_control(SUNXI_HMIC_CTL, 0x3, HMIC_DS_SAMP, 0x0); /*14 */
- + hmic_wr_control(SUNXI_HMIC_CTL, 0x1f, HMIC_TH2_KEY, 0x0); /*0xf should be get from hw_debug 8*/
- + hmic_wr_control(SUNXI_HMIC_CTL, 0x1f, HMIC_TH1_EARPHONE, 0x1); /*0x1 should be get from hw_debug 0*/
- +
- + irq = platform_get_irq(pdev, 0);
- + if (irq < 0) {
- + dev_err(&pdev->dev, "Can't retrieve our interrupt\n");
- + return irq;
- + }
- +
- + ret = devm_request_irq(&pdev->dev, irq, sunxi_codec_analog_irq, 0, "audio_hmic_irq", NULL);
- + if (ret) {
- + dev_err(&pdev->dev, "can't register interrupt handler irq %d: %d\n",
- + irq, ret);
- + return ret;
- + }
- +
- + codec_init_events();
- + }
- +
- regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
- if (IS_ERR(regmap)) {
- dev_err(&pdev->dev, "Failed to create regmap\n");
- diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
- index 518bfb724a5b..b6a90e33f20a 100644
- --- a/sound/soc/sunxi/sun8i-codec.c
- +++ b/sound/soc/sunxi/sun8i-codec.c
- @@ -257,6 +257,9 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
- regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
- SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
- hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
- + regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
- + SUN8I_SYS_SR_CTRL_AIF2_FS_MASK,
- + hw_rate << SUN8I_SYS_SR_CTRL_AIF2_FS);
-
- return 0;
- }
- @@ -288,6 +291,9 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
- SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
- SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
- } else {
- + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
- + BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
- + value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
- regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
- BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
- value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
- @@ -321,6 +327,9 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
- if (format != 3)
- return -EINVAL;
- } else {
- + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
- + SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
- + format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
- regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
- SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
- format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
- @@ -365,6 +374,9 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
- invert ^= scodec->quirks->lrck_inversion;
- }
-
- + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
- + SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
- + invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
- regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
- SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
- invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
- @@ -519,6 +531,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
- return -EINVAL;
- }
-
- + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
- + SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
- + word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
- regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
- SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
- word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
- @@ -548,6 +563,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
- clk_reg = SUN8I_AIF_CLK_CTRL(dai->id);
- }
-
- + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
- + SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
- + (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
- regmap_update_bits(scodec->regmap, clk_reg,
- SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
- (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
- @@ -557,6 +575,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
- if (bclk_div < 0)
- return bclk_div;
-
- + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
- + SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
- + bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
- regmap_update_bits(scodec->regmap, clk_reg,
- SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
- bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
- @@ -1226,6 +1247,7 @@ static const struct snd_soc_component_driver sun8i_soc_component = {
- };
-
- static const struct regmap_config sun8i_codec_regmap_config = {
- + .name = "sun8i_codec",
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
|