build/patch/kernel/archive/sunxi-5.10/check/0000-sound-soc-ac100-codec-Initial-implementation.patch.disabled

347 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 6eb4890e1b83490864f18d3926182069e54a4dfb Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 12 Nov 2017 23:09:14 +0100
Subject: [PATCH] sound: soc: ac100-codec: Initial implementation
This driver provides AC100 codec controls.
Note: This does not yet provide anything, it's just a skeleton
for a future driver.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
sound/soc/sunxi/Kconfig | 11 ++
sound/soc/sunxi/Makefile | 1 +
sound/soc/sunxi/ac100-codec.c | 291 ++++++++++++++++++++++++++++++++++
3 files changed, 303 insertions(+)
create mode 100644 sound/soc/sunxi/ac100-codec.c
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 22408bc2d6ec6..e276cc94a8c5e 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -20,6 +20,17 @@ config SND_SUN8I_CODEC
Say Y or M if you want to add sun8i digital audio codec support.
+config SND_AC100_CODEC
+ tristate "Allwinner (X-Powers) AC100 audio codec"
+ depends on OF
+ depends on MACH_SUN8I || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This option enables the audio codec support for Allwinner (X-Powers)
+ AC100 chip.
+
+ Say Y or M if you want to add AC100 audio codec support.
+
config SND_SUN8I_CODEC_ANALOG
tristate "Allwinner sun8i Codec Analog Controls Support"
depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index 4a9ef67386caf..83461fdbfaa2a 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
+obj-$(CONFIG_SND_AC100_CODEC) += ac100-codec.o
diff --git a/sound/soc/sunxi/ac100-codec.c b/sound/soc/sunxi/ac100-codec.c
new file mode 100644
index 0000000000000..d5438815be754
--- /dev/null
+++ b/sound/soc/sunxi/ac100-codec.c
@@ -0,0 +1,291 @@
+/*
+ * This driver supports the controls for X-Powers (Allwinner)
+ * AC100 audio codec. This codec is co-packaged with AXP81x PMICs.
+ *
+ * (C) Copyright 2017 Ondrej Jirman <megous@megous.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/mfd/ac100.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+/*
+ * Reasearch
+ * ---------
+ *
+ * Features:
+ * 2 A/D
+ * 2 D/A
+ * 2 I2S/PCM #1 and #2
+ * 1 PCM mono #3 muxable with I2S #2
+ * 3 mic inputs (mic #2 and #3 exclusively muxable at input)
+ * 1 line in (directly or through amp)
+ * 1 aux input
+ * all input signals mixable directly into output (bypass AD/DA)
+ *
+ * outputs:
+ * HPOUTL - headphone left
+ * HPOUTR - headphone right
+ * LINEOUT - line out differential
+ * EAROUT - earpeiece differential
+ * SPKOUT1 - SPOL left speaker differnetial
+ * SPKOUT2 - SPOR right speaker differnetial
+ *
+ * Power up:
+ * LDOIN - 1.5-3.3V external power
+ * AVCC - analog power 3V
+ * CPVDD - 1.8V
+ * VDD-IO1 - power for I2S #1 and #2 1.8/3V
+ * VDD-IO2 - power for I2S #3 1.8/3V
+ * VCC-RTC - power for RTC 1.8/3V
+ *
+ * Clocks: page 28
+ * SYSCLK must be 24576000 Hz (48kHz) or 22579200 Hz (44.1kHz)
+ * - Source I2S1CLK/MCLK1
+ * - If SRC# module is used SYSCLK must be generated by PLL
+ *
+ * A/D:
+ * ADC_APC_CTRL B15 B11 enable/disable A/D to save power
+ * ADC_APC_CTRL B14-12 B10-8 volume control for A/D
+ * ADC_DIG_CTRL B15 enable/disable digital A/D to save power
+ * ADDA_FS_I2S1 ADDA_FS_I2S2 - select sample rate
+ *
+ * D/A:
+ * OMIXER_DACA_CTRL B15-14 enable/disable D/A channels
+ * DAC_DIG_CTRL B15 enable/disable digital D/A
+ *
+ * Mixer:
+ * - 2 channels DAC Output mixers
+ * - inputs:
+ * - LINEINL/R
+ * - AXIL/R
+ * - MIC1P/N,MIC2P/N
+ * - Stereo DAC output
+ * - 2 channels ADC Record mixers
+ * - inputs:
+ * - LINEINL/R
+ * - AXIL/R
+ * - MIC1P/N,MIC2P/N
+ * - Stereo DAC output
+ * - Digital mixers
+ * - avaliable on:
+ * - before stereo DAC - DAC_MXR_SRC
+ * - I2S1 output - I2S1_MXR_SRC
+ * - I2S2 output - I2S2_MXR_SRC
+ * - Analogue inputs
+ * - LINEINL/R - 1 ch. mono
+ * - can be mixed into ADC record mixer or DAC output mixer
+ * - -9dB to 12dB in 1.5dB step by LINEIN_DIFF_PREG
+ * - AXIL/R - 2 ch. stereo
+ * - can be mixed into ADC record mixer or DAC output mixer
+ * - programmable volume level adj. and mute
+ * - -9dB to 12dB in 1.5dB steps by AXI_PREG
+ * - MIC1P/N - has preamp
+ * - MIC2P/N - has preamp
+ * - MIC3P/N - has preamp muxed with MIC2 (sel by ADC_SRCBST_CTRL B7)
+ * - can be mixed into ADC record mixer or DAC output mixer
+ * - preamps enable at ADC_SRCBST_CTRL B15 and B11
+ * - preamp gain at MIC1BOOST MIC2BOOST
+ * - Analogue outputs:
+ * - HPOUTL/R, HPOUTFB - 2ch. headphones
+ * - sources output mixer or directly from DAC
+ * - sel HPOUT_CTRL B15 B14
+ * - mute HPOUT_CTRL B13 B12
+ * - power amp
+ * - powerdown/up HPOUT_CTRL B11
+ * - volume HP_VOL[5:0] - 64dB range in 1dB step from 0dB to -62dB
+ * - mute by using 0 for HP_VOL[5:0]
+ * - DC offset cancellation (POP noise) HP_DCRM_EN
+ * - This bit must be set 0xf before headphone PA enabled, and this bit
+ * must be set 0x0 before headphone PA disabled.
+ * - zero cross to prevent noise/clicsk on volume change ZCROSS_EN
+ * - SPOLP/N, SPORP/N 2 ch. speakers (mono/stereo)
+ * - source for SPOLP
+ * - left output mixer or (left+right) output mixer
+ * - source for SPORP
+ * - right output mixer or (left+right) output mixer
+ * - volume 43.5dB rang in 1.5dB step from -43.5dB to 0dB
+ * - amp enable SPKOUT_CTRL B11 B7
+ * - EAROUTP/N - 1 ch earpeice
+ * - source left DAC, right DAC, left output mixer or right output mixer
+ * - volume ERPOUT_CTRL[4:0] 43.5dB range in 1.5dB step from -43.5dB to 0dB
+ * - power amp enable ERPOUT_CTRL B5
+ * - LINEOUTP/N - 1ch line out
+ * - source MIC1 preamp, MIC2 preamp, left output mix or right output mix
+ * - volume 10.5dB range in 1.5dB step from -4.5dB to 6dB
+ * - out buffer power up/down LOUT_CTRL B4
+ *
+ * Jack insert detection:
+ * - HBIAS current detection
+ * - 5bit ADC sample rate 16/32/64/128Hz
+ * - HMIC_STATUS[12:8] - ADC value
+ * - 2 thresholds TH1 for plug connection, TH2 for key press
+ * - can periodically trigger interrupts during key press (HBIAS above TH2)
+ *
+ * Interrupts:
+ * - FALLING_EDGE
+ * - for:
+ * - KEYDOWN
+ * - KEYUP
+ * - PLUG_IN
+ * - PLUG_OUT
+ * - HMIC_DATA
+ *
+ * High Pass Filter:
+ * - remove DC offset, can be disabled
+ *
+ * AGC:
+ * - automatic gain control before ADC input channels
+ * - params:
+ * - attack, decay time - 32/fs to 2^15*32/fs
+ * - target gain - 1dB to 30dB relative to a full-scale signal
+ * - noise threshold - 30dB to 90dB of full-scale (mute if input below this level)
+ * - max gain 0dB to 40dB in steps of 0.5dB
+ * - hysteresis - for noise detection in terms of signal level
+ * - debounce time - hysteresis for noise det in terms of time
+ * - also provides some output flags:
+ * - noise threshold reached
+ * - current gain
+ * - agc saturated (gain could get higher for the given input, but limited by
+ * params)
+ * - adc saturated - clipping at ADC input stage
+ *
+ * DRC:
+ * - dynamic range control for digital playback path
+ * - energy filter
+ * - compressor
+ * - smooth filter
+ * - can be disabled
+ */
+
+#define AC100_HMIC_DATA_MASK GENMASK(12, 8)
+#define AC100_HMIC_DATA_OFF 8
+#define AC100_HMIC_PULLOUT_PENDING BIT(4)
+#define AC100_HMIC_PLUGIN_PENDING BIT(3)
+#define AC100_HMIC_KEYUP_PENDING BIT(2)
+#define AC100_HMIC_KEYDOWN_PENDING BIT(1)
+#define AC100_HMIC_DATA_PENDING BIT(0)
+
+struct ac100_codec {
+ struct device *dev;
+ struct regmap *regmap;
+ int irq;
+};
+
+static irqreturn_t ac100_codec_irq(int irq, void *data)
+{
+ struct ac100_codec *codec = data;
+ unsigned int val = 0;
+ int ret;
+
+ /* read status */
+ ret = regmap_read(codec->regmap, AC100_HMIC_STATUS, &val);
+ if (ret)
+ return IRQ_HANDLED;
+
+ if (val & AC100_HMIC_PULLOUT_PENDING) {
+ dev_info(codec->dev, "IRQ: Pull out");
+ }
+
+ if (val & AC100_HMIC_PLUGIN_PENDING) {
+ dev_info(codec->dev, "IRQ: Plug in");
+ }
+
+ if (val & AC100_HMIC_KEYUP_PENDING) {
+ dev_info(codec->dev, "IRQ: Key up");
+ }
+
+ if (val & AC100_HMIC_KEYDOWN_PENDING) {
+ dev_info(codec->dev, "IRQ: Key down");
+ }
+
+ if (val & AC100_HMIC_DATA_PENDING) {
+ dev_info(codec->dev, "IRQ: Data");
+ }
+
+ /* clear status */
+ ret = regmap_write(codec->regmap, AC100_HMIC_STATUS, 0);
+ if (ret)
+ return IRQ_HANDLED;
+
+ return IRQ_HANDLED;
+}
+
+static int ac100_codec_probe(struct platform_device *pdev)
+{
+ struct ac100_dev *ac100 = dev_get_drvdata(pdev->dev.parent);
+ struct ac100_codec *codec;
+ int ret;
+
+ codec = devm_kzalloc(&pdev->dev, sizeof(*codec), GFP_KERNEL);
+ if (!codec)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, codec);
+ codec->dev = &pdev->dev;
+ codec->regmap = ac100->regmap;
+
+ codec->irq = platform_get_irq(pdev, 0);
+ if (codec->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+ return codec->irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, codec->irq, NULL,
+ ac100_codec_irq,
+ IRQF_SHARED | IRQF_ONESHOT,
+ dev_name(&pdev->dev), codec);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not request IRQ\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ac100_codec_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct ac100_codec *codec = snd_soc_card_get_drvdata(card);
+
+ return 0;
+}
+
+static const struct of_device_id ac100_codec_of_match[] = {
+ { .compatible = "x-powers,ac100-codec" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ac100_codec_of_match);
+
+static struct platform_driver ac100_codec_driver = {
+ .driver = {
+ .name = "ac100-codec",
+ .of_match_table = ac100_codec_of_match,
+ },
+ .probe = ac100_codec_probe,
+ .remove = ac100_codec_remove,
+};
+module_platform_driver(ac100_codec_driver);
+
+MODULE_DESCRIPTION("X-Powers AC100 codec driver");
+MODULE_AUTHOR("Ondrej Jirman <megous@megous.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ac100-codec");