mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-19 11:04:00 +08:00
ASoC: Final updates for v3.16
A few more updates from the last week of development, nothing too exciting. Highlights include: - GPIO descriptor support for jacks - More updates and fixes to the Freescale SSI, Intel and rsnd drivers. - New drivers for Analog Devices ADAU1361, ADAU1381, ADAU1761 and ADAU1781, and Realtek RT5677. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTjZkHAAoJELSic+t+oim9pl0P/RTeNipwuUbFUWSYMcARc2wE Zpw+imtqjgE91ix5QR4OcQtL6+JtoOF7wfXA8dUmXRLrBqgSGDT/OJh771Jq4J7X LNTd7And4INeELeV7yajsDnHKD8P0V5Dmn+94HrjBgDuseELFn1izdGjM+0GpfKo i/C+595PtLSx3ekdYmsrXWyxgkUOrArhimiYKQzOtjncsGfXJCyhzvusXZQb3tCl Fa/HMTgMH8DlRInruN87s5CFr3O4seDB7LYOmjUIsPj4lorEFbqaGOUtPOCDJN1h tqMVuSIfbAEHX/ny9chsEYtMzOMPWk8s9TWn3LNfHkG8embkzaCaJqg8b8WIk/0U scqcKptarASYAGpSMu8IoSruC4+7GKtpo8zpGGJBclAMgmpXBSa381QnsiUGGocq BoBIjNSXzft3eRB0wjhGPLmJ5qMdHSEKuaDaACf2cot63ePF764cdg9EBItJLWEt G8nHQErUm4UfJapLvrDC+ItSNMLeaSJvCXrM1DPdfObqryKzJDbST/4B7m+w1ZGe 2Cnc536hkYdZ6kFdDgtIyK5yTeAgoxHzYNMndejt4bjkK7bnCIxa49tZV9d8LsTG g03cCEkkE4nCHWsSL891YBKfLLujTZoIY+f5M396FhLHBXL5krCtPRWE42I/xo58 wXH46Sd7HqDXxom5jpP+ =iPCP -----END PGP SIGNATURE----- Merge tag 'asoc-v3.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next ASoC: Final updates for v3.16 A few more updates from the last week of development, nothing too exciting. Highlights include: - GPIO descriptor support for jacks - More updates and fixes to the Freescale SSI, Intel and rsnd drivers. - New drivers for Analog Devices ADAU1361, ADAU1381, ADAU1761 and ADAU1781, and Realtek RT5677.
This commit is contained in:
commit
8743dcd663
@ -10,6 +10,12 @@ Required properties:
|
||||
|
||||
- interrupts : The CODEC's interrupt output.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks: The phandle of the master clock to the CODEC
|
||||
|
||||
- clock-names: Should be "mclk"
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* MIC1
|
||||
|
@ -8,6 +8,12 @@ Required properties:
|
||||
|
||||
- reg : The I2C address of the device.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks: The phandle of the master clock to the CODEC
|
||||
|
||||
- clock-names: Should be "mclk"
|
||||
|
||||
Example:
|
||||
|
||||
max98095: codec@11 {
|
||||
|
@ -20,6 +20,7 @@ Required properties:
|
||||
SSI subnode properties:
|
||||
- interrupts : Should contain SSI interrupt for PIO transfer
|
||||
- shared-pin : if shared clock pin
|
||||
- pio-transfer : use PIO transfer mode
|
||||
|
||||
SRC subnode properties:
|
||||
no properties at this point
|
||||
|
@ -15,6 +15,9 @@ Optional properties:
|
||||
Each entry is a pair of strings, the first being the
|
||||
connection's sink, the second being the connection's
|
||||
source.
|
||||
- simple-audio-card,mclk-fs : Multiplication factor between stream rate and codec
|
||||
mclk.
|
||||
|
||||
Optional subnodes:
|
||||
|
||||
- simple-audio-card,dai-link : Container for dai-link level
|
||||
|
109
include/linux/platform_data/adau17x1.h
Normal file
109
include/linux/platform_data/adau17x1.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961/ADAU1781/ADAU1781 codecs
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_PLATFORM_DATA_ADAU17X1_H__
|
||||
#define __LINUX_PLATFORM_DATA_ADAU17X1_H__
|
||||
|
||||
/**
|
||||
* enum adau17x1_micbias_voltage - Microphone bias voltage
|
||||
* @ADAU17X1_MICBIAS_0_90_AVDD: 0.9 * AVDD
|
||||
* @ADAU17X1_MICBIAS_0_65_AVDD: 0.65 * AVDD
|
||||
*/
|
||||
enum adau17x1_micbias_voltage {
|
||||
ADAU17X1_MICBIAS_0_90_AVDD = 0,
|
||||
ADAU17X1_MICBIAS_0_65_AVDD = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum adau1761_digmic_jackdet_pin_mode - Configuration of the JACKDET/MICIN pin
|
||||
* @ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: Disable the pin
|
||||
* @ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC: Configure the pin for usage as
|
||||
* digital microphone input.
|
||||
* @ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT: Configure the pin for jack
|
||||
* insertion detection.
|
||||
*/
|
||||
enum adau1761_digmic_jackdet_pin_mode {
|
||||
ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE,
|
||||
ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC,
|
||||
ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT,
|
||||
};
|
||||
|
||||
/**
|
||||
* adau1761_jackdetect_debounce_time - Jack insertion detection debounce time
|
||||
* @ADAU1761_JACKDETECT_DEBOUNCE_5MS: 5 milliseconds
|
||||
* @ADAU1761_JACKDETECT_DEBOUNCE_10MS: 10 milliseconds
|
||||
* @ADAU1761_JACKDETECT_DEBOUNCE_20MS: 20 milliseconds
|
||||
* @ADAU1761_JACKDETECT_DEBOUNCE_40MS: 40 milliseconds
|
||||
*/
|
||||
enum adau1761_jackdetect_debounce_time {
|
||||
ADAU1761_JACKDETECT_DEBOUNCE_5MS = 0,
|
||||
ADAU1761_JACKDETECT_DEBOUNCE_10MS = 1,
|
||||
ADAU1761_JACKDETECT_DEBOUNCE_20MS = 2,
|
||||
ADAU1761_JACKDETECT_DEBOUNCE_40MS = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum adau1761_output_mode - Output mode configuration
|
||||
* @ADAU1761_OUTPUT_MODE_HEADPHONE: Headphone output
|
||||
* @ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS: Capless headphone output
|
||||
* @ADAU1761_OUTPUT_MODE_LINE: Line output
|
||||
*/
|
||||
enum adau1761_output_mode {
|
||||
ADAU1761_OUTPUT_MODE_HEADPHONE,
|
||||
ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS,
|
||||
ADAU1761_OUTPUT_MODE_LINE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adau1761_platform_data - ADAU1761 Codec driver platform data
|
||||
* @input_differential: If true the input pins will be configured in
|
||||
* differential mode.
|
||||
* @lineout_mode: Output mode for the LOUT/ROUT pins
|
||||
* @headphone_mode: Output mode for the LHP/RHP pins
|
||||
* @digmic_jackdetect_pin_mode: JACKDET/MICIN pin configuration
|
||||
* @jackdetect_debounce_time: Jack insertion detection debounce time.
|
||||
* Note: This value will only be used, if the JACKDET/MICIN pin is configured
|
||||
* for jack insertion detection.
|
||||
* @jackdetect_active_low: If true the jack insertion detection is active low.
|
||||
* Othwise it will be active high.
|
||||
* @micbias_voltage: Microphone voltage bias
|
||||
*/
|
||||
struct adau1761_platform_data {
|
||||
bool input_differential;
|
||||
enum adau1761_output_mode lineout_mode;
|
||||
enum adau1761_output_mode headphone_mode;
|
||||
|
||||
enum adau1761_digmic_jackdet_pin_mode digmic_jackdetect_pin_mode;
|
||||
|
||||
enum adau1761_jackdetect_debounce_time jackdetect_debounce_time;
|
||||
bool jackdetect_active_low;
|
||||
|
||||
enum adau17x1_micbias_voltage micbias_voltage;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adau1781_platform_data - ADAU1781 Codec driver platform data
|
||||
* @left_input_differential: If true configure the left input as
|
||||
* differential input.
|
||||
* @right_input_differential: If true configure the right input as differntial
|
||||
* input.
|
||||
* @use_dmic: If true configure the MIC pins as digital microphone pins instead
|
||||
* of analog microphone pins.
|
||||
* @micbias_voltage: Microphone voltage bias
|
||||
*/
|
||||
struct adau1781_platform_data {
|
||||
bool left_input_differential;
|
||||
bool right_input_differential;
|
||||
|
||||
bool use_dmic;
|
||||
|
||||
enum adau17x1_micbias_voltage micbias_voltage;
|
||||
};
|
||||
|
||||
#endif
|
21
include/sound/rt5677.h
Normal file
21
include/sound/rt5677.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* linux/sound/rt5677.h -- Platform data for RT5677
|
||||
*
|
||||
* Copyright 2013 Realtek Semiconductor Corp.
|
||||
* Author: Oder Chiou <oder_chiou@realtek.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_SND_RT5677_H
|
||||
#define __LINUX_SND_RT5677_H
|
||||
|
||||
struct rt5677_platform_data {
|
||||
/* IN1 IN2 can optionally be differential */
|
||||
bool in1_diff;
|
||||
bool in2_diff;
|
||||
};
|
||||
|
||||
#endif
|
@ -452,6 +452,9 @@ int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage);
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
|
||||
struct snd_soc_jack_gpio *gpios);
|
||||
int snd_soc_jack_add_gpiods(struct device *gpiod_dev,
|
||||
struct snd_soc_jack *jack,
|
||||
int count, struct snd_soc_jack_gpio *gpios);
|
||||
void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
|
||||
struct snd_soc_jack_gpio *gpios);
|
||||
#else
|
||||
@ -461,6 +464,14 @@ static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int snd_soc_jack_add_gpiods(struct device *gpiod_dev,
|
||||
struct snd_soc_jack *jack,
|
||||
int count,
|
||||
struct snd_soc_jack_gpio *gpios)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
|
||||
struct snd_soc_jack_gpio *gpios)
|
||||
{
|
||||
@ -587,8 +598,12 @@ struct snd_soc_jack_zone {
|
||||
/**
|
||||
* struct snd_soc_jack_gpio - Describes a gpio pin for jack detection
|
||||
*
|
||||
* @gpio: gpio number
|
||||
* @name: gpio name
|
||||
* @gpio: legacy gpio number
|
||||
* @idx: gpio descriptor index within the function of the GPIO
|
||||
* consumer device
|
||||
* @gpiod_dev GPIO consumer device
|
||||
* @name: gpio name. Also as connection ID for the GPIO consumer
|
||||
* device function name lookup
|
||||
* @report: value to report when jack detected
|
||||
* @invert: report presence in low state
|
||||
* @debouce_time: debouce time in ms
|
||||
@ -599,6 +614,8 @@ struct snd_soc_jack_zone {
|
||||
*/
|
||||
struct snd_soc_jack_gpio {
|
||||
unsigned int gpio;
|
||||
unsigned int idx;
|
||||
struct device *gpiod_dev;
|
||||
const char *name;
|
||||
int report;
|
||||
int invert;
|
||||
@ -607,6 +624,7 @@ struct snd_soc_jack_gpio {
|
||||
|
||||
struct snd_soc_jack *jack;
|
||||
struct delayed_work work;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
void *data;
|
||||
int (*jack_status_check)(void *data);
|
||||
@ -1146,6 +1164,33 @@ static inline struct snd_soc_platform *snd_soc_component_to_platform(
|
||||
return container_of(component, struct snd_soc_platform, component);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_to_codec() - Casts a DAPM context to the CODEC it is embedded in
|
||||
* @dapm: The DAPM context to cast to the CODEC
|
||||
*
|
||||
* This function must only be used on DAPM contexts that are known to be part of
|
||||
* a CODEC (e.g. in a CODEC driver). Otherwise the behavior is undefined.
|
||||
*/
|
||||
static inline struct snd_soc_codec *snd_soc_dapm_to_codec(
|
||||
struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
return container_of(dapm, struct snd_soc_codec, dapm);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_to_platform() - Casts a DAPM context to the platform it is
|
||||
* embedded in
|
||||
* @dapm: The DAPM context to cast to the platform.
|
||||
*
|
||||
* This function must only be used on DAPM contexts that are known to be part of
|
||||
* a platform (e.g. in a platform driver). Otherwise the behavior is undefined.
|
||||
*/
|
||||
static inline struct snd_soc_platform *snd_soc_dapm_to_platform(
|
||||
struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
return container_of(dapm, struct snd_soc_platform, dapm);
|
||||
}
|
||||
|
||||
/* codec IO */
|
||||
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
|
||||
int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
|
@ -43,6 +43,32 @@ config SND_SOC_BFIN_EVAL_ADAU1373
|
||||
Note: This driver assumes that first ADAU1373 DAI is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1X61
|
||||
tristate "Support for the EVAL-ADAU1X61 board on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1761_I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1X61
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that the ADAU1X61 is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1X81
|
||||
tristate "Support for the EVAL-ADAU1X81 boards on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1781_I2C
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1X81
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that the ADAU1X81 is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAV80X
|
||||
tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
|
||||
|
@ -22,6 +22,8 @@ snd-ssm2602-objs := bf5xx-ssm2602.o
|
||||
snd-ad73311-objs := bf5xx-ad73311.o
|
||||
snd-ad193x-objs := bf5xx-ad193x.o
|
||||
snd-soc-bfin-eval-adau1373-objs := bfin-eval-adau1373.o
|
||||
snd-soc-bfin-eval-adau1x61-objs := bfin-eval-adau1x61.o
|
||||
snd-soc-bfin-eval-adau1x81-objs := bfin-eval-adau1x81.o
|
||||
snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
|
||||
snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
|
||||
|
||||
@ -31,5 +33,7 @@ obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
|
||||
obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1373) += snd-soc-bfin-eval-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) += snd-soc-bfin-eval-adau1x61.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X81) += snd-soc-bfin-eval-adau1x81.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o
|
||||
|
142
sound/soc/blackfin/bfin-eval-adau1x61.c
Normal file
142
sound/soc/blackfin/bfin-eval-adau1x61.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Machine driver for EVAL-ADAU1x61MINIZ on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau17x1.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1x61_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("In 1", NULL),
|
||||
SND_SOC_DAPM_LINE("In 2", NULL),
|
||||
SND_SOC_DAPM_LINE("In 3-4", NULL),
|
||||
|
||||
SND_SOC_DAPM_LINE("Diff Out L", NULL),
|
||||
SND_SOC_DAPM_LINE("Diff Out R", NULL),
|
||||
SND_SOC_DAPM_LINE("Stereo Out", NULL),
|
||||
SND_SOC_DAPM_HP("Capless HP Out", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1x61_dapm_routes[] = {
|
||||
{ "LAUX", NULL, "In 3-4" },
|
||||
{ "RAUX", NULL, "In 3-4" },
|
||||
{ "LINP", NULL, "In 1" },
|
||||
{ "LINN", NULL, "In 1"},
|
||||
{ "RINP", NULL, "In 2" },
|
||||
{ "RINN", NULL, "In 2" },
|
||||
|
||||
{ "In 1", NULL, "MICBIAS" },
|
||||
{ "In 2", NULL, "MICBIAS" },
|
||||
|
||||
{ "Capless HP Out", NULL, "LHP" },
|
||||
{ "Capless HP Out", NULL, "RHP" },
|
||||
{ "Diff Out L", NULL, "LOUT" },
|
||||
{ "Diff Out R", NULL, "ROUT" },
|
||||
{ "Stereo Out", NULL, "LOUT" },
|
||||
{ "Stereo Out", NULL, "ROUT" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x61_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int pll_rate;
|
||||
int ret;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 96000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
case 88200:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
|
||||
ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops bfin_eval_adau1x61_ops = {
|
||||
.hw_params = bfin_eval_adau1x61_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1x61_dai = {
|
||||
.name = "adau1x61",
|
||||
.stream_name = "adau1x61",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1761.0-0038",
|
||||
.ops = &bfin_eval_adau1x61_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1x61 = {
|
||||
.name = "bfin-eval-adau1x61",
|
||||
.driver_name = "eval-adau1x61",
|
||||
.dai_link = &bfin_eval_adau1x61_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1x61_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x61_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1x61_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x61_dapm_routes),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x61_probe(struct platform_device *pdev)
|
||||
{
|
||||
bfin_eval_adau1x61.dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x61);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1x61_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1x61",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1x61_probe,
|
||||
};
|
||||
module_platform_driver(bfin_eval_adau1x61_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1x61 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1x61");
|
130
sound/soc/blackfin/bfin-eval-adau1x81.c
Normal file
130
sound/soc/blackfin/bfin-eval-adau1x81.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Machine driver for EVAL-ADAU1x81 on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau17x1.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1x81_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Stereo In", NULL),
|
||||
SND_SOC_DAPM_LINE("Beep", NULL),
|
||||
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1x81_dapm_routes[] = {
|
||||
{ "BEEP", NULL, "Beep" },
|
||||
{ "LMIC", NULL, "Stereo In" },
|
||||
{ "LMIC", NULL, "Stereo In" },
|
||||
|
||||
{ "Headphone", NULL, "AOUTL" },
|
||||
{ "Headphone", NULL, "AOUTR" },
|
||||
{ "Speaker", NULL, "SP" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x81_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int pll_rate;
|
||||
int ret;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 96000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
case 88200:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU17X1_PLL,
|
||||
ADAU17X1_PLL_SRC_MCLK, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU17X1_CLK_SRC_PLL, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops bfin_eval_adau1x81_ops = {
|
||||
.hw_params = bfin_eval_adau1x81_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1x81_dai = {
|
||||
.name = "adau1x81",
|
||||
.stream_name = "adau1x81",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau-hifi",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1781.0-0038",
|
||||
.ops = &bfin_eval_adau1x81_ops,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1x81 = {
|
||||
.name = "bfin-eval-adau1x81",
|
||||
.driver_name = "eval-adau1x81",
|
||||
.dai_link = &bfin_eval_adau1x81_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1x81_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1x81_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1x81_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1x81_dapm_routes),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1x81_probe(struct platform_device *pdev)
|
||||
{
|
||||
bfin_eval_adau1x81.dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &bfin_eval_adau1x81);
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1x81_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1x81",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1x81_probe,
|
||||
};
|
||||
module_platform_driver(bfin_eval_adau1x81_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1x81 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1x81");
|
@ -23,6 +23,10 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_AD73311
|
||||
select SND_SOC_ADAU1373 if I2C
|
||||
select SND_SOC_ADAU1761_I2C if I2C
|
||||
select SND_SOC_ADAU1761_SPI if SPI
|
||||
select SND_SOC_ADAU1781_I2C if I2C
|
||||
select SND_SOC_ADAU1781_SPI if SPI
|
||||
select SND_SOC_ADAV801 if SPI_MASTER
|
||||
select SND_SOC_ADAV803 if I2C
|
||||
select SND_SOC_ADAU1977_SPI if SPI_MASTER
|
||||
@ -74,6 +78,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_RT5640 if I2C
|
||||
select SND_SOC_RT5645 if I2C
|
||||
select SND_SOC_RT5651 if I2C
|
||||
select SND_SOC_RT5677 if I2C
|
||||
select SND_SOC_SGTL5000 if I2C
|
||||
select SND_SOC_SI476X if MFD_SI476X_CORE
|
||||
select SND_SOC_SIRF_AUDIO_CODEC
|
||||
@ -214,13 +219,45 @@ config SND_SOC_AD1980
|
||||
config SND_SOC_AD73311
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1373
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1701
|
||||
tristate "Analog Devices ADAU1701 CODEC"
|
||||
depends on I2C
|
||||
select SND_SOC_SIGMADSP
|
||||
|
||||
config SND_SOC_ADAU1373
|
||||
config SND_SOC_ADAU17X1
|
||||
tristate
|
||||
select SND_SOC_SIGMADSP
|
||||
|
||||
config SND_SOC_ADAU1761
|
||||
tristate
|
||||
select SND_SOC_ADAU17X1
|
||||
|
||||
config SND_SOC_ADAU1761_I2C
|
||||
tristate
|
||||
select SND_SOC_ADAU1761
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_ADAU1761_SPI
|
||||
tristate
|
||||
select SND_SOC_ADAU1761
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_ADAU1781
|
||||
select SND_SOC_ADAU17X1
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1781_I2C
|
||||
tristate
|
||||
select SND_SOC_ADAU1781
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_ADAU1781_SPI
|
||||
tristate
|
||||
select SND_SOC_ADAU1781
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_ADAU1977
|
||||
tristate
|
||||
@ -274,6 +311,7 @@ config SND_SOC_AK5386
|
||||
|
||||
config SND_SOC_ALC5623
|
||||
tristate "Realtek ALC5623 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_ALC5632
|
||||
tristate
|
||||
@ -402,6 +440,15 @@ config SND_SOC_PCM512x_SPI
|
||||
select SND_SOC_PCM512x
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_RL6231
|
||||
tristate
|
||||
default y if SND_SOC_RT5640=y
|
||||
default y if SND_SOC_RT5645=y
|
||||
default y if SND_SOC_RT5651=y
|
||||
default m if SND_SOC_RT5640=m
|
||||
default m if SND_SOC_RT5645=m
|
||||
default m if SND_SOC_RT5651=m
|
||||
|
||||
config SND_SOC_RT5631
|
||||
tristate
|
||||
|
||||
@ -414,6 +461,9 @@ config SND_SOC_RT5645
|
||||
config SND_SOC_RT5651
|
||||
tristate
|
||||
|
||||
config SND_SOC_RT5677
|
||||
tristate
|
||||
|
||||
#Freescale sgtl5000 codec
|
||||
config SND_SOC_SGTL5000
|
||||
tristate "Freescale SGTL5000 CODEC"
|
||||
|
@ -7,8 +7,15 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o
|
||||
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
|
||||
snd-soc-ad1980-objs := ad1980.o
|
||||
snd-soc-ad73311-objs := ad73311.o
|
||||
snd-soc-adau1701-objs := adau1701.o
|
||||
snd-soc-adau1373-objs := adau1373.o
|
||||
snd-soc-adau1701-objs := adau1701.o
|
||||
snd-soc-adau17x1-objs := adau17x1.o
|
||||
snd-soc-adau1761-objs := adau1761.o
|
||||
snd-soc-adau1761-i2c-objs := adau1761-i2c.o
|
||||
snd-soc-adau1761-spi-objs := adau1761-spi.o
|
||||
snd-soc-adau1781-objs := adau1781.o
|
||||
snd-soc-adau1781-i2c-objs := adau1781-i2c.o
|
||||
snd-soc-adau1781-spi-objs := adau1781-spi.o
|
||||
snd-soc-adau1977-objs := adau1977.o
|
||||
snd-soc-adau1977-spi-objs := adau1977-spi.o
|
||||
snd-soc-adau1977-i2c-objs := adau1977-i2c.o
|
||||
@ -60,10 +67,12 @@ snd-soc-pcm3008-objs := pcm3008.o
|
||||
snd-soc-pcm512x-objs := pcm512x.o
|
||||
snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
|
||||
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
|
||||
snd-soc-rl6231-objs := rl6231.o
|
||||
snd-soc-rt5631-objs := rt5631.o
|
||||
snd-soc-rt5640-objs := rt5640.o
|
||||
snd-soc-rt5645-objs := rt5645.o
|
||||
snd-soc-rt5651-objs := rt5651.o
|
||||
snd-soc-rt5677-objs := rt5677.o
|
||||
snd-soc-sgtl5000-objs := sgtl5000.o
|
||||
snd-soc-alc5623-objs := alc5623.o
|
||||
snd-soc-alc5632-objs := alc5632.o
|
||||
@ -162,10 +171,17 @@ obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
|
||||
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1761) += snd-soc-adau1761.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1761_I2C) += snd-soc-adau1761-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1761_SPI) += snd-soc-adau1761-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1781) += snd-soc-adau1781.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1781_I2C) += snd-soc-adau1781-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1781_SPI) += snd-soc-adau1781-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
|
||||
@ -216,10 +232,12 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
|
||||
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
|
||||
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
|
||||
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
|
||||
obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
|
||||
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
|
||||
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
|
||||
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
|
||||
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
|
||||
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
|
||||
|
60
sound/soc/codecs/adau1761-i2c.c
Normal file
60
sound/soc/codecs/adau1761-i2c.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1761.h"
|
||||
|
||||
static int adau1761_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = adau1761_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 16;
|
||||
|
||||
return adau1761_probe(&client->dev,
|
||||
devm_regmap_init_i2c(client, &config),
|
||||
id->driver_data, NULL);
|
||||
}
|
||||
|
||||
static int adau1761_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adau1761_i2c_ids[] = {
|
||||
{ "adau1361", ADAU1361 },
|
||||
{ "adau1461", ADAU1761 },
|
||||
{ "adau1761", ADAU1761 },
|
||||
{ "adau1961", ADAU1361 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids);
|
||||
|
||||
static struct i2c_driver adau1761_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adau1761",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1761_i2c_probe,
|
||||
.remove = adau1761_i2c_remove,
|
||||
.id_table = adau1761_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(adau1761_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC I2C driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
77
sound/soc/codecs/adau1761-spi.c
Normal file
77
sound/soc/codecs/adau1761-spi.c
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1761.h"
|
||||
|
||||
static void adau1761_spi_switch_mode(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
/*
|
||||
* To get the device into SPI mode CLATCH has to be pulled low three
|
||||
* times. Do this by issuing three dummy reads.
|
||||
*/
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
}
|
||||
|
||||
static int adau1761_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct regmap_config config;
|
||||
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
config = adau1761_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 24;
|
||||
config.read_flag_mask = 0x1;
|
||||
|
||||
return adau1761_probe(&spi->dev,
|
||||
devm_regmap_init_spi(spi, &config),
|
||||
id->driver_data, adau1761_spi_switch_mode);
|
||||
}
|
||||
|
||||
static int adau1761_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id adau1761_spi_id[] = {
|
||||
{ "adau1361", ADAU1361 },
|
||||
{ "adau1461", ADAU1761 },
|
||||
{ "adau1761", ADAU1761 },
|
||||
{ "adau1961", ADAU1361 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adau1761_spi_id);
|
||||
|
||||
static struct spi_driver adau1761_spi_driver = {
|
||||
.driver = {
|
||||
.name = "adau1761",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1761_spi_probe,
|
||||
.remove = adau1761_spi_remove,
|
||||
.id_table = adau1761_spi_id,
|
||||
};
|
||||
module_spi_driver(adau1761_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC SPI driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
803
sound/soc/codecs/adau1761.c
Normal file
803
sound/soc/codecs/adau1761.c
Normal file
@ -0,0 +1,803 @@
|
||||
/*
|
||||
* Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec
|
||||
*
|
||||
* Copyright 2011-2013 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/platform_data/adau17x1.h>
|
||||
|
||||
#include "adau17x1.h"
|
||||
#include "adau1761.h"
|
||||
|
||||
#define ADAU1761_DIGMIC_JACKDETECT 0x4008
|
||||
#define ADAU1761_REC_MIXER_LEFT0 0x400a
|
||||
#define ADAU1761_REC_MIXER_LEFT1 0x400b
|
||||
#define ADAU1761_REC_MIXER_RIGHT0 0x400c
|
||||
#define ADAU1761_REC_MIXER_RIGHT1 0x400d
|
||||
#define ADAU1761_LEFT_DIFF_INPUT_VOL 0x400e
|
||||
#define ADAU1761_RIGHT_DIFF_INPUT_VOL 0x400f
|
||||
#define ADAU1761_PLAY_LR_MIXER_LEFT 0x4020
|
||||
#define ADAU1761_PLAY_MIXER_LEFT0 0x401c
|
||||
#define ADAU1761_PLAY_MIXER_LEFT1 0x401d
|
||||
#define ADAU1761_PLAY_MIXER_RIGHT0 0x401e
|
||||
#define ADAU1761_PLAY_MIXER_RIGHT1 0x401f
|
||||
#define ADAU1761_PLAY_LR_MIXER_RIGHT 0x4021
|
||||
#define ADAU1761_PLAY_MIXER_MONO 0x4022
|
||||
#define ADAU1761_PLAY_HP_LEFT_VOL 0x4023
|
||||
#define ADAU1761_PLAY_HP_RIGHT_VOL 0x4024
|
||||
#define ADAU1761_PLAY_LINE_LEFT_VOL 0x4025
|
||||
#define ADAU1761_PLAY_LINE_RIGHT_VOL 0x4026
|
||||
#define ADAU1761_PLAY_MONO_OUTPUT_VOL 0x4027
|
||||
#define ADAU1761_POP_CLICK_SUPPRESS 0x4028
|
||||
#define ADAU1761_JACK_DETECT_PIN 0x4031
|
||||
#define ADAU1761_DEJITTER 0x4036
|
||||
#define ADAU1761_CLK_ENABLE0 0x40f9
|
||||
#define ADAU1761_CLK_ENABLE1 0x40fa
|
||||
|
||||
#define ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW BIT(0)
|
||||
#define ADAU1761_DIGMIC_JACKDETECT_DIGMIC BIT(5)
|
||||
|
||||
#define ADAU1761_DIFF_INPUT_VOL_LDEN BIT(0)
|
||||
|
||||
#define ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP BIT(0)
|
||||
#define ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE BIT(1)
|
||||
|
||||
#define ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP BIT(0)
|
||||
|
||||
#define ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP BIT(0)
|
||||
|
||||
#define ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP BIT(0)
|
||||
|
||||
|
||||
#define ADAU1761_FIRMWARE "adau1761.bin"
|
||||
|
||||
static const struct reg_default adau1761_reg_defaults[] = {
|
||||
{ ADAU1761_DEJITTER, 0x03 },
|
||||
{ ADAU1761_DIGMIC_JACKDETECT, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_LEFT0, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_LEFT1, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_RIGHT0, 0x00 },
|
||||
{ ADAU1761_REC_MIXER_RIGHT1, 0x00 },
|
||||
{ ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 },
|
||||
{ ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_LEFT0, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_LEFT1, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_RIGHT0, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_RIGHT1, 0x00 },
|
||||
{ ADAU1761_PLAY_LR_MIXER_RIGHT, 0x00 },
|
||||
{ ADAU1761_PLAY_MIXER_MONO, 0x00 },
|
||||
{ ADAU1761_PLAY_HP_LEFT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_HP_RIGHT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_LINE_LEFT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_LINE_RIGHT_VOL, 0x00 },
|
||||
{ ADAU1761_PLAY_MONO_OUTPUT_VOL, 0x00 },
|
||||
{ ADAU1761_POP_CLICK_SUPPRESS, 0x00 },
|
||||
{ ADAU1761_JACK_DETECT_PIN, 0x00 },
|
||||
{ ADAU1761_CLK_ENABLE0, 0x00 },
|
||||
{ ADAU1761_CLK_ENABLE1, 0x00 },
|
||||
{ ADAU17X1_CLOCK_CONTROL, 0x00 },
|
||||
{ ADAU17X1_PLL_CONTROL, 0x00 },
|
||||
{ ADAU17X1_REC_POWER_MGMT, 0x00 },
|
||||
{ ADAU17X1_MICBIAS, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT0, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT1, 0x00 },
|
||||
{ ADAU17X1_CONVERTER0, 0x00 },
|
||||
{ ADAU17X1_CONVERTER1, 0x00 },
|
||||
{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
|
||||
{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
|
||||
{ ADAU17X1_ADC_CONTROL, 0x00 },
|
||||
{ ADAU17X1_PLAY_POWER_MGMT, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL0, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL1, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL2, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT_PAD, 0xaa },
|
||||
{ ADAU17X1_CONTROL_PORT_PAD0, 0xaa },
|
||||
{ ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
|
||||
{ ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
|
||||
{ ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
|
||||
{ ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
|
||||
{ ADAU17X1_DSP_ENABLE, 0x00 },
|
||||
{ ADAU17X1_DSP_RUN, 0x00 },
|
||||
{ ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_diff_in_tlv, -1200, 75, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_out_tlv, -5700, 100, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_sidetone_tlv, -1800, 300, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_boost_tlv, -600, 600, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(adau1761_pga_boost_tlv, -2000, 2000, 1);
|
||||
|
||||
static const unsigned int adau1761_bias_select_values[] = {
|
||||
0, 2, 3,
|
||||
};
|
||||
|
||||
static const char * const adau1761_bias_select_text[] = {
|
||||
"Normal operation", "Enhanced performance", "Power saving",
|
||||
};
|
||||
|
||||
static const char * const adau1761_bias_select_extreme_text[] = {
|
||||
"Normal operation", "Extreme power saving", "Enhanced performance",
|
||||
"Power saving",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_adc_bias_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 3, adau1761_bias_select_extreme_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_hp_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 6, adau1761_bias_select_extreme_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_dac_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 4, adau1761_bias_select_extreme_text);
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_playback_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 2, 0x3, adau1761_bias_select_text,
|
||||
adau1761_bias_select_values);
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(adau1761_capture_bias_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 1, 0x3, adau1761_bias_select_text,
|
||||
adau1761_bias_select_values);
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_jack_detect_controls[] = {
|
||||
SOC_SINGLE("Speaker Auto-mute Switch", ADAU1761_DIGMIC_JACKDETECT,
|
||||
4, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_differential_mode_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Capture Volume", ADAU1761_LEFT_DIFF_INPUT_VOL,
|
||||
ADAU1761_RIGHT_DIFF_INPUT_VOL, 2, 0x3f, 0,
|
||||
adau1761_diff_in_tlv),
|
||||
SOC_DOUBLE_R("Capture Switch", ADAU1761_LEFT_DIFF_INPUT_VOL,
|
||||
ADAU1761_RIGHT_DIFF_INPUT_VOL, 1, 1, 0),
|
||||
|
||||
SOC_DOUBLE_R_TLV("PGA Boost Capture Volume", ADAU1761_REC_MIXER_LEFT1,
|
||||
ADAU1761_REC_MIXER_RIGHT1, 3, 2, 0, adau1761_pga_boost_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_single_mode_controls[] = {
|
||||
SOC_SINGLE_TLV("Input 1 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
|
||||
4, 7, 0, adau1761_sing_in_tlv),
|
||||
SOC_SINGLE_TLV("Input 2 Capture Volume", ADAU1761_REC_MIXER_LEFT0,
|
||||
1, 7, 0, adau1761_sing_in_tlv),
|
||||
SOC_SINGLE_TLV("Input 3 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
|
||||
4, 7, 0, adau1761_sing_in_tlv),
|
||||
SOC_SINGLE_TLV("Input 4 Capture Volume", ADAU1761_REC_MIXER_RIGHT0,
|
||||
1, 7, 0, adau1761_sing_in_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Aux Capture Volume", ADAU1761_REC_MIXER_LEFT1,
|
||||
ADAU1761_REC_MIXER_RIGHT1, 0, 7, 0, adau1761_sing_in_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("Headphone Playback Volume", ADAU1761_PLAY_HP_LEFT_VOL,
|
||||
ADAU1761_PLAY_HP_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
|
||||
SOC_DOUBLE_R("Headphone Playback Switch", ADAU1761_PLAY_HP_LEFT_VOL,
|
||||
ADAU1761_PLAY_HP_RIGHT_VOL, 1, 1, 0),
|
||||
SOC_DOUBLE_R_TLV("Lineout Playback Volume", ADAU1761_PLAY_LINE_LEFT_VOL,
|
||||
ADAU1761_PLAY_LINE_RIGHT_VOL, 2, 0x3f, 0, adau1761_out_tlv),
|
||||
SOC_DOUBLE_R("Lineout Playback Switch", ADAU1761_PLAY_LINE_LEFT_VOL,
|
||||
ADAU1761_PLAY_LINE_RIGHT_VOL, 1, 1, 0),
|
||||
|
||||
SOC_ENUM("ADC Bias", adau1761_adc_bias_enum),
|
||||
SOC_ENUM("DAC Bias", adau1761_dac_bias_enum),
|
||||
SOC_ENUM("Capture Bias", adau1761_capture_bias_enum),
|
||||
SOC_ENUM("Playback Bias", adau1761_playback_bias_enum),
|
||||
SOC_ENUM("Headphone Bias", adau1761_hp_bias_enum),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_mono_controls[] = {
|
||||
SOC_SINGLE_TLV("Mono Playback Volume", ADAU1761_PLAY_MONO_OUTPUT_VOL,
|
||||
2, 0x3f, 0, adau1761_out_tlv),
|
||||
SOC_SINGLE("Mono Playback Switch", ADAU1761_PLAY_MONO_OUTPUT_VOL,
|
||||
1, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_left_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
|
||||
ADAU1761_PLAY_MIXER_LEFT0, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
|
||||
ADAU1761_PLAY_MIXER_LEFT0, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_LEFT0, 1, 8, 0, adau1761_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_LEFT1, 4, 8, 0, adau1761_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_LEFT1, 0, 8, 0, adau1761_sidetone_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_right_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Left DAC Switch",
|
||||
ADAU1761_PLAY_MIXER_RIGHT0, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Right DAC Switch",
|
||||
ADAU1761_PLAY_MIXER_RIGHT0, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Aux Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_RIGHT0, 1, 8, 0, adau1761_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Right Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_RIGHT1, 4, 8, 0, adau1761_sidetone_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Left Bypass Volume",
|
||||
ADAU1761_PLAY_MIXER_RIGHT1, 0, 8, 0, adau1761_sidetone_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_left_lr_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_TLV("Left Volume",
|
||||
ADAU1761_PLAY_LR_MIXER_LEFT, 1, 2, 0, adau1761_boost_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Right Volume",
|
||||
ADAU1761_PLAY_LR_MIXER_LEFT, 3, 2, 0, adau1761_boost_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_right_lr_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_TLV("Left Volume",
|
||||
ADAU1761_PLAY_LR_MIXER_RIGHT, 1, 2, 0, adau1761_boost_tlv),
|
||||
SOC_DAPM_SINGLE_TLV("Right Volume",
|
||||
ADAU1761_PLAY_LR_MIXER_RIGHT, 3, 2, 0, adau1761_boost_tlv),
|
||||
};
|
||||
|
||||
static const char * const adau1761_input_mux_text[] = {
|
||||
"ADC", "DMIC",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau1761_input_mux_enum,
|
||||
ADAU17X1_ADC_CONTROL, 2, adau1761_input_mux_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau1761_input_mux_control =
|
||||
SOC_DAPM_ENUM("Input Select", adau1761_input_mux_enum);
|
||||
|
||||
static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
|
||||
|
||||
/* After any power changes have been made the dejitter circuit
|
||||
* has to be reinitialized. */
|
||||
regmap_write(adau->regmap, ADAU1761_DEJITTER, 0);
|
||||
if (!adau->master)
|
||||
regmap_write(adau->regmap, ADAU1761_DEJITTER, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1x61_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MIXER("Left Input Mixer", ADAU1761_REC_MIXER_LEFT0, 0, 0,
|
||||
NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("Right Input Mixer", ADAU1761_REC_MIXER_RIGHT0, 0, 0,
|
||||
NULL, 0),
|
||||
|
||||
SOC_MIXER_ARRAY("Left Playback Mixer", ADAU1761_PLAY_MIXER_LEFT0,
|
||||
0, 0, adau1761_left_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Right Playback Mixer", ADAU1761_PLAY_MIXER_RIGHT0,
|
||||
0, 0, adau1761_right_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Left LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_LEFT,
|
||||
0, 0, adau1761_left_lr_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Right LR Playback Mixer", ADAU1761_PLAY_LR_MIXER_RIGHT,
|
||||
0, 0, adau1761_right_lr_mixer_controls),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Headphone", ADAU1761_PLAY_HP_LEFT_VOL,
|
||||
0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY_S("SYSCLK", 2, SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_POST("Dejitter fixup", adau1761_dejitter_fixup),
|
||||
|
||||
SND_SOC_DAPM_INPUT("LAUX"),
|
||||
SND_SOC_DAPM_INPUT("RAUX"),
|
||||
SND_SOC_DAPM_INPUT("LINP"),
|
||||
SND_SOC_DAPM_INPUT("LINN"),
|
||||
SND_SOC_DAPM_INPUT("RINP"),
|
||||
SND_SOC_DAPM_INPUT("RINN"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("LOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT"),
|
||||
SND_SOC_DAPM_OUTPUT("LHP"),
|
||||
SND_SOC_DAPM_OUTPUT("RHP"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1761_mono_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MIXER("Mono Playback Mixer", ADAU1761_PLAY_MIXER_MONO,
|
||||
0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("MONOOUT"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1761_capless_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY_S("Headphone VGND", 1, ADAU1761_PLAY_MIXER_MONO,
|
||||
0, 0, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1x61_dapm_routes[] = {
|
||||
{ "Left Input Mixer", NULL, "LINP" },
|
||||
{ "Left Input Mixer", NULL, "LINN" },
|
||||
{ "Left Input Mixer", NULL, "LAUX" },
|
||||
|
||||
{ "Right Input Mixer", NULL, "RINP" },
|
||||
{ "Right Input Mixer", NULL, "RINN" },
|
||||
{ "Right Input Mixer", NULL, "RAUX" },
|
||||
|
||||
{ "Left Playback Mixer", NULL, "Left Playback Enable"},
|
||||
{ "Right Playback Mixer", NULL, "Right Playback Enable"},
|
||||
{ "Left LR Playback Mixer", NULL, "Left Playback Enable"},
|
||||
{ "Right LR Playback Mixer", NULL, "Right Playback Enable"},
|
||||
|
||||
{ "Left Playback Mixer", "Left DAC Switch", "Left DAC" },
|
||||
{ "Left Playback Mixer", "Right DAC Switch", "Right DAC" },
|
||||
|
||||
{ "Right Playback Mixer", "Left DAC Switch", "Left DAC" },
|
||||
{ "Right Playback Mixer", "Right DAC Switch", "Right DAC" },
|
||||
|
||||
{ "Left LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
|
||||
{ "Left LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
|
||||
|
||||
{ "Right LR Playback Mixer", "Left Volume", "Left Playback Mixer" },
|
||||
{ "Right LR Playback Mixer", "Right Volume", "Right Playback Mixer" },
|
||||
|
||||
{ "LHP", NULL, "Left Playback Mixer" },
|
||||
{ "RHP", NULL, "Right Playback Mixer" },
|
||||
|
||||
{ "LHP", NULL, "Headphone" },
|
||||
{ "RHP", NULL, "Headphone" },
|
||||
|
||||
{ "LOUT", NULL, "Left LR Playback Mixer" },
|
||||
{ "ROUT", NULL, "Right LR Playback Mixer" },
|
||||
|
||||
{ "Left Playback Mixer", "Aux Bypass Volume", "LAUX" },
|
||||
{ "Left Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
|
||||
{ "Left Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
|
||||
{ "Right Playback Mixer", "Aux Bypass Volume", "RAUX" },
|
||||
{ "Right Playback Mixer", "Left Bypass Volume", "Left Input Mixer" },
|
||||
{ "Right Playback Mixer", "Right Bypass Volume", "Right Input Mixer" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_mono_dapm_routes[] = {
|
||||
{ "Mono Playback Mixer", NULL, "Left Playback Mixer" },
|
||||
{ "Mono Playback Mixer", NULL, "Right Playback Mixer" },
|
||||
|
||||
{ "MONOOUT", NULL, "Mono Playback Mixer" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_capless_dapm_routes[] = {
|
||||
{ "Headphone", NULL, "Headphone VGND" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1761_dmic_widgets[] = {
|
||||
SND_SOC_DAPM_MUX("Left Decimator Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau1761_input_mux_control),
|
||||
SND_SOC_DAPM_MUX("Right Decimator Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau1761_input_mux_control),
|
||||
|
||||
SND_SOC_DAPM_INPUT("DMIC"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_dmic_routes[] = {
|
||||
{ "Left Decimator Mux", "ADC", "Left Input Mixer" },
|
||||
{ "Left Decimator Mux", "DMIC", "DMIC" },
|
||||
{ "Right Decimator Mux", "ADC", "Right Input Mixer" },
|
||||
{ "Right Decimator Mux", "DMIC", "DMIC" },
|
||||
|
||||
{ "Left Decimator", NULL, "Left Decimator Mux" },
|
||||
{ "Right Decimator", NULL, "Right Decimator Mux" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_no_dmic_routes[] = {
|
||||
{ "Left Decimator", NULL, "Left Input Mixer" },
|
||||
{ "Right Decimator", NULL, "Right Input Mixer" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1761_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("Serial Port Clock", ADAU1761_CLK_ENABLE0,
|
||||
0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Serial Input Routing Clock", ADAU1761_CLK_ENABLE0,
|
||||
1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Serial Output Routing Clock", ADAU1761_CLK_ENABLE0,
|
||||
3, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Decimator Resync Clock", ADAU1761_CLK_ENABLE0,
|
||||
4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Interpolator Resync Clock", ADAU1761_CLK_ENABLE0,
|
||||
2, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Slew Clock", ADAU1761_CLK_ENABLE0, 6, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY_S("Digital Clock 0", 1, ADAU1761_CLK_ENABLE1,
|
||||
0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("Digital Clock 1", 1, ADAU1761_CLK_ENABLE1,
|
||||
1, 0, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1761_dapm_routes[] = {
|
||||
{ "Left Decimator", NULL, "Digital Clock 0", },
|
||||
{ "Right Decimator", NULL, "Digital Clock 0", },
|
||||
{ "Left DAC", NULL, "Digital Clock 0", },
|
||||
{ "Right DAC", NULL, "Digital Clock 0", },
|
||||
|
||||
{ "AIFCLK", NULL, "Digital Clock 1" },
|
||||
|
||||
{ "Playback", NULL, "Serial Port Clock" },
|
||||
{ "Capture", NULL, "Serial Port Clock" },
|
||||
{ "Playback", NULL, "Serial Input Routing Clock" },
|
||||
{ "Capture", NULL, "Serial Output Routing Clock" },
|
||||
|
||||
{ "Left Decimator", NULL, "Decimator Resync Clock" },
|
||||
{ "Right Decimator", NULL, "Decimator Resync Clock" },
|
||||
{ "Left DAC", NULL, "Interpolator Resync Clock" },
|
||||
{ "Right DAC", NULL, "Interpolator Resync Clock" },
|
||||
|
||||
{ "DSP", NULL, "Digital Clock 0" },
|
||||
|
||||
{ "Slew Clock", NULL, "Digital Clock 0" },
|
||||
{ "Right Playback Mixer", NULL, "Slew Clock" },
|
||||
{ "Left Playback Mixer", NULL, "Slew Clock" },
|
||||
|
||||
{ "Digital Clock 0", NULL, "SYSCLK" },
|
||||
{ "Digital Clock 1", NULL, "SYSCLK" },
|
||||
};
|
||||
|
||||
static int adau1761_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
|
||||
break;
|
||||
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum adau1761_output_mode adau1761_get_lineout_mode(
|
||||
struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1761_platform_data *pdata = codec->dev->platform_data;
|
||||
|
||||
if (pdata)
|
||||
return pdata->lineout_mode;
|
||||
|
||||
return ADAU1761_OUTPUT_MODE_LINE;
|
||||
}
|
||||
|
||||
static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1761_platform_data *pdata = codec->dev->platform_data;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
enum adau1761_digmic_jackdet_pin_mode mode;
|
||||
unsigned int val = 0;
|
||||
int ret;
|
||||
|
||||
if (pdata)
|
||||
mode = pdata->digmic_jackdetect_pin_mode;
|
||||
else
|
||||
mode = ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE;
|
||||
|
||||
switch (mode) {
|
||||
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_JACKDETECT:
|
||||
switch (pdata->jackdetect_debounce_time) {
|
||||
case ADAU1761_JACKDETECT_DEBOUNCE_5MS:
|
||||
case ADAU1761_JACKDETECT_DEBOUNCE_10MS:
|
||||
case ADAU1761_JACKDETECT_DEBOUNCE_20MS:
|
||||
case ADAU1761_JACKDETECT_DEBOUNCE_40MS:
|
||||
val |= pdata->jackdetect_debounce_time << 6;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pdata->jackdetect_active_low)
|
||||
val |= ADAU1761_DIGMIC_JACKDETECT_ACTIVE_LOW;
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec,
|
||||
adau1761_jack_detect_controls,
|
||||
ARRAY_SIZE(adau1761_jack_detect_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_no_dmic_routes,
|
||||
ARRAY_SIZE(adau1761_no_dmic_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1761_dmic_widgets,
|
||||
ARRAY_SIZE(adau1761_dmic_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_dmic_routes,
|
||||
ARRAY_SIZE(adau1761_dmic_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val |= ADAU1761_DIGMIC_JACKDETECT_DIGMIC;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_write(adau->regmap, ADAU1761_DIGMIC_JACKDETECT, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
struct adau1761_platform_data *pdata = codec->dev->platform_data;
|
||||
enum adau1761_output_mode mode;
|
||||
int ret;
|
||||
|
||||
if (pdata)
|
||||
mode = pdata->headphone_mode;
|
||||
else
|
||||
mode = ADAU1761_OUTPUT_MODE_HEADPHONE;
|
||||
|
||||
switch (mode) {
|
||||
case ADAU1761_OUTPUT_MODE_LINE:
|
||||
break;
|
||||
case ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS:
|
||||
regmap_update_bits(adau->regmap, ADAU1761_PLAY_MONO_OUTPUT_VOL,
|
||||
ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
|
||||
ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE,
|
||||
ADAU1761_PLAY_MONO_OUTPUT_VOL_MODE_HP |
|
||||
ADAU1761_PLAY_MONO_OUTPUT_VOL_UNMUTE);
|
||||
/* fallthrough */
|
||||
case ADAU1761_OUTPUT_MODE_HEADPHONE:
|
||||
regmap_update_bits(adau->regmap, ADAU1761_PLAY_HP_RIGHT_VOL,
|
||||
ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP,
|
||||
ADAU1761_PLAY_HP_RIGHT_VOL_MODE_HP);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1761_capless_dapm_widgets,
|
||||
ARRAY_SIZE(adau1761_capless_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_capless_dapm_routes,
|
||||
ARRAY_SIZE(adau1761_capless_dapm_routes));
|
||||
} else {
|
||||
ret = snd_soc_add_codec_controls(codec, adau1761_mono_controls,
|
||||
ARRAY_SIZE(adau1761_mono_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1761_mono_dapm_widgets,
|
||||
ARRAY_SIZE(adau1761_mono_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_mono_dapm_routes,
|
||||
ARRAY_SIZE(adau1761_mono_dapm_routes));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool adau1761_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU1761_DIGMIC_JACKDETECT:
|
||||
case ADAU1761_REC_MIXER_LEFT0:
|
||||
case ADAU1761_REC_MIXER_LEFT1:
|
||||
case ADAU1761_REC_MIXER_RIGHT0:
|
||||
case ADAU1761_REC_MIXER_RIGHT1:
|
||||
case ADAU1761_LEFT_DIFF_INPUT_VOL:
|
||||
case ADAU1761_RIGHT_DIFF_INPUT_VOL:
|
||||
case ADAU1761_PLAY_LR_MIXER_LEFT:
|
||||
case ADAU1761_PLAY_MIXER_LEFT0:
|
||||
case ADAU1761_PLAY_MIXER_LEFT1:
|
||||
case ADAU1761_PLAY_MIXER_RIGHT0:
|
||||
case ADAU1761_PLAY_MIXER_RIGHT1:
|
||||
case ADAU1761_PLAY_LR_MIXER_RIGHT:
|
||||
case ADAU1761_PLAY_MIXER_MONO:
|
||||
case ADAU1761_PLAY_HP_LEFT_VOL:
|
||||
case ADAU1761_PLAY_HP_RIGHT_VOL:
|
||||
case ADAU1761_PLAY_LINE_LEFT_VOL:
|
||||
case ADAU1761_PLAY_LINE_RIGHT_VOL:
|
||||
case ADAU1761_PLAY_MONO_OUTPUT_VOL:
|
||||
case ADAU1761_POP_CLICK_SUPPRESS:
|
||||
case ADAU1761_JACK_DETECT_PIN:
|
||||
case ADAU1761_DEJITTER:
|
||||
case ADAU1761_CLK_ENABLE0:
|
||||
case ADAU1761_CLK_ENABLE1:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return adau17x1_readable_register(dev, reg);
|
||||
}
|
||||
|
||||
static int adau1761_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1761_platform_data *pdata = codec->dev->platform_data;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_add_widgets(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (pdata && pdata->input_differential) {
|
||||
regmap_update_bits(adau->regmap, ADAU1761_LEFT_DIFF_INPUT_VOL,
|
||||
ADAU1761_DIFF_INPUT_VOL_LDEN,
|
||||
ADAU1761_DIFF_INPUT_VOL_LDEN);
|
||||
regmap_update_bits(adau->regmap, ADAU1761_RIGHT_DIFF_INPUT_VOL,
|
||||
ADAU1761_DIFF_INPUT_VOL_LDEN,
|
||||
ADAU1761_DIFF_INPUT_VOL_LDEN);
|
||||
ret = snd_soc_add_codec_controls(codec,
|
||||
adau1761_differential_mode_controls,
|
||||
ARRAY_SIZE(adau1761_differential_mode_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = snd_soc_add_codec_controls(codec,
|
||||
adau1761_single_mode_controls,
|
||||
ARRAY_SIZE(adau1761_single_mode_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (adau1761_get_lineout_mode(codec)) {
|
||||
case ADAU1761_OUTPUT_MODE_LINE:
|
||||
break;
|
||||
case ADAU1761_OUTPUT_MODE_HEADPHONE:
|
||||
regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_LEFT_VOL,
|
||||
ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP,
|
||||
ADAU1761_PLAY_LINE_LEFT_VOL_MODE_HP);
|
||||
regmap_update_bits(adau->regmap, ADAU1761_PLAY_LINE_RIGHT_VOL,
|
||||
ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP,
|
||||
ADAU1761_PLAY_LINE_RIGHT_VOL_MODE_HP);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = adau1761_setup_headphone_mode(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adau1761_setup_digmic_jackdetect(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adau->type == ADAU1761) {
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1761_dapm_widgets,
|
||||
ARRAY_SIZE(adau1761_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1761_dapm_routes,
|
||||
ARRAY_SIZE(adau1761_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adau17x1_load_firmware(adau, codec->dev,
|
||||
ADAU1761_FIRMWARE);
|
||||
if (ret)
|
||||
dev_warn(codec->dev, "Failed to firmware\n");
|
||||
}
|
||||
|
||||
ret = adau17x1_add_routes(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver adau1761_codec_driver = {
|
||||
.probe = adau1761_codec_probe,
|
||||
.suspend = adau17x1_suspend,
|
||||
.resume = adau17x1_resume,
|
||||
.set_bias_level = adau1761_set_bias_level,
|
||||
|
||||
.controls = adau1761_controls,
|
||||
.num_controls = ARRAY_SIZE(adau1761_controls),
|
||||
.dapm_widgets = adau1x61_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adau1x61_dapm_widgets),
|
||||
.dapm_routes = adau1x61_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(adau1x61_dapm_routes),
|
||||
};
|
||||
|
||||
#define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static struct snd_soc_dai_driver adau1361_dai_driver = {
|
||||
.name = "adau-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1761_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1761_FORMATS,
|
||||
},
|
||||
.ops = &adau17x1_dai_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver adau1761_dai_driver = {
|
||||
.name = "adau-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1761_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1761_FORMATS,
|
||||
},
|
||||
.ops = &adau17x1_dai_ops,
|
||||
};
|
||||
|
||||
int adau1761_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
{
|
||||
struct snd_soc_dai_driver *dai_drv;
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_probe(dev, regmap, type, switch_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (type == ADAU1361)
|
||||
dai_drv = &adau1361_dai_driver;
|
||||
else
|
||||
dai_drv = &adau1761_dai_driver;
|
||||
|
||||
return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau1761_probe);
|
||||
|
||||
const struct regmap_config adau1761_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 16,
|
||||
.max_register = 0x40fa,
|
||||
.reg_defaults = adau1761_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
|
||||
.readable_reg = adau1761_readable_register,
|
||||
.volatile_reg = adau17x1_volatile_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau1761_regmap_config);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1361/ADAU1461/ADAU1761/ADAU1961 CODEC driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
23
sound/soc/codecs/adau1761.h
Normal file
23
sound/soc/codecs/adau1761.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* ADAU1361/ADAU1461/ADAU1761/ADAU1961 driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_CODECS_ADAU1761_H__
|
||||
#define __SOUND_SOC_CODECS_ADAU1761_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include "adau17x1.h"
|
||||
|
||||
struct device;
|
||||
|
||||
int adau1761_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev));
|
||||
|
||||
extern const struct regmap_config adau1761_regmap_config;
|
||||
|
||||
#endif
|
58
sound/soc/codecs/adau1781-i2c.c
Normal file
58
sound/soc/codecs/adau1781-i2c.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Driver for ADAU1381/ADAU1781 CODEC
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1781.h"
|
||||
|
||||
static int adau1781_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = adau1781_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 16;
|
||||
|
||||
return adau1781_probe(&client->dev,
|
||||
devm_regmap_init_i2c(client, &config),
|
||||
id->driver_data, NULL);
|
||||
}
|
||||
|
||||
static int adau1781_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adau1781_i2c_ids[] = {
|
||||
{ "adau1381", ADAU1381 },
|
||||
{ "adau1781", ADAU1781 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids);
|
||||
|
||||
static struct i2c_driver adau1781_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "adau1781",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1781_i2c_probe,
|
||||
.remove = adau1781_i2c_remove,
|
||||
.id_table = adau1781_i2c_ids,
|
||||
};
|
||||
module_i2c_driver(adau1781_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC I2C driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
75
sound/soc/codecs/adau1781-spi.c
Normal file
75
sound/soc/codecs/adau1781-spi.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Driver for ADAU1381/ADAU1781 CODEC
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "adau1781.h"
|
||||
|
||||
static void adau1781_spi_switch_mode(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
/*
|
||||
* To get the device into SPI mode CLATCH has to be pulled low three
|
||||
* times. Do this by issuing three dummy reads.
|
||||
*/
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
spi_w8r8(spi, 0x00);
|
||||
}
|
||||
|
||||
static int adau1781_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct regmap_config config;
|
||||
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
config = adau1781_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 24;
|
||||
config.read_flag_mask = 0x1;
|
||||
|
||||
return adau1781_probe(&spi->dev,
|
||||
devm_regmap_init_spi(spi, &config),
|
||||
id->driver_data, adau1781_spi_switch_mode);
|
||||
}
|
||||
|
||||
static int adau1781_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id adau1781_spi_id[] = {
|
||||
{ "adau1381", ADAU1381 },
|
||||
{ "adau1781", ADAU1781 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adau1781_spi_id);
|
||||
|
||||
static struct spi_driver adau1781_spi_driver = {
|
||||
.driver = {
|
||||
.name = "adau1781",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = adau1781_spi_probe,
|
||||
.remove = adau1781_spi_remove,
|
||||
.id_table = adau1781_spi_id,
|
||||
};
|
||||
module_spi_driver(adau1781_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 CODEC SPI driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
511
sound/soc/codecs/adau1781.c
Normal file
511
sound/soc/codecs/adau1781.c
Normal file
@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Driver for ADAU1781/ADAU1781 codec
|
||||
*
|
||||
* Copyright 2011-2013 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/platform_data/adau17x1.h>
|
||||
|
||||
#include "adau17x1.h"
|
||||
#include "adau1781.h"
|
||||
|
||||
#define ADAU1781_DMIC_BEEP_CTRL 0x4008
|
||||
#define ADAU1781_LEFT_PGA 0x400e
|
||||
#define ADAU1781_RIGHT_PGA 0x400f
|
||||
#define ADAU1781_LEFT_PLAYBACK_MIXER 0x401c
|
||||
#define ADAU1781_RIGHT_PLAYBACK_MIXER 0x401e
|
||||
#define ADAU1781_MONO_PLAYBACK_MIXER 0x401f
|
||||
#define ADAU1781_LEFT_LINEOUT 0x4025
|
||||
#define ADAU1781_RIGHT_LINEOUT 0x4026
|
||||
#define ADAU1781_SPEAKER 0x4027
|
||||
#define ADAU1781_BEEP_ZC 0x4028
|
||||
#define ADAU1781_DEJITTER 0x4032
|
||||
#define ADAU1781_DIG_PWDN0 0x4080
|
||||
#define ADAU1781_DIG_PWDN1 0x4081
|
||||
|
||||
#define ADAU1781_INPUT_DIFFERNTIAL BIT(3)
|
||||
|
||||
#define ADAU1381_FIRMWARE "adau1381.bin"
|
||||
#define ADAU1781_FIRMWARE "adau1781.bin"
|
||||
|
||||
static const struct reg_default adau1781_reg_defaults[] = {
|
||||
{ ADAU1781_DMIC_BEEP_CTRL, 0x00 },
|
||||
{ ADAU1781_LEFT_PGA, 0xc7 },
|
||||
{ ADAU1781_RIGHT_PGA, 0xc7 },
|
||||
{ ADAU1781_LEFT_PLAYBACK_MIXER, 0x00 },
|
||||
{ ADAU1781_RIGHT_PLAYBACK_MIXER, 0x00 },
|
||||
{ ADAU1781_MONO_PLAYBACK_MIXER, 0x00 },
|
||||
{ ADAU1781_LEFT_LINEOUT, 0x00 },
|
||||
{ ADAU1781_RIGHT_LINEOUT, 0x00 },
|
||||
{ ADAU1781_SPEAKER, 0x00 },
|
||||
{ ADAU1781_BEEP_ZC, 0x19 },
|
||||
{ ADAU1781_DEJITTER, 0x60 },
|
||||
{ ADAU1781_DIG_PWDN1, 0x0c },
|
||||
{ ADAU1781_DIG_PWDN1, 0x00 },
|
||||
{ ADAU17X1_CLOCK_CONTROL, 0x00 },
|
||||
{ ADAU17X1_PLL_CONTROL, 0x00 },
|
||||
{ ADAU17X1_REC_POWER_MGMT, 0x00 },
|
||||
{ ADAU17X1_MICBIAS, 0x04 },
|
||||
{ ADAU17X1_SERIAL_PORT0, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT1, 0x00 },
|
||||
{ ADAU17X1_CONVERTER0, 0x00 },
|
||||
{ ADAU17X1_CONVERTER1, 0x00 },
|
||||
{ ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
|
||||
{ ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
|
||||
{ ADAU17X1_ADC_CONTROL, 0x00 },
|
||||
{ ADAU17X1_PLAY_POWER_MGMT, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL0, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL1, 0x00 },
|
||||
{ ADAU17X1_DAC_CONTROL2, 0x00 },
|
||||
{ ADAU17X1_SERIAL_PORT_PAD, 0x00 },
|
||||
{ ADAU17X1_CONTROL_PORT_PAD0, 0x00 },
|
||||
{ ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
|
||||
{ ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
|
||||
{ ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
|
||||
{ ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
|
||||
{ ADAU17X1_DSP_ENABLE, 0x00 },
|
||||
{ ADAU17X1_DSP_RUN, 0x00 },
|
||||
{ ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adau1781_speaker_tlv, 0, 200, 0);
|
||||
|
||||
static const DECLARE_TLV_DB_RANGE(adau1781_pga_tlv,
|
||||
0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
|
||||
2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0),
|
||||
4, 4, TLV_DB_SCALE_ITEM(1700, 0, 0),
|
||||
5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0)
|
||||
);
|
||||
|
||||
static const DECLARE_TLV_DB_RANGE(adau1781_beep_tlv,
|
||||
0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
|
||||
2, 3, TLV_DB_SCALE_ITEM(1000, 400, 0),
|
||||
4, 4, TLV_DB_SCALE_ITEM(-2300, 0, 0),
|
||||
5, 7, TLV_DB_SCALE_ITEM(2000, 600, 0)
|
||||
);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(adau1781_sidetone_tlv, -1800, 300, 1);
|
||||
|
||||
static const char * const adau1781_speaker_bias_select_text[] = {
|
||||
"Normal operation", "Power saving", "Enhanced performance",
|
||||
};
|
||||
|
||||
static const char * const adau1781_bias_select_text[] = {
|
||||
"Normal operation", "Extreme power saving", "Power saving",
|
||||
"Enhanced performance",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_adc_bias_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 3, adau1781_bias_select_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_speaker_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 6, adau1781_speaker_bias_select_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_dac_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 4, adau1781_bias_select_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_playback_bias_enum,
|
||||
ADAU17X1_PLAY_POWER_MGMT, 2, adau1781_bias_select_text);
|
||||
static SOC_ENUM_SINGLE_DECL(adau1781_capture_bias_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 1, adau1781_bias_select_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_controls[] = {
|
||||
SOC_SINGLE_TLV("Beep Capture Volume", ADAU1781_DMIC_BEEP_CTRL, 0, 7, 0,
|
||||
adau1781_beep_tlv),
|
||||
SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAU1781_LEFT_PGA,
|
||||
ADAU1781_RIGHT_PGA, 5, 7, 0, adau1781_pga_tlv),
|
||||
SOC_DOUBLE_R("PGA Capture Switch", ADAU1781_LEFT_PGA,
|
||||
ADAU1781_RIGHT_PGA, 1, 1, 0),
|
||||
|
||||
SOC_DOUBLE_R("Lineout Playback Switch", ADAU1781_LEFT_LINEOUT,
|
||||
ADAU1781_RIGHT_LINEOUT, 1, 1, 0),
|
||||
SOC_SINGLE("Beep ZC Switch", ADAU1781_BEEP_ZC, 0, 1, 0),
|
||||
|
||||
SOC_SINGLE("Mono Playback Switch", ADAU1781_MONO_PLAYBACK_MIXER,
|
||||
0, 1, 0),
|
||||
SOC_SINGLE_TLV("Mono Playback Volume", ADAU1781_SPEAKER, 6, 3, 0,
|
||||
adau1781_speaker_tlv),
|
||||
|
||||
SOC_ENUM("ADC Bias", adau1781_adc_bias_enum),
|
||||
SOC_ENUM("DAC Bias", adau1781_dac_bias_enum),
|
||||
SOC_ENUM("Capture Bias", adau1781_capture_bias_enum),
|
||||
SOC_ENUM("Playback Bias", adau1781_playback_bias_enum),
|
||||
SOC_ENUM("Speaker Bias", adau1781_speaker_bias_enum),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_beep_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Beep Capture Switch", ADAU1781_DMIC_BEEP_CTRL,
|
||||
3, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_left_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Switch",
|
||||
ADAU1781_LEFT_PLAYBACK_MIXER, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
|
||||
ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_right_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Switch",
|
||||
ADAU1781_RIGHT_PLAYBACK_MIXER, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
|
||||
ADAU1781_LEFT_PLAYBACK_MIXER, 1, 8, 0, adau1781_sidetone_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Left Switch",
|
||||
ADAU1781_MONO_PLAYBACK_MIXER, 7, 1, 0),
|
||||
SOC_DAPM_SINGLE_AUTODISABLE("Right Switch",
|
||||
ADAU1781_MONO_PLAYBACK_MIXER, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE_TLV("Beep Playback Volume",
|
||||
ADAU1781_MONO_PLAYBACK_MIXER, 2, 8, 0, adau1781_sidetone_tlv),
|
||||
};
|
||||
|
||||
static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* After any power changes have been made the dejitter circuit
|
||||
* has to be reinitialized. */
|
||||
regmap_write(adau->regmap, ADAU1781_DEJITTER, 0);
|
||||
if (!adau->master)
|
||||
regmap_write(adau->regmap, ADAU1781_DEJITTER, 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1781_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_PGA("Left PGA", ADAU1781_LEFT_PGA, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Right PGA", ADAU1781_RIGHT_PGA, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUT_DRV("Speaker", ADAU1781_SPEAKER, 0, 0, NULL, 0),
|
||||
|
||||
SOC_MIXER_NAMED_CTL_ARRAY("Beep Mixer", ADAU17X1_MICBIAS, 4, 0,
|
||||
adau1781_beep_mixer_controls),
|
||||
|
||||
SOC_MIXER_ARRAY("Left Lineout Mixer", SND_SOC_NOPM, 0, 0,
|
||||
adau1781_left_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Right Lineout Mixer", SND_SOC_NOPM, 0, 0,
|
||||
adau1781_right_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Mono Mixer", SND_SOC_NOPM, 0, 0,
|
||||
adau1781_mono_mixer_controls),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Serial Input Routing", ADAU1781_DIG_PWDN0,
|
||||
2, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Serial Output Routing", ADAU1781_DIG_PWDN0,
|
||||
3, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Clock Domain Transfer", ADAU1781_DIG_PWDN0,
|
||||
5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Serial Ports", ADAU1781_DIG_PWDN0, 4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC Engine", ADAU1781_DIG_PWDN0, 7, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC Engine", ADAU1781_DIG_PWDN1, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Digital Mic", ADAU1781_DIG_PWDN1, 1, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Sound Engine", ADAU1781_DIG_PWDN0, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, ADAU1781_DIG_PWDN0, 1, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Zero Crossing Detector", ADAU1781_DIG_PWDN1, 2, 0,
|
||||
NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_POST("Dejitter fixup", adau1781_dejitter_fixup),
|
||||
|
||||
SND_SOC_DAPM_INPUT("BEEP"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("AOUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("AOUTR"),
|
||||
SND_SOC_DAPM_OUTPUT("SP"),
|
||||
SND_SOC_DAPM_INPUT("LMIC"),
|
||||
SND_SOC_DAPM_INPUT("RMIC"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1781_dapm_routes[] = {
|
||||
{ "Left Lineout Mixer", NULL, "Left Playback Enable" },
|
||||
{ "Right Lineout Mixer", NULL, "Right Playback Enable" },
|
||||
|
||||
{ "Left Lineout Mixer", "Beep Playback Volume", "Beep Mixer" },
|
||||
{ "Left Lineout Mixer", "Switch", "Left DAC" },
|
||||
|
||||
{ "Right Lineout Mixer", "Beep Playback Volume", "Beep Mixer" },
|
||||
{ "Right Lineout Mixer", "Switch", "Right DAC" },
|
||||
|
||||
{ "Mono Mixer", "Beep Playback Volume", "Beep Mixer" },
|
||||
{ "Mono Mixer", "Right Switch", "Right DAC" },
|
||||
{ "Mono Mixer", "Left Switch", "Left DAC" },
|
||||
{ "Speaker", NULL, "Mono Mixer" },
|
||||
|
||||
{ "Mono Mixer", NULL, "SYSCLK" },
|
||||
{ "Left Lineout Mixer", NULL, "SYSCLK" },
|
||||
{ "Left Lineout Mixer", NULL, "SYSCLK" },
|
||||
|
||||
{ "Beep Mixer", "Beep Capture Switch", "BEEP" },
|
||||
{ "Beep Mixer", NULL, "Zero Crossing Detector" },
|
||||
|
||||
{ "Left DAC", NULL, "DAC Engine" },
|
||||
{ "Right DAC", NULL, "DAC Engine" },
|
||||
|
||||
{ "Sound Engine", NULL, "SYSCLK" },
|
||||
{ "DSP", NULL, "Sound Engine" },
|
||||
|
||||
{ "Left Decimator", NULL, "ADC Engine" },
|
||||
{ "Right Decimator", NULL, "ADC Engine" },
|
||||
|
||||
{ "AIFCLK", NULL, "SYSCLK" },
|
||||
|
||||
{ "Playback", NULL, "Serial Input Routing" },
|
||||
{ "Playback", NULL, "Serial Ports" },
|
||||
{ "Playback", NULL, "Clock Domain Transfer" },
|
||||
{ "Capture", NULL, "Serial Output Routing" },
|
||||
{ "Capture", NULL, "Serial Ports" },
|
||||
{ "Capture", NULL, "Clock Domain Transfer" },
|
||||
|
||||
{ "AOUTL", NULL, "Left Lineout Mixer" },
|
||||
{ "AOUTR", NULL, "Right Lineout Mixer" },
|
||||
{ "SP", NULL, "Speaker" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1781_adc_dapm_routes[] = {
|
||||
{ "Left PGA", NULL, "LMIC" },
|
||||
{ "Right PGA", NULL, "RMIC" },
|
||||
|
||||
{ "Left Decimator", NULL, "Left PGA" },
|
||||
{ "Right Decimator", NULL, "Right PGA" },
|
||||
};
|
||||
|
||||
static const char * const adau1781_dmic_select_text[] = {
|
||||
"DMIC1", "DMIC2",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_VIRT_DECL(adau1781_dmic_select_enum,
|
||||
adau1781_dmic_select_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau1781_dmic_mux =
|
||||
SOC_DAPM_ENUM("DMIC Select", adau1781_dmic_select_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget adau1781_dmic_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MUX("DMIC Select", SND_SOC_NOPM, 0, 0, &adau1781_dmic_mux),
|
||||
|
||||
SND_SOC_DAPM_ADC("DMIC1", NULL, ADAU1781_DMIC_BEEP_CTRL, 4, 0),
|
||||
SND_SOC_DAPM_ADC("DMIC2", NULL, ADAU1781_DMIC_BEEP_CTRL, 5, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau1781_dmic_dapm_routes[] = {
|
||||
{ "DMIC1", NULL, "LMIC" },
|
||||
{ "DMIC2", NULL, "RMIC" },
|
||||
|
||||
{ "DMIC1", NULL, "Digital Mic" },
|
||||
{ "DMIC2", NULL, "Digital Mic" },
|
||||
|
||||
{ "DMIC Select", "DMIC1", "DMIC1" },
|
||||
{ "DMIC Select", "DMIC2", "DMIC2" },
|
||||
|
||||
{ "Left Decimator", NULL, "DMIC Select" },
|
||||
{ "Right Decimator", NULL, "DMIC Select" },
|
||||
};
|
||||
|
||||
static int adau1781_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN);
|
||||
|
||||
/* Precharge */
|
||||
regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0x8, 0x8);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
regmap_update_bits(adau->regmap, ADAU1781_DIG_PWDN1, 0xc, 0x0);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool adau1781_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU1781_DMIC_BEEP_CTRL:
|
||||
case ADAU1781_LEFT_PGA:
|
||||
case ADAU1781_RIGHT_PGA:
|
||||
case ADAU1781_LEFT_PLAYBACK_MIXER:
|
||||
case ADAU1781_RIGHT_PLAYBACK_MIXER:
|
||||
case ADAU1781_MONO_PLAYBACK_MIXER:
|
||||
case ADAU1781_LEFT_LINEOUT:
|
||||
case ADAU1781_RIGHT_LINEOUT:
|
||||
case ADAU1781_SPEAKER:
|
||||
case ADAU1781_BEEP_ZC:
|
||||
case ADAU1781_DEJITTER:
|
||||
case ADAU1781_DIG_PWDN0:
|
||||
case ADAU1781_DIG_PWDN1:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return adau17x1_readable_register(dev, reg);
|
||||
}
|
||||
|
||||
static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
|
||||
bool differential)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (differential)
|
||||
val = ADAU1781_INPUT_DIFFERNTIAL;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
return regmap_update_bits(adau->regmap, reg,
|
||||
ADAU1781_INPUT_DIFFERNTIAL, val);
|
||||
}
|
||||
|
||||
static int adau1781_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
const char *firmware;
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_add_widgets(codec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pdata) {
|
||||
ret = adau1781_set_input_mode(adau, ADAU1781_LEFT_PGA,
|
||||
pdata->left_input_differential);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = adau1781_set_input_mode(adau, ADAU1781_RIGHT_PGA,
|
||||
pdata->right_input_differential);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata && pdata->use_dmic) {
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau1781_dmic_dapm_widgets,
|
||||
ARRAY_SIZE(adau1781_dmic_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1781_dmic_dapm_routes,
|
||||
ARRAY_SIZE(adau1781_dmic_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau1781_adc_dapm_routes,
|
||||
ARRAY_SIZE(adau1781_adc_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (adau->type) {
|
||||
case ADAU1381:
|
||||
firmware = ADAU1381_FIRMWARE;
|
||||
break;
|
||||
case ADAU1781:
|
||||
firmware = ADAU1781_FIRMWARE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = adau17x1_add_routes(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = adau17x1_load_firmware(adau, codec->dev, firmware);
|
||||
if (ret)
|
||||
dev_warn(codec->dev, "Failed to load firmware\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver adau1781_codec_driver = {
|
||||
.probe = adau1781_codec_probe,
|
||||
.suspend = adau17x1_suspend,
|
||||
.resume = adau17x1_resume,
|
||||
.set_bias_level = adau1781_set_bias_level,
|
||||
|
||||
.controls = adau1781_controls,
|
||||
.num_controls = ARRAY_SIZE(adau1781_controls),
|
||||
.dapm_widgets = adau1781_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(adau1781_dapm_widgets),
|
||||
.dapm_routes = adau1781_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(adau1781_dapm_routes),
|
||||
};
|
||||
|
||||
#define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static struct snd_soc_dai_driver adau1781_dai_driver = {
|
||||
.name = "adau-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1781_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = ADAU1781_FORMATS,
|
||||
},
|
||||
.ops = &adau17x1_dai_ops,
|
||||
};
|
||||
|
||||
const struct regmap_config adau1781_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 16,
|
||||
.max_register = 0x40f8,
|
||||
.reg_defaults = adau1781_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults),
|
||||
.readable_reg = adau1781_readable_register,
|
||||
.volatile_reg = adau17x1_volatile_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau1781_regmap_config);
|
||||
|
||||
int adau1781_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_probe(dev, regmap, type, switch_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return snd_soc_register_codec(dev, &adau1781_codec_driver,
|
||||
&adau1781_dai_driver, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau1781_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1381/ADAU1781 driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
23
sound/soc/codecs/adau1781.h
Normal file
23
sound/soc/codecs/adau1781.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* ADAU1381/ADAU1781 driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_CODECS_ADAU1781_H__
|
||||
#define __SOUND_SOC_CODECS_ADAU1781_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include "adau17x1.h"
|
||||
|
||||
struct device;
|
||||
|
||||
int adau1781_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev));
|
||||
|
||||
extern const struct regmap_config adau1781_regmap_config;
|
||||
|
||||
#endif
|
866
sound/soc/codecs/adau17x1.c
Normal file
866
sound/soc/codecs/adau17x1.c
Normal file
@ -0,0 +1,866 @@
|
||||
/*
|
||||
* Common code for ADAU1X61 and ADAU1X81 codecs
|
||||
*
|
||||
* Copyright 2011-2014 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "sigmadsp.h"
|
||||
#include "adau17x1.h"
|
||||
|
||||
static const char * const adau17x1_capture_mixer_boost_text[] = {
|
||||
"Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau17x1_capture_boost_enum,
|
||||
ADAU17X1_REC_POWER_MGMT, 5, adau17x1_capture_mixer_boost_text);
|
||||
|
||||
static const char * const adau17x1_mic_bias_mode_text[] = {
|
||||
"Normal operation", "High performance",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau17x1_mic_bias_mode_enum,
|
||||
ADAU17X1_MICBIAS, 3, adau17x1_mic_bias_mode_text);
|
||||
|
||||
static const DECLARE_TLV_DB_MINMAX(adau17x1_digital_tlv, -9563, 0);
|
||||
|
||||
static const struct snd_kcontrol_new adau17x1_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Digital Capture Volume",
|
||||
ADAU17X1_LEFT_INPUT_DIGITAL_VOL,
|
||||
ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,
|
||||
0, 0xff, 1, adau17x1_digital_tlv),
|
||||
SOC_DOUBLE_R_TLV("Digital Playback Volume", ADAU17X1_DAC_CONTROL1,
|
||||
ADAU17X1_DAC_CONTROL2, 0, 0xff, 1, adau17x1_digital_tlv),
|
||||
|
||||
SOC_SINGLE("ADC High Pass Filter Switch", ADAU17X1_ADC_CONTROL,
|
||||
5, 1, 0),
|
||||
SOC_SINGLE("Playback De-emphasis Switch", ADAU17X1_DAC_CONTROL0,
|
||||
2, 1, 0),
|
||||
|
||||
SOC_ENUM("Capture Boost", adau17x1_capture_boost_enum),
|
||||
|
||||
SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum),
|
||||
};
|
||||
|
||||
static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
|
||||
int ret;
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
adau->pll_regs[5] = 1;
|
||||
} else {
|
||||
adau->pll_regs[5] = 0;
|
||||
/* Bypass the PLL when disabled, otherwise registers will become
|
||||
* inaccessible. */
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL, 0);
|
||||
}
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
mdelay(5);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
|
||||
ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL,
|
||||
ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const adau17x1_mono_stereo_text[] = {
|
||||
"Stereo",
|
||||
"Mono Left Channel (L+R)",
|
||||
"Mono Right Channel (L+R)",
|
||||
"Mono (L+R)",
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(adau17x1_dac_mode_enum,
|
||||
ADAU17X1_DAC_CONTROL0, 6, adau17x1_mono_stereo_text);
|
||||
|
||||
static const struct snd_kcontrol_new adau17x1_dac_mode_mux =
|
||||
SOC_DAPM_ENUM("DAC Mono-Stereo-Mode", adau17x1_dac_mode_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget adau17x1_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY_S("PLL", 3, SND_SOC_NOPM, 0, 0, adau17x1_pll_event,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("AIFCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU17X1_MICBIAS, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Left Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
|
||||
0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("Right Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
|
||||
1, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MUX("Left DAC Mode Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau17x1_dac_mode_mux),
|
||||
SND_SOC_DAPM_MUX("Right DAC Mode Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau17x1_dac_mode_mux),
|
||||
|
||||
SND_SOC_DAPM_ADC("Left Decimator", NULL, ADAU17X1_ADC_CONTROL, 0, 0),
|
||||
SND_SOC_DAPM_ADC("Right Decimator", NULL, ADAU17X1_ADC_CONTROL, 1, 0),
|
||||
SND_SOC_DAPM_DAC("Left DAC", NULL, ADAU17X1_DAC_CONTROL0, 0, 0),
|
||||
SND_SOC_DAPM_DAC("Right DAC", NULL, ADAU17X1_DAC_CONTROL0, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_dapm_routes[] = {
|
||||
{ "Left Decimator", NULL, "SYSCLK" },
|
||||
{ "Right Decimator", NULL, "SYSCLK" },
|
||||
{ "Left DAC", NULL, "SYSCLK" },
|
||||
{ "Right DAC", NULL, "SYSCLK" },
|
||||
{ "Capture", NULL, "SYSCLK" },
|
||||
{ "Playback", NULL, "SYSCLK" },
|
||||
|
||||
{ "Left DAC", NULL, "Left DAC Mode Mux" },
|
||||
{ "Right DAC", NULL, "Right DAC Mode Mux" },
|
||||
|
||||
{ "Capture", NULL, "AIFCLK" },
|
||||
{ "Playback", NULL, "AIFCLK" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_dapm_pll_route = {
|
||||
"SYSCLK", NULL, "PLL",
|
||||
};
|
||||
|
||||
/*
|
||||
* The MUX register for the Capture and Playback MUXs selects either DSP as
|
||||
* source/destination or one of the TDM slots. The TDM slot is selected via
|
||||
* snd_soc_dai_set_tdm_slot(), so we only expose whether to go to the DSP or
|
||||
* directly to the DAI interface with this control.
|
||||
*/
|
||||
static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
struct snd_soc_dapm_update update;
|
||||
unsigned int stream = e->shift_l;
|
||||
unsigned int val, change;
|
||||
int reg;
|
||||
|
||||
if (ucontrol->value.enumerated.item[0] >= e->items)
|
||||
return -EINVAL;
|
||||
|
||||
switch (ucontrol->value.enumerated.item[0]) {
|
||||
case 0:
|
||||
val = 0;
|
||||
adau->dsp_bypass[stream] = false;
|
||||
break;
|
||||
default:
|
||||
val = (adau->tdm_slot[stream] * 2) + 1;
|
||||
adau->dsp_bypass[stream] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
reg = ADAU17X1_SERIAL_INPUT_ROUTE;
|
||||
else
|
||||
reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
|
||||
|
||||
change = snd_soc_test_bits(codec, reg, 0xff, val);
|
||||
if (change) {
|
||||
update.kcontrol = kcontrol;
|
||||
update.mask = 0xff;
|
||||
update.reg = reg;
|
||||
update.val = val;
|
||||
|
||||
snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol,
|
||||
ucontrol->value.enumerated.item[0], e, &update);
|
||||
}
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
unsigned int stream = e->shift_l;
|
||||
unsigned int reg, val;
|
||||
int ret;
|
||||
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
reg = ADAU17X1_SERIAL_INPUT_ROUTE;
|
||||
else
|
||||
reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
|
||||
|
||||
ret = regmap_read(adau->regmap, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val != 0)
|
||||
val = 1;
|
||||
ucontrol->value.enumerated.item[0] = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DECLARE_ADAU17X1_DSP_MUX_CTRL(_name, _label, _stream, _text) \
|
||||
const struct snd_kcontrol_new _name = \
|
||||
SOC_DAPM_ENUM_EXT(_label, (const struct soc_enum)\
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, _stream, \
|
||||
ARRAY_SIZE(_text), _text), \
|
||||
adau17x1_dsp_mux_enum_get, adau17x1_dsp_mux_enum_put)
|
||||
|
||||
static const char * const adau17x1_dac_mux_text[] = {
|
||||
"DSP",
|
||||
"AIFIN",
|
||||
};
|
||||
|
||||
static const char * const adau17x1_capture_mux_text[] = {
|
||||
"DSP",
|
||||
"Decimator",
|
||||
};
|
||||
|
||||
static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_dac_mux, "DAC Playback Mux",
|
||||
SNDRV_PCM_STREAM_PLAYBACK, adau17x1_dac_mux_text);
|
||||
|
||||
static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_capture_mux, "Capture Mux",
|
||||
SNDRV_PCM_STREAM_CAPTURE, adau17x1_capture_mux_text);
|
||||
|
||||
static const struct snd_soc_dapm_widget adau17x1_dsp_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_PGA("DSP", ADAU17X1_DSP_RUN, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SIGGEN("DSP Siggen"),
|
||||
|
||||
SND_SOC_DAPM_MUX("DAC Playback Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau17x1_dac_mux),
|
||||
SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0,
|
||||
&adau17x1_capture_mux),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = {
|
||||
{ "DAC Playback Mux", "DSP", "DSP" },
|
||||
{ "DAC Playback Mux", "AIFIN", "Playback" },
|
||||
|
||||
{ "Left DAC Mode Mux", "Stereo", "DAC Playback Mux" },
|
||||
{ "Left DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
|
||||
{ "Left DAC Mode Mux", "Mono Left Channel (L+R)", "DAC Playback Mux" },
|
||||
{ "Right DAC Mode Mux", "Stereo", "DAC Playback Mux" },
|
||||
{ "Right DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
|
||||
{ "Right DAC Mode Mux", "Mono Right Channel (L+R)", "DAC Playback Mux" },
|
||||
|
||||
{ "Capture Mux", "DSP", "DSP" },
|
||||
{ "Capture Mux", "Decimator", "Left Decimator" },
|
||||
{ "Capture Mux", "Decimator", "Right Decimator" },
|
||||
|
||||
{ "Capture", NULL, "Capture Mux" },
|
||||
|
||||
{ "DSP", NULL, "DSP Siggen" },
|
||||
|
||||
{ "DSP", NULL, "Left Decimator" },
|
||||
{ "DSP", NULL, "Right Decimator" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
|
||||
{ "Left DAC Mode Mux", "Stereo", "Playback" },
|
||||
{ "Left DAC Mode Mux", "Mono (L+R)", "Playback" },
|
||||
{ "Left DAC Mode Mux", "Mono Left Channel (L+R)", "Playback" },
|
||||
{ "Right DAC Mode Mux", "Stereo", "Playback" },
|
||||
{ "Right DAC Mode Mux", "Mono (L+R)", "Playback" },
|
||||
{ "Right DAC Mode Mux", "Mono Right Channel (L+R)", "Playback" },
|
||||
{ "Capture", NULL, "Left Decimator" },
|
||||
{ "Capture", NULL, "Right Decimator" },
|
||||
};
|
||||
|
||||
bool adau17x1_has_dsp(struct adau *adau)
|
||||
{
|
||||
switch (adau->type) {
|
||||
case ADAU1761:
|
||||
case ADAU1381:
|
||||
case ADAU1781:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
|
||||
|
||||
static int adau17x1_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 adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val, div, dsp_div;
|
||||
unsigned int freq;
|
||||
|
||||
if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
|
||||
freq = adau->pll_freq;
|
||||
else
|
||||
freq = adau->sysclk;
|
||||
|
||||
if (freq % params_rate(params) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (freq / params_rate(params)) {
|
||||
case 1024: /* fs */
|
||||
div = 0;
|
||||
dsp_div = 1;
|
||||
break;
|
||||
case 6144: /* fs / 6 */
|
||||
div = 1;
|
||||
dsp_div = 6;
|
||||
break;
|
||||
case 4096: /* fs / 4 */
|
||||
div = 2;
|
||||
dsp_div = 5;
|
||||
break;
|
||||
case 3072: /* fs / 3 */
|
||||
div = 3;
|
||||
dsp_div = 4;
|
||||
break;
|
||||
case 2048: /* fs / 2 */
|
||||
div = 4;
|
||||
dsp_div = 3;
|
||||
break;
|
||||
case 1536: /* fs / 1.5 */
|
||||
div = 5;
|
||||
dsp_div = 2;
|
||||
break;
|
||||
case 512: /* fs / 0.5 */
|
||||
div = 6;
|
||||
dsp_div = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
|
||||
ADAU17X1_CONVERTER0_CONVSR_MASK, div);
|
||||
if (adau17x1_has_dsp(adau)) {
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div);
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
|
||||
}
|
||||
|
||||
if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
|
||||
return 0;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
val = ADAU17X1_SERIAL_PORT1_DELAY16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
val = ADAU17X1_SERIAL_PORT1_DELAY8;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
val = ADAU17X1_SERIAL_PORT1_DELAY0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
|
||||
ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int r, n, m, i, j;
|
||||
unsigned int div;
|
||||
int ret;
|
||||
|
||||
if (freq_in < 8000000 || freq_in > 27000000)
|
||||
return -EINVAL;
|
||||
|
||||
if (!freq_out) {
|
||||
r = 0;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
} else {
|
||||
if (freq_out % freq_in != 0) {
|
||||
div = DIV_ROUND_UP(freq_in, 13500000);
|
||||
freq_in /= div;
|
||||
r = freq_out / freq_in;
|
||||
i = freq_out % freq_in;
|
||||
j = gcd(i, freq_in);
|
||||
n = i / j;
|
||||
m = freq_in / j;
|
||||
div--;
|
||||
} else {
|
||||
r = freq_out / freq_in;
|
||||
n = 0;
|
||||
m = 0;
|
||||
div = 0;
|
||||
}
|
||||
if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->pll_regs[0] = m >> 8;
|
||||
adau->pll_regs[1] = m & 0xff;
|
||||
adau->pll_regs[2] = n >> 8;
|
||||
adau->pll_regs[3] = n & 0xff;
|
||||
adau->pll_regs[4] = (r << 3) | (div << 1);
|
||||
if (m != 0)
|
||||
adau->pll_regs[4] |= 1; /* Fractional mode */
|
||||
|
||||
/* The PLL register is 6 bytes long and can only be written at once. */
|
||||
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
|
||||
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adau->pll_freq = freq_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
struct snd_soc_dapm_context *dapm = &dai->codec->dapm;
|
||||
|
||||
switch (clk_id) {
|
||||
case ADAU17X1_CLK_SRC_MCLK:
|
||||
case ADAU17X1_CLK_SRC_PLL:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adau->sysclk = freq;
|
||||
|
||||
if (adau->clk_src != clk_id) {
|
||||
if (clk_id == ADAU17X1_CLK_SRC_PLL) {
|
||||
snd_soc_dapm_add_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
} else {
|
||||
snd_soc_dapm_del_routes(dapm,
|
||||
&adau17x1_dapm_pll_route, 1);
|
||||
}
|
||||
}
|
||||
|
||||
adau->clk_src = clk_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
unsigned int ctrl0, ctrl1;
|
||||
int lrclk_pol;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
ctrl0 = ADAU17X1_SERIAL_PORT0_MASTER;
|
||||
adau->master = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
ctrl0 = 0;
|
||||
adau->master = false;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
lrclk_pol = 0;
|
||||
ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
lrclk_pol = 1;
|
||||
ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
lrclk_pol = 1;
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
|
||||
ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
lrclk_pol = 1;
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
|
||||
ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
lrclk_pol = !lrclk_pol;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
|
||||
lrclk_pol = !lrclk_pol;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lrclk_pol)
|
||||
ctrl0 |= ADAU17X1_SERIAL_PORT0_LRCLK_POL;
|
||||
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0);
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT1, ctrl1);
|
||||
|
||||
adau->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
unsigned int ser_ctrl0, ser_ctrl1;
|
||||
unsigned int conv_ctrl0, conv_ctrl1;
|
||||
|
||||
/* I2S mode */
|
||||
if (slots == 0) {
|
||||
slots = 2;
|
||||
rx_mask = 3;
|
||||
tx_mask = 3;
|
||||
slot_width = 32;
|
||||
}
|
||||
|
||||
switch (slots) {
|
||||
case 2:
|
||||
ser_ctrl0 = ADAU17X1_SERIAL_PORT0_STEREO;
|
||||
break;
|
||||
case 4:
|
||||
ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM4;
|
||||
break;
|
||||
case 8:
|
||||
if (adau->type == ADAU1361)
|
||||
return -EINVAL;
|
||||
|
||||
ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM8;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (slot_width * slots) {
|
||||
case 32:
|
||||
if (adau->type == ADAU1761)
|
||||
return -EINVAL;
|
||||
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32;
|
||||
break;
|
||||
case 64:
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK64;
|
||||
break;
|
||||
case 48:
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK48;
|
||||
break;
|
||||
case 128:
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK128;
|
||||
break;
|
||||
case 256:
|
||||
if (adau->type == ADAU1361)
|
||||
return -EINVAL;
|
||||
|
||||
ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK256;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (rx_mask) {
|
||||
case 0x03:
|
||||
conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(1);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 0;
|
||||
break;
|
||||
case 0x0c:
|
||||
conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(2);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 1;
|
||||
break;
|
||||
case 0x30:
|
||||
conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(3);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 2;
|
||||
break;
|
||||
case 0xc0:
|
||||
conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(4);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 3;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (tx_mask) {
|
||||
case 0x03:
|
||||
conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(1);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 0;
|
||||
break;
|
||||
case 0x0c:
|
||||
conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(2);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 1;
|
||||
break;
|
||||
case 0x30:
|
||||
conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(3);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 2;
|
||||
break;
|
||||
case 0xc0:
|
||||
conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(4);
|
||||
adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 3;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
|
||||
ADAU17X1_CONVERTER0_DAC_PAIR_MASK, conv_ctrl0);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER1,
|
||||
ADAU17X1_CONVERTER1_ADC_PAIR_MASK, conv_ctrl1);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT0,
|
||||
ADAU17X1_SERIAL_PORT0_TDM_MASK, ser_ctrl0);
|
||||
regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
|
||||
ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1);
|
||||
|
||||
if (!adau17x1_has_dsp(adau))
|
||||
return 0;
|
||||
|
||||
if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) {
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE,
|
||||
(adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] * 2) + 1);
|
||||
}
|
||||
|
||||
if (adau->dsp_bypass[SNDRV_PCM_STREAM_CAPTURE]) {
|
||||
regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE,
|
||||
(adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] * 2) + 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct snd_soc_dai_ops adau17x1_dai_ops = {
|
||||
.hw_params = adau17x1_hw_params,
|
||||
.set_sysclk = adau17x1_set_dai_sysclk,
|
||||
.set_fmt = adau17x1_set_dai_fmt,
|
||||
.set_pll = adau17x1_set_dai_pll,
|
||||
.set_tdm_slot = adau17x1_set_dai_tdm_slot,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
|
||||
|
||||
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
||||
enum adau17x1_micbias_voltage micbias)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (micbias) {
|
||||
case ADAU17X1_MICBIAS_0_90_AVDD:
|
||||
case ADAU17X1_MICBIAS_0_65_AVDD:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_write(adau->regmap, ADAU17X1_MICBIAS, micbias << 2);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
|
||||
|
||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU17X1_CLOCK_CONTROL:
|
||||
case ADAU17X1_PLL_CONTROL:
|
||||
case ADAU17X1_REC_POWER_MGMT:
|
||||
case ADAU17X1_MICBIAS:
|
||||
case ADAU17X1_SERIAL_PORT0:
|
||||
case ADAU17X1_SERIAL_PORT1:
|
||||
case ADAU17X1_CONVERTER0:
|
||||
case ADAU17X1_CONVERTER1:
|
||||
case ADAU17X1_LEFT_INPUT_DIGITAL_VOL:
|
||||
case ADAU17X1_RIGHT_INPUT_DIGITAL_VOL:
|
||||
case ADAU17X1_ADC_CONTROL:
|
||||
case ADAU17X1_PLAY_POWER_MGMT:
|
||||
case ADAU17X1_DAC_CONTROL0:
|
||||
case ADAU17X1_DAC_CONTROL1:
|
||||
case ADAU17X1_DAC_CONTROL2:
|
||||
case ADAU17X1_SERIAL_PORT_PAD:
|
||||
case ADAU17X1_CONTROL_PORT_PAD0:
|
||||
case ADAU17X1_CONTROL_PORT_PAD1:
|
||||
case ADAU17X1_DSP_SAMPLING_RATE:
|
||||
case ADAU17X1_SERIAL_INPUT_ROUTE:
|
||||
case ADAU17X1_SERIAL_OUTPUT_ROUTE:
|
||||
case ADAU17X1_DSP_ENABLE:
|
||||
case ADAU17X1_DSP_RUN:
|
||||
case ADAU17X1_SERIAL_SAMPLING_RATE:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_readable_register);
|
||||
|
||||
bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* SigmaDSP parameter and program memory */
|
||||
if (reg < 0x4000)
|
||||
return true;
|
||||
|
||||
switch (reg) {
|
||||
/* The PLL register is 6 bytes long */
|
||||
case ADAU17X1_PLL_CONTROL:
|
||||
case ADAU17X1_PLL_CONTROL + 1:
|
||||
case ADAU17X1_PLL_CONTROL + 2:
|
||||
case ADAU17X1_PLL_CONTROL + 3:
|
||||
case ADAU17X1_PLL_CONTROL + 4:
|
||||
case ADAU17X1_PLL_CONTROL + 5:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
|
||||
|
||||
int adau17x1_load_firmware(struct adau *adau, struct device *dev,
|
||||
const char *firmware)
|
||||
{
|
||||
int ret;
|
||||
int dspsr;
|
||||
|
||||
ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
|
||||
|
||||
ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware);
|
||||
if (ret) {
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
|
||||
return ret;
|
||||
}
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dspsr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_load_firmware);
|
||||
|
||||
int adau17x1_add_widgets(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec, adau17x1_controls,
|
||||
ARRAY_SIZE(adau17x1_controls));
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets,
|
||||
ARRAY_SIZE(adau17x1_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adau17x1_has_dsp(adau)) {
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau17x1_dsp_dapm_widgets,
|
||||
ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
|
||||
|
||||
int adau17x1_add_routes(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes,
|
||||
ARRAY_SIZE(adau17x1_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (adau17x1_has_dsp(adau)) {
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau17x1_dsp_dapm_routes,
|
||||
ARRAY_SIZE(adau17x1_dsp_dapm_routes));
|
||||
} else {
|
||||
ret = snd_soc_dapm_add_routes(&codec->dapm,
|
||||
adau17x1_no_dsp_dapm_routes,
|
||||
ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_add_routes);
|
||||
|
||||
int adau17x1_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_suspend);
|
||||
|
||||
int adau17x1_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (adau->switch_mode)
|
||||
adau->switch_mode(codec->dev);
|
||||
|
||||
codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
regcache_sync(adau->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_resume);
|
||||
|
||||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
{
|
||||
struct adau *adau;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
adau = devm_kzalloc(dev, sizeof(*adau), GFP_KERNEL);
|
||||
if (!adau)
|
||||
return -ENOMEM;
|
||||
|
||||
adau->regmap = regmap;
|
||||
adau->switch_mode = switch_mode;
|
||||
adau->type = type;
|
||||
|
||||
dev_set_drvdata(dev, adau);
|
||||
|
||||
if (switch_mode)
|
||||
switch_mode(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_LICENSE("GPL");
|
124
sound/soc/codecs/adau17x1.h
Normal file
124
sound/soc/codecs/adau17x1.h
Normal file
@ -0,0 +1,124 @@
|
||||
#ifndef __ADAU17X1_H__
|
||||
#define __ADAU17X1_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/platform_data/adau17x1.h>
|
||||
|
||||
enum adau17x1_type {
|
||||
ADAU1361,
|
||||
ADAU1761,
|
||||
ADAU1381,
|
||||
ADAU1781,
|
||||
};
|
||||
|
||||
enum adau17x1_pll {
|
||||
ADAU17X1_PLL,
|
||||
};
|
||||
|
||||
enum adau17x1_pll_src {
|
||||
ADAU17X1_PLL_SRC_MCLK,
|
||||
};
|
||||
|
||||
enum adau17x1_clk_src {
|
||||
ADAU17X1_CLK_SRC_MCLK,
|
||||
ADAU17X1_CLK_SRC_PLL,
|
||||
};
|
||||
|
||||
struct adau {
|
||||
unsigned int sysclk;
|
||||
unsigned int pll_freq;
|
||||
|
||||
enum adau17x1_clk_src clk_src;
|
||||
enum adau17x1_type type;
|
||||
void (*switch_mode)(struct device *dev);
|
||||
|
||||
unsigned int dai_fmt;
|
||||
|
||||
uint8_t pll_regs[6];
|
||||
|
||||
bool master;
|
||||
|
||||
unsigned int tdm_slot[2];
|
||||
bool dsp_bypass[2];
|
||||
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
int adau17x1_add_widgets(struct snd_soc_codec *codec);
|
||||
int adau17x1_add_routes(struct snd_soc_codec *codec);
|
||||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev));
|
||||
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
||||
enum adau17x1_micbias_voltage micbias);
|
||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
|
||||
bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
|
||||
int adau17x1_suspend(struct snd_soc_codec *codec);
|
||||
int adau17x1_resume(struct snd_soc_codec *codec);
|
||||
|
||||
extern const struct snd_soc_dai_ops adau17x1_dai_ops;
|
||||
|
||||
int adau17x1_load_firmware(struct adau *adau, struct device *dev,
|
||||
const char *firmware);
|
||||
bool adau17x1_has_dsp(struct adau *adau);
|
||||
|
||||
#define ADAU17X1_CLOCK_CONTROL 0x4000
|
||||
#define ADAU17X1_PLL_CONTROL 0x4002
|
||||
#define ADAU17X1_REC_POWER_MGMT 0x4009
|
||||
#define ADAU17X1_MICBIAS 0x4010
|
||||
#define ADAU17X1_SERIAL_PORT0 0x4015
|
||||
#define ADAU17X1_SERIAL_PORT1 0x4016
|
||||
#define ADAU17X1_CONVERTER0 0x4017
|
||||
#define ADAU17X1_CONVERTER1 0x4018
|
||||
#define ADAU17X1_LEFT_INPUT_DIGITAL_VOL 0x401a
|
||||
#define ADAU17X1_RIGHT_INPUT_DIGITAL_VOL 0x401b
|
||||
#define ADAU17X1_ADC_CONTROL 0x4019
|
||||
#define ADAU17X1_PLAY_POWER_MGMT 0x4029
|
||||
#define ADAU17X1_DAC_CONTROL0 0x402a
|
||||
#define ADAU17X1_DAC_CONTROL1 0x402b
|
||||
#define ADAU17X1_DAC_CONTROL2 0x402c
|
||||
#define ADAU17X1_SERIAL_PORT_PAD 0x402d
|
||||
#define ADAU17X1_CONTROL_PORT_PAD0 0x402f
|
||||
#define ADAU17X1_CONTROL_PORT_PAD1 0x4030
|
||||
#define ADAU17X1_DSP_SAMPLING_RATE 0x40eb
|
||||
#define ADAU17X1_SERIAL_INPUT_ROUTE 0x40f2
|
||||
#define ADAU17X1_SERIAL_OUTPUT_ROUTE 0x40f3
|
||||
#define ADAU17X1_DSP_ENABLE 0x40f5
|
||||
#define ADAU17X1_DSP_RUN 0x40f6
|
||||
#define ADAU17X1_SERIAL_SAMPLING_RATE 0x40f8
|
||||
|
||||
#define ADAU17X1_SERIAL_PORT0_BCLK_POL BIT(4)
|
||||
#define ADAU17X1_SERIAL_PORT0_LRCLK_POL BIT(3)
|
||||
#define ADAU17X1_SERIAL_PORT0_MASTER BIT(0)
|
||||
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY1 0x00
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY0 0x01
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY8 0x02
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY16 0x03
|
||||
#define ADAU17X1_SERIAL_PORT1_DELAY_MASK 0x03
|
||||
|
||||
#define ADAU17X1_CLOCK_CONTROL_INFREQ_MASK 0x6
|
||||
#define ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL BIT(3)
|
||||
#define ADAU17X1_CLOCK_CONTROL_SYSCLK_EN BIT(0)
|
||||
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK32 (0x0 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK48 (0x1 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK64 (0x2 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK128 (0x3 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK256 (0x4 << 5)
|
||||
#define ADAU17X1_SERIAL_PORT1_BCLK_MASK (0x7 << 5)
|
||||
|
||||
#define ADAU17X1_SERIAL_PORT0_STEREO (0x0 << 1)
|
||||
#define ADAU17X1_SERIAL_PORT0_TDM4 (0x1 << 1)
|
||||
#define ADAU17X1_SERIAL_PORT0_TDM8 (0x2 << 1)
|
||||
#define ADAU17X1_SERIAL_PORT0_TDM_MASK (0x3 << 1)
|
||||
#define ADAU17X1_SERIAL_PORT0_PULSE_MODE BIT(5)
|
||||
|
||||
#define ADAU17X1_CONVERTER0_DAC_PAIR(x) (((x) - 1) << 5)
|
||||
#define ADAU17X1_CONVERTER0_DAC_PAIR_MASK (0x3 << 5)
|
||||
#define ADAU17X1_CONVERTER1_ADC_PAIR(x) ((x) - 1)
|
||||
#define ADAU17X1_CONVERTER1_ADC_PAIR_MASK 0x3
|
||||
|
||||
#define ADAU17X1_CONVERTER0_CONVSR_MASK 0x7
|
||||
|
||||
|
||||
#endif
|
@ -763,14 +763,14 @@ static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
|
||||
case CS42L56_MCLK_11P2896MHZ:
|
||||
case CS42L56_MCLK_12MHZ:
|
||||
case CS42L56_MCLK_12P288MHZ:
|
||||
cs42l56->mclk_div2 = 1;
|
||||
cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
|
||||
cs42l56->mclk_prediv = 0;
|
||||
break;
|
||||
case CS42L56_MCLK_22P5792MHZ:
|
||||
case CS42L56_MCLK_24MHZ:
|
||||
case CS42L56_MCLK_24P576MHZ:
|
||||
cs42l56->mclk_div2 = 1;
|
||||
cs42l56->mclk_prediv = 1;
|
||||
cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
|
||||
cs42l56->mclk_prediv = CS42L56_MCLK_PREDIV;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -844,57 +844,49 @@ static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
/* Hit the DSP Mixer first */
|
||||
snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
|
||||
CS42L56_ADCAMIX_MUTE_MASK |
|
||||
CS42L56_ADCBMIX_MUTE_MASK |
|
||||
CS42L56_PCMAMIX_MUTE_MASK |
|
||||
CS42L56_PCMBMIX_MUTE_MASK |
|
||||
CS42L56_MSTB_MUTE_MASK |
|
||||
CS42L56_MSTA_MUTE_MASK,
|
||||
CS42L56_MUTE);
|
||||
CS42L56_ADCBMIX_MUTE_MASK |
|
||||
CS42L56_PCMAMIX_MUTE_MASK |
|
||||
CS42L56_PCMBMIX_MUTE_MASK |
|
||||
CS42L56_MSTB_MUTE_MASK |
|
||||
CS42L56_MSTA_MUTE_MASK,
|
||||
CS42L56_MUTE_ALL);
|
||||
/* Mute ADC's */
|
||||
snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
|
||||
CS42L56_ADCA_MUTE_MASK |
|
||||
CS42L56_ADCB_MUTE_MASK,
|
||||
CS42L56_MUTE);
|
||||
CS42L56_ADCA_MUTE_MASK |
|
||||
CS42L56_ADCB_MUTE_MASK,
|
||||
CS42L56_MUTE_ALL);
|
||||
/* HP And LO */
|
||||
snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
|
||||
CS42L56_HP_MUTE_MASK,
|
||||
CS42L56_MUTE);
|
||||
CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
|
||||
snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
|
||||
CS42L56_HP_MUTE_MASK,
|
||||
CS42L56_MUTE);
|
||||
CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
|
||||
snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
|
||||
CS42L56_LO_MUTE_MASK,
|
||||
CS42L56_MUTE);
|
||||
CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
|
||||
snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
|
||||
CS42L56_LO_MUTE_MASK,
|
||||
CS42L56_MUTE);
|
||||
|
||||
|
||||
CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
|
||||
} else {
|
||||
snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
|
||||
CS42L56_ADCAMIX_MUTE_MASK |
|
||||
CS42L56_ADCBMIX_MUTE_MASK |
|
||||
CS42L56_PCMAMIX_MUTE_MASK |
|
||||
CS42L56_PCMBMIX_MUTE_MASK |
|
||||
CS42L56_MSTB_MUTE_MASK |
|
||||
CS42L56_MSTA_MUTE_MASK,
|
||||
CS42L56_UNMUTE);
|
||||
CS42L56_ADCBMIX_MUTE_MASK |
|
||||
CS42L56_PCMAMIX_MUTE_MASK |
|
||||
CS42L56_PCMBMIX_MUTE_MASK |
|
||||
CS42L56_MSTB_MUTE_MASK |
|
||||
CS42L56_MSTA_MUTE_MASK,
|
||||
CS42L56_UNMUTE);
|
||||
|
||||
snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
|
||||
CS42L56_ADCA_MUTE_MASK |
|
||||
CS42L56_ADCB_MUTE_MASK,
|
||||
CS42L56_UNMUTE);
|
||||
CS42L56_ADCA_MUTE_MASK |
|
||||
CS42L56_ADCB_MUTE_MASK,
|
||||
CS42L56_UNMUTE);
|
||||
|
||||
snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
|
||||
CS42L56_HP_MUTE_MASK,
|
||||
CS42L56_UNMUTE);
|
||||
CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
|
||||
snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
|
||||
CS42L56_HP_MUTE_MASK,
|
||||
CS42L56_UNMUTE);
|
||||
CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
|
||||
snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
|
||||
CS42L56_LO_MUTE_MASK,
|
||||
CS42L56_UNMUTE);
|
||||
CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
|
||||
snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
|
||||
CS42L56_LO_MUTE_MASK,
|
||||
CS42L56_UNMUTE);
|
||||
CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -80,19 +80,21 @@
|
||||
#define CS42L56_PDN_HPB_MASK 0xc0
|
||||
|
||||
/* serial port and clk masks */
|
||||
#define CS42L56_MASTER_MODE 1
|
||||
#define CS42L56_MASTER_MODE 0x40
|
||||
#define CS42L56_SLAVE_MODE 0
|
||||
#define CS42L56_MS_MODE_MASK 0x40
|
||||
#define CS42L56_SCLK_INV 1
|
||||
#define CS42L56_SCLK_INV 0x20
|
||||
#define CS42L56_SCLK_INV_MASK 0x20
|
||||
#define CS42L56_SCLK_MCLK_MASK 0x18
|
||||
#define CS42L56_MCLK_PREDIV 0x04
|
||||
#define CS42L56_MCLK_PREDIV_MASK 0x04
|
||||
#define CS42L56_MCLK_DIV2 0x02
|
||||
#define CS42L56_MCLK_DIV2_MASK 0x02
|
||||
#define CS42L56_MCLK_DIS_MASK 0x01
|
||||
#define CS42L56_CLK_AUTO_MASK 0x20
|
||||
#define CS42L56_CLK_RATIO_MASK 0x1f
|
||||
#define CS42L56_DIG_FMT_I2S 0
|
||||
#define CS42L56_DIG_FMT_LEFT_J 1
|
||||
#define CS42L56_DIG_FMT_LEFT_J 0x08
|
||||
#define CS42L56_DIG_FMT_MASK 0x08
|
||||
|
||||
/* Class H and misc ctl masks */
|
||||
@ -116,7 +118,7 @@
|
||||
#define CS42L56_DEEMPH_MASK 0x40
|
||||
#define CS42L56_PLYBCK_GANG_MASK 0x10
|
||||
#define CS42L56_PCM_INV_MASK 0x0c
|
||||
#define CS42L56_MUTE 1
|
||||
#define CS42L56_MUTE_ALL 0xff
|
||||
#define CS42L56_UNMUTE 0
|
||||
#define CS42L56_ADCAMIX_MUTE_MASK 0x40
|
||||
#define CS42L56_ADCBMIX_MUTE_MASK 0x80
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -1547,19 +1548,19 @@ static const int lrclk_rates[] = {
|
||||
};
|
||||
|
||||
static const int user_pclk_rates[] = {
|
||||
13000000, 13000000
|
||||
13000000, 13000000, 19200000, 19200000,
|
||||
};
|
||||
|
||||
static const int user_lrclk_rates[] = {
|
||||
44100, 48000
|
||||
44100, 48000, 44100, 48000,
|
||||
};
|
||||
|
||||
static const unsigned long long ni_value[] = {
|
||||
3528, 768
|
||||
3528, 768, 441, 8
|
||||
};
|
||||
|
||||
static const unsigned long long mi_value[] = {
|
||||
8125, 1625
|
||||
8125, 1625, 1500, 25
|
||||
};
|
||||
|
||||
static void max98090_configure_bclk(struct snd_soc_codec *codec)
|
||||
@ -1800,6 +1801,19 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/*
|
||||
* SND_SOC_BIAS_PREPARE is called while preparing for a
|
||||
* transition to ON or away from ON. If current bias_level
|
||||
* is SND_SOC_BIAS_ON, then it is preparing for a transition
|
||||
* away from ON. Disable the clock in that case, otherwise
|
||||
* enable it.
|
||||
*/
|
||||
if (!IS_ERR(max98090->mclk)) {
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
|
||||
clk_disable_unprepare(max98090->mclk);
|
||||
else
|
||||
clk_prepare_enable(max98090->mclk);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
@ -1929,6 +1943,11 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
|
||||
if (freq == max98090->sysclk)
|
||||
return 0;
|
||||
|
||||
if (!IS_ERR(max98090->mclk)) {
|
||||
freq = clk_round_rate(max98090->mclk, freq);
|
||||
clk_set_rate(max98090->mclk, freq);
|
||||
}
|
||||
|
||||
/* Setup clocks for slave mode, and using the PLL
|
||||
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
|
||||
* 0x02 (when master clk is 20MHz to 40MHz)..
|
||||
@ -2213,6 +2232,10 @@ static int max98090_probe(struct snd_soc_codec *codec)
|
||||
|
||||
dev_dbg(codec->dev, "max98090_probe\n");
|
||||
|
||||
max98090->mclk = devm_clk_get(codec->dev, "mclk");
|
||||
if (PTR_ERR(max98090->mclk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
max98090->codec = codec;
|
||||
|
||||
/* Reset the codec, the DSP core, and disable all interrupts */
|
||||
|
@ -1524,6 +1524,7 @@ struct max98090_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
enum max98090_type devtype;
|
||||
struct max98090_pdata *pdata;
|
||||
struct clk *mclk;
|
||||
unsigned int sysclk;
|
||||
unsigned int bclk;
|
||||
unsigned int lrclk;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/clk.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -42,6 +43,7 @@ struct max98095_priv {
|
||||
struct regmap *regmap;
|
||||
enum max98095_type devtype;
|
||||
struct max98095_pdata *pdata;
|
||||
struct clk *mclk;
|
||||
unsigned int sysclk;
|
||||
struct max98095_cdata dai[3];
|
||||
const char **eq_texts;
|
||||
@ -1395,6 +1397,11 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
|
||||
if (freq == max98095->sysclk)
|
||||
return 0;
|
||||
|
||||
if (!IS_ERR(max98095->mclk)) {
|
||||
freq = clk_round_rate(max98095->mclk, freq);
|
||||
clk_set_rate(max98095->mclk, freq);
|
||||
}
|
||||
|
||||
/* Setup clocks for slave mode, and using the PLL
|
||||
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
|
||||
* 0x02 (when master clk is 20MHz to 40MHz)..
|
||||
@ -1634,6 +1641,19 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/*
|
||||
* SND_SOC_BIAS_PREPARE is called while preparing for a
|
||||
* transition to ON or away from ON. If current bias_level
|
||||
* is SND_SOC_BIAS_ON, then it is preparing for a transition
|
||||
* away from ON. Disable the clock in that case, otherwise
|
||||
* enable it.
|
||||
*/
|
||||
if (!IS_ERR(max98095->mclk)) {
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
|
||||
clk_disable_unprepare(max98095->mclk);
|
||||
else
|
||||
clk_prepare_enable(max98095->mclk);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
@ -2238,6 +2258,10 @@ static int max98095_probe(struct snd_soc_codec *codec)
|
||||
struct i2c_client *client;
|
||||
int ret = 0;
|
||||
|
||||
max98095->mclk = devm_clk_get(codec->dev, "mclk");
|
||||
if (PTR_ERR(max98095->mclk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
/* reset the codec, the DSP core, and disable all interrupts */
|
||||
max98095_reset(codec);
|
||||
|
||||
|
152
sound/soc/codecs/rl6231.c
Normal file
152
sound/soc/codecs/rl6231.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* rl6231.c - RL6231 class device shared support
|
||||
*
|
||||
* Copyright 2014 Realtek Semiconductor Corp.
|
||||
*
|
||||
* Author: Oder Chiou <oder_chiou@realtek.com>
|
||||
*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "rl6231.h"
|
||||
|
||||
/**
|
||||
* rl6231_calc_dmic_clk - Calculate the parameter of dmic.
|
||||
*
|
||||
* @rate: base clock rate.
|
||||
*
|
||||
* Choose dmic clock between 1MHz and 3MHz.
|
||||
* It is better for clock to approximate 3MHz.
|
||||
*/
|
||||
int rl6231_calc_dmic_clk(int rate)
|
||||
{
|
||||
int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL;
|
||||
int i, red, bound, temp;
|
||||
|
||||
red = 3000000 * 12;
|
||||
for (i = 0; i < ARRAY_SIZE(div); i++) {
|
||||
bound = div[i] * 3000000;
|
||||
if (rate > bound)
|
||||
continue;
|
||||
temp = bound - rate;
|
||||
if (temp < red) {
|
||||
red = temp;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk);
|
||||
|
||||
/**
|
||||
* rl6231_pll_calc - Calcualte PLL M/N/K code.
|
||||
* @freq_in: external clock provided to codec.
|
||||
* @freq_out: target clock which codec works on.
|
||||
* @pll_code: Pointer to structure with M, N, K and bypass flag.
|
||||
*
|
||||
* Calcualte M/N/K code to configure PLL for codec.
|
||||
*
|
||||
* Returns 0 for success or negative error code.
|
||||
*/
|
||||
int rl6231_pll_calc(const unsigned int freq_in,
|
||||
const unsigned int freq_out, struct rl6231_pll_code *pll_code)
|
||||
{
|
||||
int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX;
|
||||
int k, red, n_t, pll_out, in_t, out_t;
|
||||
int n = 0, m = 0, m_t = 0;
|
||||
int red_t = abs(freq_out - freq_in);
|
||||
bool bypass = false;
|
||||
|
||||
if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in)
|
||||
return -EINVAL;
|
||||
|
||||
k = 100000000 / freq_out - 2;
|
||||
if (k > RL6231_PLL_K_MAX)
|
||||
k = RL6231_PLL_K_MAX;
|
||||
for (n_t = 0; n_t <= max_n; n_t++) {
|
||||
in_t = freq_in / (k + 2);
|
||||
pll_out = freq_out / (n_t + 2);
|
||||
if (in_t < 0)
|
||||
continue;
|
||||
if (in_t == pll_out) {
|
||||
bypass = true;
|
||||
n = n_t;
|
||||
goto code_find;
|
||||
}
|
||||
red = abs(in_t - pll_out);
|
||||
if (red < red_t) {
|
||||
bypass = true;
|
||||
n = n_t;
|
||||
m = m_t;
|
||||
if (red == 0)
|
||||
goto code_find;
|
||||
red_t = red;
|
||||
}
|
||||
for (m_t = 0; m_t <= max_m; m_t++) {
|
||||
out_t = in_t / (m_t + 2);
|
||||
red = abs(out_t - pll_out);
|
||||
if (red < red_t) {
|
||||
bypass = false;
|
||||
n = n_t;
|
||||
m = m_t;
|
||||
if (red == 0)
|
||||
goto code_find;
|
||||
red_t = red;
|
||||
}
|
||||
}
|
||||
}
|
||||
pr_debug("Only get approximation about PLL\n");
|
||||
|
||||
code_find:
|
||||
|
||||
pll_code->m_bp = bypass;
|
||||
pll_code->m_code = m;
|
||||
pll_code->n_code = n;
|
||||
pll_code->k_code = k;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rl6231_pll_calc);
|
||||
|
||||
int rl6231_get_clk_info(int sclk, int rate)
|
||||
{
|
||||
int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
|
||||
if (sclk <= 0 || rate <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
rate = rate << 8;
|
||||
for (i = 0; i < ARRAY_SIZE(pd); i++)
|
||||
if (sclk == rate * pd[i])
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rl6231_get_clk_info);
|
||||
|
||||
MODULE_DESCRIPTION("RL6231 class device shared support");
|
||||
MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
34
sound/soc/codecs/rl6231.h
Normal file
34
sound/soc/codecs/rl6231.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* rl6231.h - RL6231 class device shared support
|
||||
*
|
||||
* Copyright 2014 Realtek Semiconductor Corp.
|
||||
*
|
||||
* Author: Oder Chiou <oder_chiou@realtek.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __RL6231_H__
|
||||
#define __RL6231_H__
|
||||
|
||||
#define RL6231_PLL_INP_MAX 40000000
|
||||
#define RL6231_PLL_INP_MIN 256000
|
||||
#define RL6231_PLL_N_MAX 0x1ff
|
||||
#define RL6231_PLL_K_MAX 0x1f
|
||||
#define RL6231_PLL_M_MAX 0xf
|
||||
|
||||
struct rl6231_pll_code {
|
||||
bool m_bp; /* Indicates bypass m code or not. */
|
||||
int m_code;
|
||||
int n_code;
|
||||
int k_code;
|
||||
};
|
||||
|
||||
int rl6231_calc_dmic_clk(int rate);
|
||||
int rl6231_pll_calc(const unsigned int freq_in,
|
||||
const unsigned int freq_out, struct rl6231_pll_code *pll_code);
|
||||
int rl6231_get_clk_info(int sclk, int rate);
|
||||
|
||||
#endif /* __RL6231_H__ */
|
@ -31,6 +31,7 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "rl6231.h"
|
||||
#include "rt5640.h"
|
||||
|
||||
#define RT5640_DEVICE_ID 0x6231
|
||||
@ -453,30 +454,16 @@ static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
|
||||
* @kcontrol: The kcontrol of this widget.
|
||||
* @event: Event id.
|
||||
*
|
||||
* Choose dmic clock between 1MHz and 3MHz.
|
||||
* It is better for clock to approximate 3MHz.
|
||||
*/
|
||||
static int set_dmic_clk(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
|
||||
int div[] = {2, 3, 4, 6, 8, 12};
|
||||
int idx = -EINVAL, i;
|
||||
int rate, red, bound, temp;
|
||||
int idx = -EINVAL;
|
||||
|
||||
idx = rl6231_calc_dmic_clk(rt5640->sysclk);
|
||||
|
||||
rate = rt5640->sysclk;
|
||||
red = 3000000 * 12;
|
||||
for (i = 0; i < ARRAY_SIZE(div); i++) {
|
||||
bound = div[i] * 3000000;
|
||||
if (rate > bound)
|
||||
continue;
|
||||
temp = bound - rate;
|
||||
if (temp < red) {
|
||||
red = temp;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
if (idx < 0)
|
||||
dev_err(codec->dev, "Failed to set DMIC clock\n");
|
||||
else
|
||||
@ -1639,21 +1626,6 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_clk_info(int sclk, int rate)
|
||||
{
|
||||
int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
|
||||
if (sclk <= 0 || rate <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
rate = rate << 8;
|
||||
for (i = 0; i < ARRAY_SIZE(pd); i++)
|
||||
if (sclk == rate * pd[i])
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rt5640_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -1663,7 +1635,7 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
|
||||
int dai_sel, pre_div, bclk_ms, frame_size;
|
||||
|
||||
rt5640->lrck[dai->id] = params_rate(params);
|
||||
pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
|
||||
pre_div = rl6231_get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
|
||||
if (pre_div < 0) {
|
||||
dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
|
||||
rt5640->lrck[dai->id], dai->id);
|
||||
@ -1820,65 +1792,12 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rt5640_pll_calc - Calculate PLL M/N/K code.
|
||||
* @freq_in: external clock provided to codec.
|
||||
* @freq_out: target clock which codec works on.
|
||||
* @pll_code: Pointer to structure with M, N, K and bypass flag.
|
||||
*
|
||||
* Calculate M/N/K code to configure PLL for codec. And K is assigned to 2
|
||||
* which make calculation more efficiently.
|
||||
*
|
||||
* Returns 0 for success or negative error code.
|
||||
*/
|
||||
static int rt5640_pll_calc(const unsigned int freq_in,
|
||||
const unsigned int freq_out, struct rt5640_pll_code *pll_code)
|
||||
{
|
||||
int max_n = RT5640_PLL_N_MAX, max_m = RT5640_PLL_M_MAX;
|
||||
int n = 0, m = 0, red, n_t, m_t, in_t, out_t;
|
||||
int red_t = abs(freq_out - freq_in);
|
||||
bool bypass = false;
|
||||
|
||||
if (RT5640_PLL_INP_MAX < freq_in || RT5640_PLL_INP_MIN > freq_in)
|
||||
return -EINVAL;
|
||||
|
||||
for (n_t = 0; n_t <= max_n; n_t++) {
|
||||
in_t = (freq_in >> 1) + (freq_in >> 2) * n_t;
|
||||
if (in_t < 0)
|
||||
continue;
|
||||
if (in_t == freq_out) {
|
||||
bypass = true;
|
||||
n = n_t;
|
||||
goto code_find;
|
||||
}
|
||||
for (m_t = 0; m_t <= max_m; m_t++) {
|
||||
out_t = in_t / (m_t + 2);
|
||||
red = abs(out_t - freq_out);
|
||||
if (red < red_t) {
|
||||
n = n_t;
|
||||
m = m_t;
|
||||
if (red == 0)
|
||||
goto code_find;
|
||||
red_t = red;
|
||||
}
|
||||
}
|
||||
}
|
||||
pr_debug("Only get approximation about PLL\n");
|
||||
|
||||
code_find:
|
||||
pll_code->m_bp = bypass;
|
||||
pll_code->m_code = m;
|
||||
pll_code->n_code = n;
|
||||
pll_code->k_code = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
|
||||
struct rt5640_pll_code *pll_code = &rt5640->pll_code;
|
||||
struct rl6231_pll_code pll_code;
|
||||
int ret, dai_sel;
|
||||
|
||||
if (source == rt5640->pll_src && freq_in == rt5640->pll_in &&
|
||||
@ -1922,20 +1841,21 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = rt5640_pll_calc(freq_in, freq_out, pll_code);
|
||||
ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp,
|
||||
(pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code);
|
||||
dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
|
||||
pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
|
||||
pll_code.n_code, pll_code.k_code);
|
||||
|
||||
snd_soc_write(codec, RT5640_PLL_CTRL1,
|
||||
pll_code->n_code << RT5640_PLL_N_SFT | pll_code->k_code);
|
||||
pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code);
|
||||
snd_soc_write(codec, RT5640_PLL_CTRL2,
|
||||
(pll_code->m_bp ? 0 : pll_code->m_code) << RT5640_PLL_M_SFT |
|
||||
pll_code->m_bp << RT5640_PLL_M_BP_SFT);
|
||||
(pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT |
|
||||
pll_code.m_bp << RT5640_PLL_M_BP_SFT);
|
||||
|
||||
rt5640->pll_in = freq_in;
|
||||
rt5640->pll_out = freq_out;
|
||||
|
@ -2079,13 +2079,6 @@ enum {
|
||||
RT5640_DMIC2,
|
||||
};
|
||||
|
||||
struct rt5640_pll_code {
|
||||
bool m_bp; /* Indicates bypass m code or not. */
|
||||
int m_code;
|
||||
int n_code;
|
||||
int k_code;
|
||||
};
|
||||
|
||||
struct rt5640_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
struct rt5640_platform_data pdata;
|
||||
@ -2097,7 +2090,6 @@ struct rt5640_priv {
|
||||
int bclk[RT5640_AIFS];
|
||||
int master[RT5640_AIFS];
|
||||
|
||||
struct rt5640_pll_code pll_code;
|
||||
int pll_src;
|
||||
int pll_in;
|
||||
int pll_out;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "rl6231.h"
|
||||
#include "rt5645.h"
|
||||
|
||||
#define RT5645_DEVICE_ID 0x6308
|
||||
@ -519,30 +520,15 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
|
||||
* @kcontrol: The kcontrol of this widget.
|
||||
* @event: Event id.
|
||||
*
|
||||
* Choose dmic clock between 1MHz and 3MHz.
|
||||
* It is better for clock to approximate 3MHz.
|
||||
*/
|
||||
static int set_dmic_clk(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
||||
int div[] = {2, 3, 4, 6, 8, 12};
|
||||
int idx = -EINVAL, i;
|
||||
int rate, red, bound, temp;
|
||||
int idx = -EINVAL;
|
||||
|
||||
rate = rt5645->sysclk;
|
||||
red = 3000000 * 12;
|
||||
for (i = 0; i < ARRAY_SIZE(div); i++) {
|
||||
bound = div[i] * 3000000;
|
||||
if (rate > bound)
|
||||
continue;
|
||||
temp = bound - rate;
|
||||
if (temp < red) {
|
||||
red = temp;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
idx = rl6231_calc_dmic_clk(rt5645->sysclk);
|
||||
|
||||
if (idx < 0)
|
||||
dev_err(codec->dev, "Failed to set DMIC clock\n");
|
||||
@ -1800,21 +1786,6 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
|
||||
{ "SPOR", NULL, "SPK amp" },
|
||||
};
|
||||
|
||||
static int get_clk_info(int sclk, int rate)
|
||||
{
|
||||
int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
|
||||
if (sclk <= 0 || rate <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
rate = rate << 8;
|
||||
for (i = 0; i < ARRAY_SIZE(pd); i++)
|
||||
if (sclk == rate * pd[i])
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rt5645_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -1824,7 +1795,7 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
|
||||
int pre_div, bclk_ms, frame_size;
|
||||
|
||||
rt5645->lrck[dai->id] = params_rate(params);
|
||||
pre_div = get_clk_info(rt5645->sysclk, rt5645->lrck[dai->id]);
|
||||
pre_div = rl6231_get_clk_info(rt5645->sysclk, rt5645->lrck[dai->id]);
|
||||
if (pre_div < 0) {
|
||||
dev_err(codec->dev, "Unsupported clock setting\n");
|
||||
return -EINVAL;
|
||||
@ -1978,80 +1949,12 @@ static int rt5645_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rt5645_pll_calc - Calcualte PLL M/N/K code.
|
||||
* @freq_in: external clock provided to codec.
|
||||
* @freq_out: target clock which codec works on.
|
||||
* @pll_code: Pointer to structure with M, N, K and bypass flag.
|
||||
*
|
||||
* Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2
|
||||
* which make calculation more efficiently.
|
||||
*
|
||||
* Returns 0 for success or negative error code.
|
||||
*/
|
||||
static int rt5645_pll_calc(const unsigned int freq_in,
|
||||
const unsigned int freq_out, struct rt5645_pll_code *pll_code)
|
||||
{
|
||||
int max_n = RT5645_PLL_N_MAX, max_m = RT5645_PLL_M_MAX;
|
||||
int k, n = 0, m = 0, red, n_t, m_t, pll_out, in_t, out_t;
|
||||
int red_t = abs(freq_out - freq_in);
|
||||
bool bypass = false;
|
||||
|
||||
if (RT5645_PLL_INP_MAX < freq_in || RT5645_PLL_INP_MIN > freq_in)
|
||||
return -EINVAL;
|
||||
|
||||
k = 100000000 / freq_out - 2;
|
||||
if (k > RT5645_PLL_K_MAX)
|
||||
k = RT5645_PLL_K_MAX;
|
||||
for (n_t = 0; n_t <= max_n; n_t++) {
|
||||
in_t = freq_in / (k + 2);
|
||||
pll_out = freq_out / (n_t + 2);
|
||||
if (in_t < 0)
|
||||
continue;
|
||||
if (in_t == pll_out) {
|
||||
bypass = true;
|
||||
n = n_t;
|
||||
goto code_find;
|
||||
}
|
||||
red = abs(in_t - pll_out);
|
||||
if (red < red_t) {
|
||||
bypass = true;
|
||||
n = n_t;
|
||||
m = m_t;
|
||||
if (red == 0)
|
||||
goto code_find;
|
||||
red_t = red;
|
||||
}
|
||||
for (m_t = 0; m_t <= max_m; m_t++) {
|
||||
out_t = in_t / (m_t + 2);
|
||||
red = abs(out_t - pll_out);
|
||||
if (red < red_t) {
|
||||
bypass = false;
|
||||
n = n_t;
|
||||
m = m_t;
|
||||
if (red == 0)
|
||||
goto code_find;
|
||||
red_t = red;
|
||||
}
|
||||
}
|
||||
}
|
||||
pr_debug("Only get approximation about PLL\n");
|
||||
|
||||
code_find:
|
||||
|
||||
pll_code->m_bp = bypass;
|
||||
pll_code->m_code = m;
|
||||
pll_code->n_code = n;
|
||||
pll_code->k_code = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
||||
struct rt5645_pll_code pll_code;
|
||||
struct rl6231_pll_code pll_code;
|
||||
int ret;
|
||||
|
||||
if (source == rt5645->pll_src && freq_in == rt5645->pll_in &&
|
||||
@ -2094,7 +1997,7 @@ static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = rt5645_pll_calc(freq_in, freq_out, &pll_code);
|
||||
ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
|
||||
return ret;
|
||||
|
@ -2162,13 +2162,6 @@ enum {
|
||||
RT5645_DMIC_DATA_GPIO11,
|
||||
};
|
||||
|
||||
struct rt5645_pll_code {
|
||||
bool m_bp; /* Indicates bypass m code or not. */
|
||||
int m_code;
|
||||
int n_code;
|
||||
int k_code;
|
||||
};
|
||||
|
||||
struct rt5645_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
struct rt5645_platform_data pdata;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "rl6231.h"
|
||||
#include "rt5651.h"
|
||||
|
||||
#define RT5651_DEVICE_ID_VALUE 0x6281
|
||||
@ -371,29 +372,16 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
|
||||
* @kcontrol: The kcontrol of this widget.
|
||||
* @event: Event id.
|
||||
*
|
||||
* Choose dmic clock between 1MHz and 3MHz.
|
||||
* It is better for clock to approximate 3MHz.
|
||||
*/
|
||||
static int set_dmic_clk(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
|
||||
int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL;
|
||||
int i, rate, red, bound, temp;
|
||||
int idx = -EINVAL;
|
||||
|
||||
idx = rl6231_calc_dmic_clk(rt5651->sysclk);
|
||||
|
||||
rate = rt5651->sysclk;
|
||||
red = 3000000 * 12;
|
||||
for (i = 0; i < ARRAY_SIZE(div); i++) {
|
||||
bound = div[i] * 3000000;
|
||||
if (rate > bound)
|
||||
continue;
|
||||
temp = bound - rate;
|
||||
if (temp < red) {
|
||||
red = temp;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
if (idx < 0)
|
||||
dev_err(codec->dev, "Failed to set DMIC clock\n");
|
||||
else
|
||||
@ -1350,21 +1338,6 @@ static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {
|
||||
{"PDMR", NULL, "PDM R Mux"},
|
||||
};
|
||||
|
||||
static int get_clk_info(int sclk, int rate)
|
||||
{
|
||||
int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
|
||||
if (sclk <= 0 || rate <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
rate = rate << 8;
|
||||
for (i = 0; i < ARRAY_SIZE(pd); i++)
|
||||
if (sclk == rate * pd[i])
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rt5651_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
@ -1374,7 +1347,7 @@ static int rt5651_hw_params(struct snd_pcm_substream *substream,
|
||||
int pre_div, bclk_ms, frame_size;
|
||||
|
||||
rt5651->lrck[dai->id] = params_rate(params);
|
||||
pre_div = get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]);
|
||||
pre_div = rl6231_get_clk_info(rt5651->sysclk, rt5651->lrck[dai->id]);
|
||||
|
||||
if (pre_div < 0) {
|
||||
dev_err(codec->dev, "Unsupported clock setting\n");
|
||||
@ -1528,65 +1501,12 @@ static int rt5651_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rt5651_pll_calc - Calcualte PLL M/N/K code.
|
||||
* @freq_in: external clock provided to codec.
|
||||
* @freq_out: target clock which codec works on.
|
||||
* @pll_code: Pointer to structure with M, N, K and bypass flag.
|
||||
*
|
||||
* Calcualte M/N/K code to configure PLL for codec. And K is assigned to 2
|
||||
* which make calculation more efficiently.
|
||||
*
|
||||
* Returns 0 for success or negative error code.
|
||||
*/
|
||||
static int rt5651_pll_calc(const unsigned int freq_in,
|
||||
const unsigned int freq_out, struct rt5651_pll_code *pll_code)
|
||||
{
|
||||
int max_n = RT5651_PLL_N_MAX, max_m = RT5651_PLL_M_MAX;
|
||||
int n = 0, m = 0, red, n_t, m_t, in_t, out_t;
|
||||
int red_t = abs(freq_out - freq_in);
|
||||
bool bypass = false;
|
||||
|
||||
if (RT5651_PLL_INP_MAX < freq_in || RT5651_PLL_INP_MIN > freq_in)
|
||||
return -EINVAL;
|
||||
|
||||
for (n_t = 0; n_t <= max_n; n_t++) {
|
||||
in_t = (freq_in >> 1) + (freq_in >> 2) * n_t;
|
||||
if (in_t < 0)
|
||||
continue;
|
||||
if (in_t == freq_out) {
|
||||
bypass = true;
|
||||
n = n_t;
|
||||
goto code_find;
|
||||
}
|
||||
for (m_t = 0; m_t <= max_m; m_t++) {
|
||||
out_t = in_t / (m_t + 2);
|
||||
red = abs(out_t - freq_out);
|
||||
if (red < red_t) {
|
||||
n = n_t;
|
||||
m = m_t;
|
||||
if (red == 0)
|
||||
goto code_find;
|
||||
red_t = red;
|
||||
}
|
||||
}
|
||||
}
|
||||
pr_debug("Only get approximation about PLL\n");
|
||||
|
||||
code_find:
|
||||
pll_code->m_bp = bypass;
|
||||
pll_code->m_code = m;
|
||||
pll_code->n_code = n;
|
||||
pll_code->k_code = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
|
||||
struct rt5651_pll_code *pll_code = &rt5651->pll_code;
|
||||
struct rl6231_pll_code pll_code;
|
||||
int ret;
|
||||
|
||||
if (source == rt5651->pll_src && freq_in == rt5651->pll_in &&
|
||||
@ -1621,20 +1541,21 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = rt5651_pll_calc(freq_in, freq_out, pll_code);
|
||||
ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp,
|
||||
(pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code);
|
||||
dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
|
||||
pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
|
||||
pll_code.n_code, pll_code.k_code);
|
||||
|
||||
snd_soc_write(codec, RT5651_PLL_CTRL1,
|
||||
pll_code->n_code << RT5651_PLL_N_SFT | pll_code->k_code);
|
||||
pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code);
|
||||
snd_soc_write(codec, RT5651_PLL_CTRL2,
|
||||
(pll_code->m_bp ? 0 : pll_code->m_code) << RT5651_PLL_M_SFT |
|
||||
pll_code->m_bp << RT5651_PLL_M_BP_SFT);
|
||||
(pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT |
|
||||
pll_code.m_bp << RT5651_PLL_M_BP_SFT);
|
||||
|
||||
rt5651->pll_in = freq_in;
|
||||
rt5651->pll_out = freq_out;
|
||||
|
@ -2069,7 +2069,6 @@ struct rt5651_priv {
|
||||
int bclk[RT5651_AIFS];
|
||||
int master[RT5651_AIFS];
|
||||
|
||||
struct rt5651_pll_code pll_code;
|
||||
int pll_src;
|
||||
int pll_in;
|
||||
int pll_out;
|
||||
|
3498
sound/soc/codecs/rt5677.c
Normal file
3498
sound/soc/codecs/rt5677.c
Normal file
File diff suppressed because it is too large
Load Diff
1451
sound/soc/codecs/rt5677.h
Normal file
1451
sound/soc/codecs/rt5677.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -36,18 +36,32 @@
|
||||
|
||||
/* default value of sgtl5000 registers */
|
||||
static const struct reg_default sgtl5000_reg_defaults[] = {
|
||||
{ SGTL5000_CHIP_DIG_POWER, 0x0000 },
|
||||
{ SGTL5000_CHIP_CLK_CTRL, 0x0008 },
|
||||
{ SGTL5000_CHIP_I2S_CTRL, 0x0010 },
|
||||
{ SGTL5000_CHIP_SSS_CTRL, 0x0010 },
|
||||
{ SGTL5000_CHIP_ADCDAC_CTRL, 0x020c },
|
||||
{ SGTL5000_CHIP_DAC_VOL, 0x3c3c },
|
||||
{ SGTL5000_CHIP_PAD_STRENGTH, 0x015f },
|
||||
{ SGTL5000_CHIP_ANA_ADC_CTRL, 0x0000 },
|
||||
{ SGTL5000_CHIP_ANA_HP_CTRL, 0x1818 },
|
||||
{ SGTL5000_CHIP_ANA_CTRL, 0x0111 },
|
||||
{ SGTL5000_CHIP_LINREG_CTRL, 0x0000 },
|
||||
{ SGTL5000_CHIP_REF_CTRL, 0x0000 },
|
||||
{ SGTL5000_CHIP_MIC_CTRL, 0x0000 },
|
||||
{ SGTL5000_CHIP_LINE_OUT_CTRL, 0x0000 },
|
||||
{ SGTL5000_CHIP_LINE_OUT_VOL, 0x0404 },
|
||||
{ SGTL5000_CHIP_ANA_POWER, 0x7060 },
|
||||
{ SGTL5000_CHIP_PLL_CTRL, 0x5000 },
|
||||
{ SGTL5000_CHIP_CLK_TOP_CTRL, 0x0000 },
|
||||
{ SGTL5000_CHIP_ANA_STATUS, 0x0000 },
|
||||
{ SGTL5000_CHIP_SHORT_CTRL, 0x0000 },
|
||||
{ SGTL5000_CHIP_ANA_TEST2, 0x0000 },
|
||||
{ SGTL5000_DAP_CTRL, 0x0000 },
|
||||
{ SGTL5000_DAP_PEQ, 0x0000 },
|
||||
{ SGTL5000_DAP_BASS_ENHANCE, 0x0040 },
|
||||
{ SGTL5000_DAP_BASS_ENHANCE_CTRL, 0x051f },
|
||||
{ SGTL5000_DAP_AUDIO_EQ, 0x0000 },
|
||||
{ SGTL5000_DAP_SURROUND, 0x0040 },
|
||||
{ SGTL5000_DAP_EQ_BASS_BAND0, 0x002f },
|
||||
{ SGTL5000_DAP_EQ_BASS_BAND1, 0x002f },
|
||||
@ -55,6 +69,7 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
|
||||
{ SGTL5000_DAP_EQ_BASS_BAND3, 0x002f },
|
||||
{ SGTL5000_DAP_EQ_BASS_BAND4, 0x002f },
|
||||
{ SGTL5000_DAP_MAIN_CHAN, 0x8000 },
|
||||
{ SGTL5000_DAP_MIX_CHAN, 0x0000 },
|
||||
{ SGTL5000_DAP_AVC_CTRL, 0x0510 },
|
||||
{ SGTL5000_DAP_AVC_THRESHOLD, 0x1473 },
|
||||
{ SGTL5000_DAP_AVC_ATTACK, 0x0028 },
|
||||
@ -1068,71 +1083,11 @@ static int sgtl5000_suspend(struct snd_soc_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* restore all sgtl5000 registers,
|
||||
* since a big hole between dap and regular registers,
|
||||
* we will restore them respectively.
|
||||
*/
|
||||
static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
u16 reg;
|
||||
|
||||
/* restore regular registers */
|
||||
for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) {
|
||||
|
||||
/* These regs should restore in particular order */
|
||||
if (reg == SGTL5000_CHIP_ANA_POWER ||
|
||||
reg == SGTL5000_CHIP_CLK_CTRL ||
|
||||
reg == SGTL5000_CHIP_LINREG_CTRL ||
|
||||
reg == SGTL5000_CHIP_LINE_OUT_CTRL ||
|
||||
reg == SGTL5000_CHIP_REF_CTRL)
|
||||
continue;
|
||||
|
||||
snd_soc_write(codec, reg, cache[reg]);
|
||||
}
|
||||
|
||||
/* restore dap registers */
|
||||
for (reg = SGTL5000_DAP_REG_OFFSET; reg < SGTL5000_MAX_REG_OFFSET; reg += 2)
|
||||
snd_soc_write(codec, reg, cache[reg]);
|
||||
|
||||
/*
|
||||
* restore these regs according to the power setting sequence in
|
||||
* sgtl5000_set_power_regs() and clock setting sequence in
|
||||
* sgtl5000_set_clock().
|
||||
*
|
||||
* The order of restore is:
|
||||
* 1. SGTL5000_CHIP_CLK_CTRL MCLK_FREQ bits (1:0) should be restore after
|
||||
* SGTL5000_CHIP_ANA_POWER PLL bits set
|
||||
* 2. SGTL5000_CHIP_LINREG_CTRL should be set before
|
||||
* SGTL5000_CHIP_ANA_POWER LINREG_D restored
|
||||
* 3. SGTL5000_CHIP_REF_CTRL controls Analog Ground Voltage,
|
||||
* prefer to resotre it after SGTL5000_CHIP_ANA_POWER restored
|
||||
*/
|
||||
snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL,
|
||||
cache[SGTL5000_CHIP_LINREG_CTRL]);
|
||||
|
||||
snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER,
|
||||
cache[SGTL5000_CHIP_ANA_POWER]);
|
||||
|
||||
snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL,
|
||||
cache[SGTL5000_CHIP_CLK_CTRL]);
|
||||
|
||||
snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL,
|
||||
cache[SGTL5000_CHIP_REF_CTRL]);
|
||||
|
||||
snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
|
||||
cache[SGTL5000_CHIP_LINE_OUT_CTRL]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sgtl5000_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
/* Bring the codec back up to standby to enable regulators */
|
||||
sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
/* Restore registers by cached in memory */
|
||||
sgtl5000_restore_regs(codec);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@ -109,7 +109,7 @@ static void enable_and_reset_codec(struct regmap *regmap,
|
||||
{
|
||||
regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
|
||||
codec_enable_bits | codec_reset_bits,
|
||||
codec_enable_bits | ~codec_reset_bits);
|
||||
codec_enable_bits);
|
||||
msleep(20);
|
||||
regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
|
||||
codec_reset_bits, codec_reset_bits);
|
||||
@ -128,8 +128,7 @@ static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
regmap_update_bits(sirf_audio_codec->regmap,
|
||||
AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS,
|
||||
~ATLAS6_CODEC_ENABLE_BITS);
|
||||
AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -151,8 +150,7 @@ static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
regmap_update_bits(sirf_audio_codec->regmap,
|
||||
AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS,
|
||||
~PRIMA2_CODEC_ENABLE_BITS);
|
||||
AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -169,7 +169,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
|
||||
mask <<= shift;
|
||||
val <<= shift;
|
||||
|
||||
change = snd_soc_test_bits(codec, val, mask, reg);
|
||||
change = snd_soc_test_bits(codec, reg, mask, val);
|
||||
if (change) {
|
||||
update.kcontrol = kcontrol;
|
||||
update.reg = reg;
|
||||
|
@ -63,6 +63,7 @@ struct wm8804_priv {
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
|
||||
struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
|
||||
int mclk_div;
|
||||
};
|
||||
|
||||
static int txsrc_get(struct snd_kcontrol *kcontrol,
|
||||
@ -318,7 +319,7 @@ static struct {
|
||||
|
||||
#define FIXED_PLL_SIZE ((1ULL << 22) * 10)
|
||||
static int pll_factors(struct pll_div *pll_div, unsigned int target,
|
||||
unsigned int source)
|
||||
unsigned int source, unsigned int mclk_div)
|
||||
{
|
||||
u64 Kpart;
|
||||
unsigned long int K, Ndiv, Nmod, tmp;
|
||||
@ -330,7 +331,8 @@ static int pll_factors(struct pll_div *pll_div, unsigned int target,
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(post_table); i++) {
|
||||
tmp = target * post_table[i].div;
|
||||
if (tmp >= 90000000 && tmp <= 100000000) {
|
||||
if ((tmp >= 90000000 && tmp <= 100000000) &&
|
||||
(mclk_div == post_table[i].mclkdiv)) {
|
||||
pll_div->freqmode = post_table[i].freqmode;
|
||||
pll_div->mclkdiv = post_table[i].mclkdiv;
|
||||
target *= post_table[i].div;
|
||||
@ -387,8 +389,12 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
} else {
|
||||
int ret;
|
||||
struct pll_div pll_div;
|
||||
struct wm8804_priv *wm8804;
|
||||
|
||||
ret = pll_factors(&pll_div, freq_out, freq_in);
|
||||
wm8804 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ret = pll_factors(&pll_div, freq_out, freq_in,
|
||||
wm8804->mclk_div);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -452,6 +458,7 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
|
||||
int div_id, int div)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct wm8804_priv *wm8804;
|
||||
|
||||
codec = dai->codec;
|
||||
switch (div_id) {
|
||||
@ -459,6 +466,10 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
|
||||
snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
|
||||
(div & 0x3) << 4);
|
||||
break;
|
||||
case WM8804_MCLK_DIV:
|
||||
wm8804 = snd_soc_codec_get_drvdata(codec);
|
||||
wm8804->mclk_div = div;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
|
||||
return -EINVAL;
|
||||
|
@ -57,5 +57,9 @@
|
||||
#define WM8804_CLKOUT_SRC_OSCCLK 4
|
||||
|
||||
#define WM8804_CLKOUT_DIV 1
|
||||
#define WM8804_MCLK_DIV 2
|
||||
|
||||
#define WM8804_MCLKDIV_256FS 0
|
||||
#define WM8804_MCLKDIV_128FS 1
|
||||
|
||||
#endif /* _WM8804_H */
|
||||
|
@ -74,8 +74,7 @@ static const char *wm9713_rec_src[] =
|
||||
"Mono Out", "Zh"};
|
||||
static const char *wm9713_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
|
||||
static const char *wm9713_alc_select[] = {"None", "Left", "Right", "Stereo"};
|
||||
static const char *wm9713_mono_pga[] = {"Vmid", "Zh", "Mono", "Inv",
|
||||
"Mono Vmid", "Inv Vmid"};
|
||||
static const char *wm9713_mono_pga[] = {"Vmid", "Zh", "Mono", "Inv"};
|
||||
static const char *wm9713_spk_pga[] =
|
||||
{"Vmid", "Zh", "Headphone", "Speaker", "Inv", "Headphone Vmid",
|
||||
"Speaker Vmid", "Inv Vmid"};
|
||||
|
@ -1543,16 +1543,16 @@ static void wm_adsp2_boot_work(struct work_struct *work)
|
||||
ret = regmap_read(dsp->regmap,
|
||||
dsp->base + ADSP2_CLOCKING, &val);
|
||||
if (ret != 0) {
|
||||
dev_err(dsp->dev, "Failed to read clocking: %d\n", ret);
|
||||
adsp_err(dsp, "Failed to read clocking: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
|
||||
ret = regulator_enable(dsp->dvfs);
|
||||
if (ret != 0) {
|
||||
dev_err(dsp->dev,
|
||||
"Failed to enable supply: %d\n",
|
||||
ret);
|
||||
adsp_err(dsp,
|
||||
"Failed to enable supply: %d\n",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1560,9 +1560,9 @@ static void wm_adsp2_boot_work(struct work_struct *work)
|
||||
1800000,
|
||||
1800000);
|
||||
if (ret != 0) {
|
||||
dev_err(dsp->dev,
|
||||
"Failed to raise supply: %d\n",
|
||||
ret);
|
||||
adsp_err(dsp,
|
||||
"Failed to raise supply: %d\n",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1672,15 +1672,15 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
|
||||
ret = regulator_set_voltage(dsp->dvfs, 1200000,
|
||||
1800000);
|
||||
if (ret != 0)
|
||||
dev_warn(dsp->dev,
|
||||
"Failed to lower supply: %d\n",
|
||||
ret);
|
||||
adsp_warn(dsp,
|
||||
"Failed to lower supply: %d\n",
|
||||
ret);
|
||||
|
||||
ret = regulator_disable(dsp->dvfs);
|
||||
if (ret != 0)
|
||||
dev_err(dsp->dev,
|
||||
"Failed to enable supply: %d\n",
|
||||
ret);
|
||||
adsp_err(dsp,
|
||||
"Failed to enable supply: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
list_for_each_entry(ctl, &dsp->ctl_list, list)
|
||||
@ -1732,28 +1732,25 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
|
||||
adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
|
||||
if (IS_ERR(adsp->dvfs)) {
|
||||
ret = PTR_ERR(adsp->dvfs);
|
||||
dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
|
||||
adsp_err(adsp, "Failed to get DCVDD: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_enable(adsp->dvfs);
|
||||
if (ret != 0) {
|
||||
dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
|
||||
ret);
|
||||
adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
|
||||
if (ret != 0) {
|
||||
dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
|
||||
ret);
|
||||
adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_disable(adsp->dvfs);
|
||||
if (ret != 0) {
|
||||
dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
|
||||
ret);
|
||||
adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ struct snd_soc_card_drvdata_davinci {
|
||||
static int evm_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *soc_card = rtd->codec->card;
|
||||
struct snd_soc_card *soc_card = rtd->card;
|
||||
struct snd_soc_card_drvdata_davinci *drvdata =
|
||||
snd_soc_card_get_drvdata(soc_card);
|
||||
|
||||
@ -51,7 +51,7 @@ static int evm_startup(struct snd_pcm_substream *substream)
|
||||
static void evm_shutdown(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *soc_card = rtd->codec->card;
|
||||
struct snd_soc_card *soc_card = rtd->card;
|
||||
struct snd_soc_card_drvdata_davinci *drvdata =
|
||||
snd_soc_card_get_drvdata(soc_card);
|
||||
|
||||
@ -65,8 +65,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_card *soc_card = codec->card;
|
||||
struct snd_soc_card *soc_card = rtd->card;
|
||||
int ret = 0;
|
||||
unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
|
||||
snd_soc_card_get_drvdata(soc_card))->sysclk;
|
||||
@ -125,7 +124,7 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct device_node *np = codec->card->dev->of_node;
|
||||
struct device_node *np = card->dev->of_node;
|
||||
int ret;
|
||||
|
||||
/* Add davinci-evm specific widgets */
|
||||
|
@ -33,10 +33,10 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/omap-pcm.h>
|
||||
|
||||
#include "davinci-pcm.h"
|
||||
#include "davinci-mcasp.h"
|
||||
#include "../omap/omap-pcm.h"
|
||||
|
||||
#define MCASP_MAX_AFIFO_DEPTH 64
|
||||
|
||||
|
@ -16,6 +16,7 @@ config SND_SOC_FSL_SSI
|
||||
tristate "Synchronous Serial Interface module support"
|
||||
select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
|
||||
select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && ARCH_MXC
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Say Y if you want to add Synchronous Serial Interface (SSI)
|
||||
support for the Freescale CPUs.
|
||||
@ -207,12 +208,7 @@ config SND_SOC_PHYCORE_AC97
|
||||
|
||||
config SND_SOC_EUKREA_TLV320
|
||||
tristate "Eukrea TLV320"
|
||||
depends on MACH_EUKREA_MBIMX27_BASEBOARD \
|
||||
|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
|
||||
|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
|
||||
|| MACH_EUKREA_MBIMXSD51_BASEBOARD \
|
||||
|| (OF && ARM)
|
||||
depends on I2C
|
||||
depends on ARCH_MXC && I2C
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
select SND_SOC_IMX_AUDMUX
|
||||
select SND_SOC_IMX_SSI
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,32 +12,30 @@
|
||||
#ifndef _MPC8610_I2S_H
|
||||
#define _MPC8610_I2S_H
|
||||
|
||||
/* SSI Register Map */
|
||||
struct ccsr_ssi {
|
||||
__be32 stx0; /* 0x.0000 - SSI Transmit Data Register 0 */
|
||||
__be32 stx1; /* 0x.0004 - SSI Transmit Data Register 1 */
|
||||
__be32 srx0; /* 0x.0008 - SSI Receive Data Register 0 */
|
||||
__be32 srx1; /* 0x.000C - SSI Receive Data Register 1 */
|
||||
__be32 scr; /* 0x.0010 - SSI Control Register */
|
||||
__be32 sisr; /* 0x.0014 - SSI Interrupt Status Register Mixed */
|
||||
__be32 sier; /* 0x.0018 - SSI Interrupt Enable Register */
|
||||
__be32 stcr; /* 0x.001C - SSI Transmit Configuration Register */
|
||||
__be32 srcr; /* 0x.0020 - SSI Receive Configuration Register */
|
||||
__be32 stccr; /* 0x.0024 - SSI Transmit Clock Control Register */
|
||||
__be32 srccr; /* 0x.0028 - SSI Receive Clock Control Register */
|
||||
__be32 sfcsr; /* 0x.002C - SSI FIFO Control/Status Register */
|
||||
__be32 str; /* 0x.0030 - SSI Test Register */
|
||||
__be32 sor; /* 0x.0034 - SSI Option Register */
|
||||
__be32 sacnt; /* 0x.0038 - SSI AC97 Control Register */
|
||||
__be32 sacadd; /* 0x.003C - SSI AC97 Command Address Register */
|
||||
__be32 sacdat; /* 0x.0040 - SSI AC97 Command Data Register */
|
||||
__be32 satag; /* 0x.0044 - SSI AC97 Tag Register */
|
||||
__be32 stmsk; /* 0x.0048 - SSI Transmit Time Slot Mask Register */
|
||||
__be32 srmsk; /* 0x.004C - SSI Receive Time Slot Mask Register */
|
||||
__be32 saccst; /* 0x.0050 - SSI AC97 Channel Status Register */
|
||||
__be32 saccen; /* 0x.0054 - SSI AC97 Channel Enable Register */
|
||||
__be32 saccdis; /* 0x.0058 - SSI AC97 Channel Disable Register */
|
||||
};
|
||||
/* SSI registers */
|
||||
#define CCSR_SSI_STX0 0x00
|
||||
#define CCSR_SSI_STX1 0x04
|
||||
#define CCSR_SSI_SRX0 0x08
|
||||
#define CCSR_SSI_SRX1 0x0c
|
||||
#define CCSR_SSI_SCR 0x10
|
||||
#define CCSR_SSI_SISR 0x14
|
||||
#define CCSR_SSI_SIER 0x18
|
||||
#define CCSR_SSI_STCR 0x1c
|
||||
#define CCSR_SSI_SRCR 0x20
|
||||
#define CCSR_SSI_STCCR 0x24
|
||||
#define CCSR_SSI_SRCCR 0x28
|
||||
#define CCSR_SSI_SFCSR 0x2c
|
||||
#define CCSR_SSI_STR 0x30
|
||||
#define CCSR_SSI_SOR 0x34
|
||||
#define CCSR_SSI_SACNT 0x38
|
||||
#define CCSR_SSI_SACADD 0x3c
|
||||
#define CCSR_SSI_SACDAT 0x40
|
||||
#define CCSR_SSI_SATAG 0x44
|
||||
#define CCSR_SSI_STMSK 0x48
|
||||
#define CCSR_SSI_SRMSK 0x4c
|
||||
#define CCSR_SSI_SACCST 0x50
|
||||
#define CCSR_SSI_SACCEN 0x54
|
||||
#define CCSR_SSI_SACCDIS 0x58
|
||||
|
||||
#define CCSR_SSI_SCR_SYNC_TX_FS 0x00001000
|
||||
#define CCSR_SSI_SCR_RFR_CLK_DIS 0x00000800
|
||||
|
@ -24,9 +24,32 @@ struct simple_card_data {
|
||||
struct asoc_simple_dai cpu_dai;
|
||||
struct asoc_simple_dai codec_dai;
|
||||
} *dai_props;
|
||||
unsigned int mclk_fs;
|
||||
struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
|
||||
};
|
||||
|
||||
static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
unsigned int mclk;
|
||||
int ret = 0;
|
||||
|
||||
if (priv->mclk_fs) {
|
||||
mclk = params_rate(params) * priv->mclk_fs;
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
|
||||
SND_SOC_CLOCK_IN);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops asoc_simple_card_ops = {
|
||||
.hw_params = asoc_simple_card_hw_params,
|
||||
};
|
||||
|
||||
static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
|
||||
struct asoc_simple_dai *set)
|
||||
{
|
||||
@ -144,7 +167,8 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
|
||||
static int simple_card_dai_link_of(struct device_node *node,
|
||||
struct device *dev,
|
||||
struct snd_soc_dai_link *dai_link,
|
||||
struct simple_dai_props *dai_props)
|
||||
struct simple_dai_props *dai_props,
|
||||
bool is_top_level_node)
|
||||
{
|
||||
struct device_node *np = NULL;
|
||||
struct device_node *bitclkmaster = NULL;
|
||||
@ -155,7 +179,8 @@ static int simple_card_dai_link_of(struct device_node *node,
|
||||
char *prefix = "";
|
||||
int ret;
|
||||
|
||||
prefix = "simple-audio-card,";
|
||||
if (is_top_level_node)
|
||||
prefix = "simple-audio-card,";
|
||||
|
||||
daifmt = snd_soc_of_parse_daifmt(node, prefix,
|
||||
&bitclkmaster, &framemaster);
|
||||
@ -249,6 +274,7 @@ static int simple_card_dai_link_of(struct device_node *node,
|
||||
sprintf(name, "%s-%s", dai_link->cpu_dai_name,
|
||||
dai_link->codec_dai_name);
|
||||
dai_link->name = dai_link->stream_name = name;
|
||||
dai_link->ops = &asoc_simple_card_ops;
|
||||
|
||||
dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
|
||||
dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
|
||||
@ -298,6 +324,10 @@ static int asoc_simple_card_parse_of(struct device_node *node,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Factor to mclk, used in hw_params() */
|
||||
of_property_read_u32(node, "simple-audio-card,mclk-fs",
|
||||
&priv->mclk_fs);
|
||||
|
||||
dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
|
||||
priv->snd_card.name : "");
|
||||
|
||||
@ -307,14 +337,15 @@ static int asoc_simple_card_parse_of(struct device_node *node,
|
||||
for (i = 0; (np = of_get_next_child(node, np)); i++) {
|
||||
dev_dbg(dev, "\tlink %d:\n", i);
|
||||
ret = simple_card_dai_link_of(np, dev, dai_link + i,
|
||||
dai_props + i);
|
||||
dai_props + i, false);
|
||||
if (ret < 0) {
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = simple_card_dai_link_of(node, dev, dai_link, dai_props);
|
||||
ret = simple_card_dai_link_of(node, dev, dai_link, dai_props,
|
||||
true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -49,3 +49,12 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
|
||||
help
|
||||
This adds audio driver for Intel Baytrail platform based boards
|
||||
with the RT5640 audio codec.
|
||||
|
||||
config SND_SOC_INTEL_BYT_MAX98090_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
|
||||
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
|
||||
select SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_MAX98090
|
||||
help
|
||||
This adds audio driver for Intel Baytrail platform based boards
|
||||
with the MAX98090 audio codec.
|
||||
|
@ -23,6 +23,8 @@ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
|
||||
# Machine support
|
||||
snd-soc-sst-haswell-objs := haswell.o
|
||||
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
|
||||
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
|
||||
|
203
sound/soc/intel/byt-max98090.c
Normal file
203
sound/soc/intel/byt-max98090.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Intel Baytrail SST MAX98090 machine driver
|
||||
* Copyright (c) 2014, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
#include "../codecs/max98090.h"
|
||||
|
||||
struct byt_max98090_private {
|
||||
struct snd_soc_jack jack;
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget byt_max98090_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_max98090_audio_map[] = {
|
||||
{"IN34", NULL, "Headset Mic"},
|
||||
{"IN34", NULL, "MICBIAS"},
|
||||
{"MICBIAS", NULL, "Headset Mic"},
|
||||
{"DMICL", NULL, "Int Mic"},
|
||||
{"Headphone", NULL, "HPL"},
|
||||
{"Headphone", NULL, "HPR"},
|
||||
{"Ext Spk", NULL, "SPKL"},
|
||||
{"Ext Spk", NULL, "SPKR"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new byt_max98090_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Int Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Ext Spk"),
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_pin hs_jack_pins[] = {
|
||||
{
|
||||
.pin = "Headphone",
|
||||
.mask = SND_JACK_HEADPHONE,
|
||||
},
|
||||
{
|
||||
.pin = "Headset Mic",
|
||||
.mask = SND_JACK_MICROPHONE,
|
||||
},
|
||||
{
|
||||
.pin = "Ext Spk",
|
||||
.mask = SND_JACK_LINEOUT,
|
||||
},
|
||||
{
|
||||
.pin = "Int Mic",
|
||||
.mask = SND_JACK_LINEIN,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_gpio hs_jack_gpios[] = {
|
||||
{
|
||||
.name = "hp-gpio",
|
||||
.idx = 0,
|
||||
.report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
|
||||
.debounce_time = 200,
|
||||
},
|
||||
{
|
||||
.name = "mic-gpio",
|
||||
.idx = 1,
|
||||
.report = SND_JACK_MICROPHONE | SND_JACK_LINEIN,
|
||||
.debounce_time = 200,
|
||||
},
|
||||
};
|
||||
|
||||
static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_codec *codec = runtime->codec;
|
||||
struct snd_soc_card *card = runtime->card;
|
||||
struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_jack *jack = &drv->jack;
|
||||
|
||||
card->dapm.idle_bias_off = true;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(runtime->codec_dai,
|
||||
M98090_REG_SYSTEM_CLOCK,
|
||||
25000000, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "Can't set codec clock %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable jack detection */
|
||||
ret = snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, jack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(jack, ARRAY_SIZE(hs_jack_pins),
|
||||
hs_jack_pins);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_gpiods(card->dev->parent, jack,
|
||||
ARRAY_SIZE(hs_jack_gpios),
|
||||
hs_jack_gpios);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return max98090_mic_detect(codec, jack);
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_link byt_max98090_dais[] = {
|
||||
{
|
||||
.name = "Baytrail Audio",
|
||||
.stream_name = "Audio",
|
||||
.cpu_dai_name = "baytrail-pcm-audio",
|
||||
.codec_dai_name = "HiFi",
|
||||
.codec_name = "i2c-193C9890:00",
|
||||
.platform_name = "baytrail-pcm-audio",
|
||||
.init = byt_max98090_init,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card byt_max98090_card = {
|
||||
.name = "byt-max98090",
|
||||
.dai_link = byt_max98090_dais,
|
||||
.num_links = ARRAY_SIZE(byt_max98090_dais),
|
||||
.dapm_widgets = byt_max98090_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(byt_max98090_widgets),
|
||||
.dapm_routes = byt_max98090_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
|
||||
.controls = byt_max98090_controls,
|
||||
.num_controls = ARRAY_SIZE(byt_max98090_controls),
|
||||
};
|
||||
|
||||
static int byt_max98090_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct byt_max98090_private *priv;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
|
||||
if (!priv) {
|
||||
dev_err(&pdev->dev, "allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
byt_max98090_card.dev = &pdev->dev;
|
||||
snd_soc_card_set_drvdata(&byt_max98090_card, priv);
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_max98090_card);
|
||||
if (ret_val) {
|
||||
dev_err(&pdev->dev,
|
||||
"snd_soc_register_card failed %d\n", ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int byt_max98090_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct byt_max98090_private *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_jack_free_gpios(&priv->jack, ARRAY_SIZE(hs_jack_gpios),
|
||||
hs_jack_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver byt_max98090_driver = {
|
||||
.probe = byt_max98090_probe,
|
||||
.remove = byt_max98090_remove,
|
||||
.driver = {
|
||||
.name = "byt-max98090",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(byt_max98090_driver)
|
||||
|
||||
MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
|
||||
MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:byt-max98090");
|
@ -132,43 +132,20 @@ static struct snd_soc_card byt_rt5640_card = {
|
||||
.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static const struct dev_pm_ops byt_rt5640_pm_ops = {
|
||||
.suspend = snd_soc_suspend,
|
||||
.resume = snd_soc_resume,
|
||||
};
|
||||
|
||||
#define BYT_RT5640_PM_OPS (&byt_rt5640_pm_ops)
|
||||
#else
|
||||
#define BYT_RT5640_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static int byt_rt5640_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &byt_rt5640_card;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
dev_set_drvdata(dev, card);
|
||||
return snd_soc_register_card(card);
|
||||
}
|
||||
|
||||
static int byt_rt5640_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
return 0;
|
||||
return devm_snd_soc_register_card(&pdev->dev, card);
|
||||
}
|
||||
|
||||
static struct platform_driver byt_rt5640_audio = {
|
||||
.probe = byt_rt5640_probe,
|
||||
.remove = byt_rt5640_remove,
|
||||
.driver = {
|
||||
.name = "byt-rt5640",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = BYT_RT5640_PM_OPS,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(byt_rt5640_audio)
|
||||
|
@ -202,18 +202,11 @@ static int haswell_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
haswell_rt5640.dev = &pdev->dev;
|
||||
|
||||
return snd_soc_register_card(&haswell_rt5640);
|
||||
}
|
||||
|
||||
static int haswell_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_card(&haswell_rt5640);
|
||||
return 0;
|
||||
return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640);
|
||||
}
|
||||
|
||||
static struct platform_driver haswell_audio = {
|
||||
.probe = haswell_audio_probe,
|
||||
.remove = haswell_audio_remove,
|
||||
.driver = {
|
||||
.name = "haswell-audio",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -247,6 +247,7 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
|
||||
|
||||
static struct sst_acpi_mach baytrail_machines[] = {
|
||||
{ "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
|
||||
{ "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-i2s_master" },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/firmware.h>
|
||||
@ -892,7 +891,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
|
||||
/* start the IPC message thread */
|
||||
init_kthread_worker(&byt->kworker);
|
||||
byt->tx_thread = kthread_run(kthread_worker_fn,
|
||||
&byt->kworker,
|
||||
&byt->kworker, "%s",
|
||||
dev_name(byt->dev));
|
||||
if (IS_ERR(byt->tx_thread)) {
|
||||
err = PTR_ERR(byt->tx_thread);
|
||||
@ -907,7 +906,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
|
||||
byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
|
||||
if (byt->dsp == NULL) {
|
||||
err = -ENODEV;
|
||||
goto err_free_msg;
|
||||
goto dsp_err;
|
||||
}
|
||||
|
||||
/* keep the DSP in reset state for base FW loading */
|
||||
@ -940,6 +939,8 @@ boot_err:
|
||||
sst_fw_free(byt_sst_fw);
|
||||
fw_err:
|
||||
sst_dsp_free(byt->dsp);
|
||||
dsp_err:
|
||||
kthread_stop(byt->tx_thread);
|
||||
err_free_msg:
|
||||
kfree(byt->msg);
|
||||
|
||||
@ -954,6 +955,7 @@ void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
|
||||
sst_dsp_reset(byt->dsp);
|
||||
sst_fw_free_all(byt->dsp);
|
||||
sst_dsp_free(byt->dsp);
|
||||
kthread_stop(byt->tx_thread);
|
||||
kfree(byt->msg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_byt_dsp_free);
|
||||
|
@ -180,6 +180,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
pcm_data->hw_ptr = 0;
|
||||
sst_byt_stream_start(byt, pcm_data->stream, 0);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/firmware.h>
|
||||
@ -1730,17 +1729,17 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
|
||||
|
||||
ret = msg_empty_list_init(hsw);
|
||||
if (ret < 0)
|
||||
goto list_err;
|
||||
return -ENOMEM;
|
||||
|
||||
/* start the IPC message thread */
|
||||
init_kthread_worker(&hsw->kworker);
|
||||
hsw->tx_thread = kthread_run(kthread_worker_fn,
|
||||
&hsw->kworker,
|
||||
&hsw->kworker, "%s",
|
||||
dev_name(hsw->dev));
|
||||
if (IS_ERR(hsw->tx_thread)) {
|
||||
ret = PTR_ERR(hsw->tx_thread);
|
||||
dev_err(hsw->dev, "error: failed to create message TX task\n");
|
||||
goto list_err;
|
||||
goto err_free_msg;
|
||||
}
|
||||
init_kthread_work(&hsw->kwork, ipc_tx_msgs);
|
||||
|
||||
@ -1750,7 +1749,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
|
||||
hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata);
|
||||
if (hsw->dsp == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto list_err;
|
||||
goto dsp_err;
|
||||
}
|
||||
|
||||
/* keep the DSP in reset state for base FW loading */
|
||||
@ -1794,8 +1793,11 @@ boot_err:
|
||||
sst_fw_free(hsw_sst_fw);
|
||||
fw_err:
|
||||
sst_dsp_free(hsw->dsp);
|
||||
dsp_err:
|
||||
kthread_stop(hsw->tx_thread);
|
||||
err_free_msg:
|
||||
kfree(hsw->msg);
|
||||
list_err:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_hsw_dsp_init);
|
||||
@ -1808,6 +1810,7 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
|
||||
sst_fw_free_all(hsw->dsp);
|
||||
sst_dsp_free(hsw->dsp);
|
||||
kfree(hsw->scratch);
|
||||
kthread_stop(hsw->tx_thread);
|
||||
kfree(hsw->msg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_hsw_dsp_free);
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
@ -527,6 +527,15 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ams_delta_card_remove(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
snd_soc_jack_free_gpios(&ams_delta_hook_switch,
|
||||
ARRAY_SIZE(ams_delta_hook_switch_gpios),
|
||||
ams_delta_hook_switch_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DAI glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link ams_delta_dai_link = {
|
||||
.name = "CX20442",
|
||||
@ -543,6 +552,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
|
||||
static struct snd_soc_card ams_delta_audio_card = {
|
||||
.name = "AMS_DELTA",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = ams_delta_card_remove,
|
||||
.dai_link = &ams_delta_dai_link,
|
||||
.num_links = 1,
|
||||
|
||||
@ -579,10 +589,6 @@ static int ams_delta_remove(struct platform_device *pdev)
|
||||
dev_warn(&pdev->dev,
|
||||
"failed to unregister V253 line discipline\n");
|
||||
|
||||
snd_soc_jack_free_gpios(&ams_delta_hook_switch,
|
||||
ARRAY_SIZE(ams_delta_hook_switch_gpios),
|
||||
ams_delta_hook_switch_gpios);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
card->dev = NULL;
|
||||
return 0;
|
||||
|
@ -40,9 +40,9 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/omap-pcm.h>
|
||||
|
||||
#include "omap-dmic.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
struct omap_dmic {
|
||||
struct device *dev;
|
||||
|
@ -34,9 +34,9 @@
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <sound/omap-pcm.h>
|
||||
|
||||
#include "omap-hdmi.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
#define DRV_NAME "omap-hdmi-audio-dai"
|
||||
|
||||
|
@ -34,11 +34,11 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/omap-pcm.h>
|
||||
|
||||
#include <linux/platform_data/asoc-ti-mcbsp.h>
|
||||
#include "mcbsp.h"
|
||||
#include "omap-mcbsp.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
|
||||
|
||||
|
@ -40,9 +40,9 @@
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/omap-pcm.h>
|
||||
|
||||
#include "omap-mcpdm.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
struct mcpdm_link_config {
|
||||
u32 link_mask; /* channel mask for the direction */
|
||||
|
@ -231,6 +231,19 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int omap_twl4030_card_remove(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (priv->jack_detect > 0)
|
||||
snd_soc_jack_free_gpios(&priv->hs_jack,
|
||||
ARRAY_SIZE(hs_jack_gpios),
|
||||
hs_jack_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Digital audio interface glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
|
||||
{
|
||||
@ -258,6 +271,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
|
||||
/* Audio machine driver */
|
||||
static struct snd_soc_card omap_twl4030_card = {
|
||||
.owner = THIS_MODULE,
|
||||
.remove = omap_twl4030_card_remove,
|
||||
.dai_link = omap_twl4030_dai_links,
|
||||
.num_links = ARRAY_SIZE(omap_twl4030_dai_links),
|
||||
|
||||
@ -353,19 +367,6 @@ static int omap_twl4030_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_twl4030_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (priv->jack_detect > 0)
|
||||
snd_soc_jack_free_gpios(&priv->hs_jack,
|
||||
ARRAY_SIZE(hs_jack_gpios),
|
||||
hs_jack_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id omap_twl4030_of_match[] = {
|
||||
{.compatible = "ti,omap-twl4030", },
|
||||
{ },
|
||||
@ -380,7 +381,6 @@ static struct platform_driver omap_twl4030_driver = {
|
||||
.of_match_table = omap_twl4030_of_match,
|
||||
},
|
||||
.probe = omap_twl4030_probe,
|
||||
.remove = omap_twl4030_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(omap_twl4030_driver);
|
||||
|
@ -334,6 +334,14 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rx51_card_remove(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
|
||||
rx51_av_jack_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Digital audio interface glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link rx51_dai[] = {
|
||||
{
|
||||
@ -368,6 +376,7 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = {
|
||||
static struct snd_soc_card rx51_sound_card = {
|
||||
.name = "RX-51",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = rx51_card_remove,
|
||||
.dai_link = rx51_dai,
|
||||
.num_links = ARRAY_SIZE(rx51_dai),
|
||||
.aux_dev = rx51_aux_dev,
|
||||
@ -499,14 +508,6 @@ static int rx51_soc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx51_soc_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
|
||||
rx51_av_jack_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id rx51_audio_of_match[] = {
|
||||
{ .compatible = "nokia,n900-audio", },
|
||||
@ -522,7 +523,6 @@ static struct platform_driver rx51_soc_driver = {
|
||||
.of_match_table = of_match_ptr(rx51_audio_of_match),
|
||||
},
|
||||
.probe = rx51_soc_probe,
|
||||
.remove = rx51_soc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(rx51_soc_driver);
|
||||
|
@ -152,6 +152,13 @@ static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hx4700_card_remove(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* hx4700 digital audio interface glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link hx4700_dai = {
|
||||
.name = "ak4641",
|
||||
@ -170,6 +177,7 @@ static struct snd_soc_dai_link hx4700_dai = {
|
||||
static struct snd_soc_card snd_soc_card_hx4700 = {
|
||||
.name = "iPAQ hx4700",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = hx4700_card_remove,
|
||||
.dai_link = &hx4700_dai,
|
||||
.num_links = 1,
|
||||
.dapm_widgets = hx4700_dapm_widgets,
|
||||
@ -206,7 +214,6 @@ static int hx4700_audio_probe(struct platform_device *pdev)
|
||||
|
||||
static int hx4700_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
|
||||
snd_soc_unregister_card(&snd_soc_card_hx4700);
|
||||
|
||||
gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
|
||||
|
@ -808,6 +808,7 @@ static const struct snd_soc_component_driver pxa_ssp_component = {
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pxa_ssp_of_ids[] = {
|
||||
{ .compatible = "mrvl,pxa-ssp-dai" },
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -189,6 +189,14 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int h1940_uda1380_card_remove(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
|
||||
hp_jack_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* s3c24xx digital audio interface glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link h1940_uda1380_dai[] = {
|
||||
{
|
||||
@ -206,6 +214,7 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = {
|
||||
static struct snd_soc_card h1940_asoc = {
|
||||
.name = "h1940",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = h1940_uda1380_card_remove,
|
||||
.dai_link = h1940_uda1380_dai,
|
||||
.num_links = ARRAY_SIZE(h1940_uda1380_dai),
|
||||
|
||||
@ -257,8 +266,6 @@ err_out:
|
||||
static void __exit h1940_exit(void)
|
||||
{
|
||||
platform_device_unregister(s3c24xx_snd_device);
|
||||
snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
|
||||
hp_jack_gpios);
|
||||
gpio_free(S3C_GPIO_END + 9);
|
||||
}
|
||||
|
||||
|
@ -488,7 +488,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
|
||||
clk_id = 1;
|
||||
|
||||
if (!any_active(i2s)) {
|
||||
if (i2s->op_clk) {
|
||||
if (i2s->op_clk && !IS_ERR(i2s->op_clk)) {
|
||||
if ((clk_id && !(mod & MOD_IMS_SYSMUX)) ||
|
||||
(!clk_id && (mod & MOD_IMS_SYSMUX))) {
|
||||
clk_disable_unprepare(i2s->op_clk);
|
||||
@ -506,6 +506,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
|
||||
else
|
||||
i2s->op_clk = clk_get(&i2s->pdev->dev,
|
||||
"i2s_opclk0");
|
||||
|
||||
if (WARN_ON(IS_ERR(i2s->op_clk)))
|
||||
return PTR_ERR(i2s->op_clk);
|
||||
|
||||
clk_prepare_enable(i2s->op_clk);
|
||||
i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
|
||||
|
||||
@ -672,8 +676,8 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
if (is_manager(i2s))
|
||||
mod &= ~MOD_BLC_MASK;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
switch (params_width(params)) {
|
||||
case 8:
|
||||
if (is_secondary(i2s))
|
||||
mod |= MOD_BLCS_8BIT;
|
||||
else
|
||||
@ -681,7 +685,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
if (is_manager(i2s))
|
||||
mod |= MOD_BLC_8BIT;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
case 16:
|
||||
if (is_secondary(i2s))
|
||||
mod |= MOD_BLCS_16BIT;
|
||||
else
|
||||
@ -689,7 +693,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
if (is_manager(i2s))
|
||||
mod |= MOD_BLC_16BIT;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
case 24:
|
||||
if (is_secondary(i2s))
|
||||
mod |= MOD_BLCS_24BIT;
|
||||
else
|
||||
|
@ -283,8 +283,8 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
dev_dbg(pcm->dev, "Entered %s\n", __func__);
|
||||
|
||||
/* Strictly check for sample size */
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "s3c24xx-i2s.h"
|
||||
|
||||
static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
|
||||
static int rx1950_uda1380_card_remove(struct snd_soc_pcm_runtime *rtd);
|
||||
static int rx1950_startup(struct snd_pcm_substream *substream);
|
||||
static int rx1950_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
@ -116,6 +117,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
||||
static struct snd_soc_card rx1950_asoc = {
|
||||
.name = "rx1950",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = rx1950_uda1380_card_remove,
|
||||
.dai_link = rx1950_uda1380_dai,
|
||||
.num_links = ARRAY_SIZE(rx1950_uda1380_dai),
|
||||
|
||||
@ -234,6 +236,14 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx1950_uda1380_card_remove(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
|
||||
hp_jack_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init rx1950_init(void)
|
||||
{
|
||||
int ret;
|
||||
@ -278,8 +288,6 @@ err_gpio:
|
||||
static void __exit rx1950_exit(void)
|
||||
{
|
||||
platform_device_unregister(s3c24xx_snd_device);
|
||||
snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
|
||||
hp_jack_gpios);
|
||||
gpio_free(S3C2410_GPA(1));
|
||||
}
|
||||
|
||||
|
@ -322,13 +322,13 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
iismod &= ~S3C64XX_IISMOD_BLC_MASK;
|
||||
/* Sample size */
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
switch (params_width(params)) {
|
||||
case 8:
|
||||
iismod |= S3C64XX_IISMOD_BLC_8BIT;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
case 16:
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
case 24:
|
||||
iismod |= S3C64XX_IISMOD_BLC_24BIT;
|
||||
break;
|
||||
}
|
||||
|
@ -120,11 +120,11 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
iismod = readl(i2s->regs + S3C2412_IISMOD);
|
||||
pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
switch (params_width(params)) {
|
||||
case 8:
|
||||
iismod |= S3C2412_IISMOD_8BIT;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
case 16:
|
||||
iismod &= ~S3C2412_IISMOD_8BIT;
|
||||
break;
|
||||
}
|
||||
|
@ -248,12 +248,12 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
|
||||
pr_debug("hw_params r: IISMOD: %x\n", iismod);
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
switch (params_width(params)) {
|
||||
case 8:
|
||||
iismod &= ~S3C2410_IISMOD_16BIT;
|
||||
dma_data->dma_size = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
case 16:
|
||||
iismod |= S3C2410_IISMOD_16BIT;
|
||||
dma_data->dma_size = 2;
|
||||
break;
|
||||
|
@ -182,6 +182,14 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int smartq_wm8987_card_remove(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
|
||||
smartq_jack_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_link smartq_dai[] = {
|
||||
{
|
||||
.name = "wm8987",
|
||||
@ -198,6 +206,7 @@ static struct snd_soc_dai_link smartq_dai[] = {
|
||||
static struct snd_soc_card snd_soc_smartq = {
|
||||
.name = "SmartQ",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = smartq_wm8987_card_remove,
|
||||
.dai_link = smartq_dai,
|
||||
.num_links = ARRAY_SIZE(smartq_dai),
|
||||
|
||||
@ -259,8 +268,6 @@ err_unregister_device:
|
||||
static void __exit smartq_exit(void)
|
||||
{
|
||||
gpio_free(S3C64XX_GPK(12));
|
||||
snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
|
||||
smartq_jack_gpios);
|
||||
|
||||
platform_device_unregister(smartq_snd_device);
|
||||
}
|
||||
|
@ -37,13 +37,11 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
|
||||
unsigned int pll_out;
|
||||
int bfs, rfs, ret;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_U8:
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
switch (params_width(params)) {
|
||||
case 8:
|
||||
bfs = 16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_U16_LE:
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
case 16:
|
||||
bfs = 32;
|
||||
break;
|
||||
default:
|
||||
|
@ -57,7 +57,7 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
|
||||
int ret;
|
||||
|
||||
/* AIF1CLK should be >=3MHz for optimal performance */
|
||||
if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE)
|
||||
if (params_width(params) == 24)
|
||||
pll_out = params_rate(params) * 384;
|
||||
else if (params_rate(params) == 8000 || params_rate(params) == 11025)
|
||||
pll_out = params_rate(params) * 512;
|
||||
|
@ -211,8 +211,8 @@ static int spdif_hw_params(struct snd_pcm_substream *substream,
|
||||
con |= CON_PCM_DATA;
|
||||
|
||||
con &= ~CON_PCM_MASK;
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
switch (params_width(params)) {
|
||||
case 16:
|
||||
con |= CON_PCM_16BIT;
|
||||
break;
|
||||
default:
|
||||
|
@ -255,11 +255,81 @@ int rsnd_dma_available(struct rsnd_dma *dma)
|
||||
return !!dma->chan;
|
||||
}
|
||||
|
||||
#define DMA_NAME_SIZE 16
|
||||
#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
|
||||
static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
|
||||
{
|
||||
if (mod)
|
||||
return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod));
|
||||
else
|
||||
return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
|
||||
|
||||
}
|
||||
|
||||
static void rsnd_dma_of_name(struct rsnd_dma *dma,
|
||||
int is_play, char *dma_name)
|
||||
{
|
||||
struct rsnd_mod *this = rsnd_dma_to_mod(dma);
|
||||
struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
|
||||
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
|
||||
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
|
||||
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
|
||||
struct rsnd_mod *mod[MOD_MAX];
|
||||
struct rsnd_mod *src_mod, *dst_mod;
|
||||
int i, index;
|
||||
|
||||
|
||||
for (i = 0; i < MOD_MAX; i++)
|
||||
mod[i] = NULL;
|
||||
|
||||
/*
|
||||
* in play case...
|
||||
*
|
||||
* src -> dst
|
||||
*
|
||||
* mem -> SSI
|
||||
* mem -> SRC -> SSI
|
||||
* mem -> SRC -> DVC -> SSI
|
||||
*/
|
||||
mod[0] = NULL; /* for "mem" */
|
||||
index = 1;
|
||||
for (i = 1; i < MOD_MAX; i++) {
|
||||
if (!src) {
|
||||
mod[i] = ssi;
|
||||
break;
|
||||
} else if (!dvc) {
|
||||
mod[i] = src;
|
||||
src = NULL;
|
||||
} else {
|
||||
mod[i] = dvc;
|
||||
dvc = NULL;
|
||||
}
|
||||
|
||||
if (mod[i] == this)
|
||||
index = i;
|
||||
}
|
||||
|
||||
if (is_play) {
|
||||
src_mod = mod[index - 1];
|
||||
dst_mod = mod[index];
|
||||
} else {
|
||||
src_mod = mod[index];
|
||||
dst_mod = mod[index + 1];
|
||||
}
|
||||
|
||||
index = 0;
|
||||
index = _rsnd_dma_of_name(dma_name + index, src_mod);
|
||||
*(dma_name + index++) = '_';
|
||||
index = _rsnd_dma_of_name(dma_name + index, dst_mod);
|
||||
}
|
||||
|
||||
int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
|
||||
int is_play, int id)
|
||||
{
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct dma_slave_config cfg;
|
||||
char dma_name[DMA_NAME_SIZE];
|
||||
dma_cap_mask_t mask;
|
||||
int ret;
|
||||
|
||||
@ -271,18 +341,23 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
if (dev->of_node)
|
||||
rsnd_dma_of_name(dma, is_play, dma_name);
|
||||
else
|
||||
snprintf(dma_name, DMA_NAME_SIZE,
|
||||
is_play ? "tx" : "rx");
|
||||
|
||||
dev_dbg(dev, "dma name : %s\n", dma_name);
|
||||
|
||||
dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
|
||||
(void *)id, dev,
|
||||
is_play ? "tx" : "rx");
|
||||
dma_name);
|
||||
if (!dma->chan) {
|
||||
dev_err(dev, "can't get dma channel\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
cfg.slave_id = id;
|
||||
cfg.dst_addr = 0; /* use default addr when playback */
|
||||
cfg.src_addr = 0; /* use default addr when capture */
|
||||
cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
|
||||
rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id);
|
||||
|
||||
ret = dmaengine_slave_config(dma->chan, &cfg);
|
||||
if (ret < 0)
|
||||
@ -956,7 +1031,7 @@ static int rsnd_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->dev = dev;
|
||||
priv->pdev = pdev;
|
||||
priv->info = info;
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
|
@ -13,6 +13,9 @@
|
||||
#define RSND_DVC_NAME_SIZE 16
|
||||
#define RSND_DVC_VOLUME_MAX 100
|
||||
#define RSND_DVC_VOLUME_NUM 2
|
||||
|
||||
#define DVC_NAME "dvc"
|
||||
|
||||
struct rsnd_dvc {
|
||||
struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
|
||||
struct rsnd_mod mod;
|
||||
@ -43,6 +46,17 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
|
||||
rsnd_mod_write(mod, DVC_VOL1R, vol[1]);
|
||||
}
|
||||
|
||||
static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
|
||||
struct rsnd_dai *rdai)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
|
||||
dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
|
||||
struct rsnd_dai *rdai)
|
||||
{
|
||||
@ -208,7 +222,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_dvc_ops = {
|
||||
.name = "dvc (gen2)",
|
||||
.name = DVC_NAME,
|
||||
.probe = rsnd_dvc_probe_gen2,
|
||||
.init = rsnd_dvc_init,
|
||||
.quit = rsnd_dvc_quit,
|
||||
.start = rsnd_dvc_start,
|
||||
@ -255,7 +270,8 @@ int rsnd_dvc_probe(struct platform_device *pdev,
|
||||
priv->dvc = dvc;
|
||||
|
||||
for_each_rsnd_dvc(dvc, priv, i) {
|
||||
snprintf(name, RSND_DVC_NAME_SIZE, "dvc.%d", i);
|
||||
snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
|
||||
DVC_NAME, i);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -155,6 +155,101 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DMA read/write register offset
|
||||
*
|
||||
* RSND_xxx_I_N for Audio DMAC input
|
||||
* RSND_xxx_O_N for Audio DMAC output
|
||||
* RSND_xxx_I_P for Audio DMAC peri peri input
|
||||
* RSND_xxx_O_P for Audio DMAC peri peri output
|
||||
*
|
||||
* ex) R-Car H2 case
|
||||
* mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out
|
||||
* SSI : 0xec541000 / 0xec241008 / 0xec24100c / 0xec400000 / 0xec400000
|
||||
* SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
|
||||
* CMD : 0xec500000 / 0xec008000 0xec308000
|
||||
*/
|
||||
#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
|
||||
#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
|
||||
|
||||
#define RDMA_SSI_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
|
||||
#define RDMA_SSI_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
|
||||
|
||||
#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i))
|
||||
#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i))
|
||||
|
||||
#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i))
|
||||
#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i))
|
||||
|
||||
#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i))
|
||||
#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i))
|
||||
|
||||
void rsnd_gen_dma_addr(struct rsnd_priv *priv,
|
||||
struct rsnd_dma *dma,
|
||||
struct dma_slave_config *cfg,
|
||||
int is_play, int slave_id)
|
||||
{
|
||||
struct platform_device *pdev = rsnd_priv_to_pdev(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
|
||||
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
|
||||
dma_addr_t ssi_reg = platform_get_resource(pdev,
|
||||
IORESOURCE_MEM, RSND_GEN2_SSI)->start;
|
||||
dma_addr_t src_reg = platform_get_resource(pdev,
|
||||
IORESOURCE_MEM, RSND_GEN2_SCU)->start;
|
||||
int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
|
||||
int use_src = !!rsnd_io_to_mod_src(io);
|
||||
int use_dvc = !!rsnd_io_to_mod_dvc(io);
|
||||
int id = rsnd_mod_id(mod);
|
||||
struct dma_addr {
|
||||
dma_addr_t src_addr;
|
||||
dma_addr_t dst_addr;
|
||||
} dma_addrs[2][2][3] = {
|
||||
{ /* SRC */
|
||||
/* Capture */
|
||||
{{ 0, 0 },
|
||||
{ RDMA_SRC_O_N(src, id), 0 },
|
||||
{ RDMA_CMD_O_N(src, id), 0 }},
|
||||
/* Playback */
|
||||
{{ 0, 0, },
|
||||
{ 0, RDMA_SRC_I_N(src, id) },
|
||||
{ 0, RDMA_SRC_I_N(src, id) }}
|
||||
}, { /* SSI */
|
||||
/* Capture */
|
||||
{{ RDMA_SSI_O_N(ssi, id), 0 },
|
||||
{ RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) },
|
||||
{ RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }},
|
||||
/* Playback */
|
||||
{{ 0, RDMA_SSI_I_N(ssi, id) },
|
||||
{ RDMA_SRC_O_P(src, id), RDMA_SSI_I_P(ssi, id) },
|
||||
{ RDMA_CMD_O_P(src, id), RDMA_SSI_I_P(ssi, id) }}
|
||||
}
|
||||
};
|
||||
|
||||
cfg->slave_id = slave_id;
|
||||
cfg->src_addr = 0;
|
||||
cfg->dst_addr = 0;
|
||||
cfg->direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
|
||||
|
||||
/*
|
||||
* gen1 uses default DMA addr
|
||||
*/
|
||||
if (rsnd_is_gen1(priv))
|
||||
return;
|
||||
|
||||
/* it shouldn't happen */
|
||||
if (use_dvc & !use_src) {
|
||||
dev_err(dev, "DVC is selected without SRC\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr;
|
||||
cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr;
|
||||
|
||||
dev_dbg(dev, "dma%d addr - src : %x / dst : %x\n",
|
||||
id, cfg->src_addr, cfg->dst_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gen2
|
||||
*/
|
||||
|
@ -281,6 +281,11 @@ int rsnd_gen_probe(struct platform_device *pdev,
|
||||
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
|
||||
struct rsnd_mod *mod,
|
||||
enum rsnd_reg reg);
|
||||
void rsnd_gen_dma_addr(struct rsnd_priv *priv,
|
||||
struct rsnd_dma *dma,
|
||||
struct dma_slave_config *cfg,
|
||||
int is_play, int slave_id);
|
||||
|
||||
#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
|
||||
#define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
|
||||
|
||||
@ -317,7 +322,7 @@ struct rsnd_of_data {
|
||||
|
||||
struct rsnd_priv {
|
||||
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
struct rcar_snd_info *info;
|
||||
spinlock_t lock;
|
||||
|
||||
@ -357,7 +362,8 @@ struct rsnd_priv {
|
||||
int rdai_nr;
|
||||
};
|
||||
|
||||
#define rsnd_priv_to_dev(priv) ((priv)->dev)
|
||||
#define rsnd_priv_to_pdev(priv) ((priv)->pdev)
|
||||
#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
|
||||
#define rsnd_priv_to_info(priv) ((priv)->info)
|
||||
#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
|
||||
#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
|
||||
|
@ -10,6 +10,8 @@
|
||||
*/
|
||||
#include "rsnd.h"
|
||||
|
||||
#define SRC_NAME "src"
|
||||
|
||||
struct rsnd_src {
|
||||
struct rsnd_src_platform_info *info; /* rcar_snd.h */
|
||||
struct rsnd_mod mod;
|
||||
@ -268,10 +270,6 @@ static int rsnd_src_stop(struct rsnd_mod *mod,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_src_non_ops = {
|
||||
.name = "src (non)",
|
||||
};
|
||||
|
||||
/*
|
||||
* Gen1 functions
|
||||
*/
|
||||
@ -393,6 +391,17 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
|
||||
struct rsnd_dai *rdai)
|
||||
{
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
|
||||
dev_dbg(dev, "%s (Gen1) is probed\n", rsnd_mod_name(mod));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_src_init_gen1(struct rsnd_mod *mod,
|
||||
struct rsnd_dai *rdai)
|
||||
{
|
||||
@ -438,7 +447,8 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_src_gen1_ops = {
|
||||
.name = "sru (gen1)",
|
||||
.name = SRC_NAME,
|
||||
.probe = rsnd_src_probe_gen1,
|
||||
.init = rsnd_src_init_gen1,
|
||||
.quit = rsnd_src_quit,
|
||||
.start = rsnd_src_start_gen1,
|
||||
@ -502,6 +512,8 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
|
||||
if (ret < 0)
|
||||
dev_err(dev, "SRC DMA failed\n");
|
||||
|
||||
dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -562,7 +574,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_src_gen2_ops = {
|
||||
.name = "src (gen2)",
|
||||
.name = SRC_NAME,
|
||||
.probe = rsnd_src_probe_gen2,
|
||||
.remove = rsnd_src_remove_gen2,
|
||||
.init = rsnd_src_init_gen2,
|
||||
@ -598,18 +610,21 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
|
||||
|
||||
nr = of_get_child_count(src_node);
|
||||
if (!nr)
|
||||
return;
|
||||
goto rsnd_of_parse_src_end;
|
||||
|
||||
src_info = devm_kzalloc(dev,
|
||||
sizeof(struct rsnd_src_platform_info) * nr,
|
||||
GFP_KERNEL);
|
||||
if (!src_info) {
|
||||
dev_err(dev, "src info allocation error\n");
|
||||
return;
|
||||
goto rsnd_of_parse_src_end;
|
||||
}
|
||||
|
||||
info->src_info = src_info;
|
||||
info->src_info_nr = nr;
|
||||
|
||||
rsnd_of_parse_src_end:
|
||||
of_node_put(src_node);
|
||||
}
|
||||
|
||||
int rsnd_src_probe(struct platform_device *pdev,
|
||||
@ -624,6 +639,16 @@ int rsnd_src_probe(struct platform_device *pdev,
|
||||
char name[RSND_SRC_NAME_SIZE];
|
||||
int i, nr;
|
||||
|
||||
ops = NULL;
|
||||
if (rsnd_is_gen1(priv))
|
||||
ops = &rsnd_src_gen1_ops;
|
||||
if (rsnd_is_gen2(priv))
|
||||
ops = &rsnd_src_gen2_ops;
|
||||
if (!ops) {
|
||||
dev_err(dev, "unknown Generation\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rsnd_of_parse_src(pdev, of_data, priv);
|
||||
|
||||
/*
|
||||
@ -643,7 +668,8 @@ int rsnd_src_probe(struct platform_device *pdev,
|
||||
priv->src = src;
|
||||
|
||||
for_each_rsnd_src(src, priv, i) {
|
||||
snprintf(name, RSND_SRC_NAME_SIZE, "src.%d", i);
|
||||
snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
|
||||
SRC_NAME, i);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
if (IS_ERR(clk))
|
||||
@ -652,12 +678,6 @@ int rsnd_src_probe(struct platform_device *pdev,
|
||||
src->info = &info->src_info[i];
|
||||
src->clk = clk;
|
||||
|
||||
ops = &rsnd_src_non_ops;
|
||||
if (rsnd_is_gen1(priv))
|
||||
ops = &rsnd_src_gen1_ops;
|
||||
if (rsnd_is_gen2(priv))
|
||||
ops = &rsnd_src_gen2_ops;
|
||||
|
||||
rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i);
|
||||
|
||||
dev_dbg(dev, "SRC%d probed\n", i);
|
||||
|
@ -57,6 +57,8 @@
|
||||
*/
|
||||
#define CONT (1 << 8) /* WS Continue Function */
|
||||
|
||||
#define SSI_NAME "ssi"
|
||||
|
||||
struct rsnd_ssi {
|
||||
struct clk *clk;
|
||||
struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
|
||||
@ -373,6 +375,8 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
|
||||
if (ret)
|
||||
dev_err(dev, "SSI request interrupt failed\n");
|
||||
|
||||
dev_dbg(dev, "%s (PIO) is probed\n", rsnd_mod_name(mod));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -405,7 +409,7 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
|
||||
.name = "ssi (pio)",
|
||||
.name = SSI_NAME,
|
||||
.probe = rsnd_ssi_pio_probe,
|
||||
.init = rsnd_ssi_init,
|
||||
.quit = rsnd_ssi_quit,
|
||||
@ -430,6 +434,8 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
|
||||
if (ret < 0)
|
||||
dev_err(dev, "SSI DMA failed\n");
|
||||
|
||||
dev_dbg(dev, "%s (DMA) is probed\n", rsnd_mod_name(mod));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -480,7 +486,7 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
|
||||
}
|
||||
|
||||
static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
|
||||
.name = "ssi (dma)",
|
||||
.name = SSI_NAME,
|
||||
.probe = rsnd_ssi_dma_probe,
|
||||
.remove = rsnd_ssi_dma_remove,
|
||||
.init = rsnd_ssi_init,
|
||||
@ -493,7 +499,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
|
||||
* Non SSI
|
||||
*/
|
||||
static struct rsnd_mod_ops rsnd_ssi_non_ops = {
|
||||
.name = "ssi (non)",
|
||||
.name = SSI_NAME,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -554,14 +560,14 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
|
||||
|
||||
nr = of_get_child_count(node);
|
||||
if (!nr)
|
||||
return;
|
||||
goto rsnd_of_parse_ssi_end;
|
||||
|
||||
ssi_info = devm_kzalloc(dev,
|
||||
sizeof(struct rsnd_ssi_platform_info) * nr,
|
||||
GFP_KERNEL);
|
||||
if (!ssi_info) {
|
||||
dev_err(dev, "ssi info allocation error\n");
|
||||
return;
|
||||
goto rsnd_of_parse_ssi_end;
|
||||
}
|
||||
|
||||
info->ssi_info = ssi_info;
|
||||
@ -583,7 +589,16 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
|
||||
* irq
|
||||
*/
|
||||
ssi_info->pio_irq = irq_of_parse_and_map(np, 0);
|
||||
|
||||
/*
|
||||
* DMA
|
||||
*/
|
||||
ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ?
|
||||
0 : 1;
|
||||
}
|
||||
|
||||
rsnd_of_parse_ssi_end:
|
||||
of_node_put(node);
|
||||
}
|
||||
|
||||
int rsnd_ssi_probe(struct platform_device *pdev,
|
||||
@ -617,7 +632,8 @@ int rsnd_ssi_probe(struct platform_device *pdev,
|
||||
for_each_rsnd_ssi(ssi, priv, i) {
|
||||
pinfo = &info->ssi_info[i];
|
||||
|
||||
snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i);
|
||||
snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
|
||||
SSI_NAME, i);
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -72,6 +72,9 @@ int snd_soc_cache_init(struct snd_soc_codec *codec)
|
||||
|
||||
reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
|
||||
|
||||
if (!reg_size)
|
||||
return 0;
|
||||
|
||||
mutex_init(&codec->cache_rw_mutex);
|
||||
|
||||
dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n",
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <sound/jack.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/delay.h>
|
||||
@ -240,7 +241,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
|
||||
int enable;
|
||||
int report;
|
||||
|
||||
enable = gpio_get_value_cansleep(gpio->gpio);
|
||||
enable = gpiod_get_value_cansleep(gpio->desc);
|
||||
if (gpio->invert)
|
||||
enable = !enable;
|
||||
|
||||
@ -297,31 +298,50 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!gpio_is_valid(gpios[i].gpio)) {
|
||||
dev_err(jack->codec->dev, "ASoC: Invalid gpio %d\n",
|
||||
gpios[i].gpio);
|
||||
ret = -EINVAL;
|
||||
goto undo;
|
||||
}
|
||||
if (!gpios[i].name) {
|
||||
dev_err(jack->codec->dev, "ASoC: No name for gpio %d\n",
|
||||
gpios[i].gpio);
|
||||
dev_err(jack->codec->dev,
|
||||
"ASoC: No name for gpio at index %d\n", i);
|
||||
ret = -EINVAL;
|
||||
goto undo;
|
||||
}
|
||||
|
||||
ret = gpio_request(gpios[i].gpio, gpios[i].name);
|
||||
if (ret)
|
||||
goto undo;
|
||||
if (gpios[i].gpiod_dev) {
|
||||
/* GPIO descriptor */
|
||||
gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev,
|
||||
gpios[i].name,
|
||||
gpios[i].idx);
|
||||
if (IS_ERR(gpios[i].desc)) {
|
||||
ret = PTR_ERR(gpios[i].desc);
|
||||
dev_err(gpios[i].gpiod_dev,
|
||||
"ASoC: Cannot get gpio at index %d: %d",
|
||||
i, ret);
|
||||
goto undo;
|
||||
}
|
||||
} else {
|
||||
/* legacy GPIO number */
|
||||
if (!gpio_is_valid(gpios[i].gpio)) {
|
||||
dev_err(jack->codec->dev,
|
||||
"ASoC: Invalid gpio %d\n",
|
||||
gpios[i].gpio);
|
||||
ret = -EINVAL;
|
||||
goto undo;
|
||||
}
|
||||
|
||||
ret = gpio_direction_input(gpios[i].gpio);
|
||||
ret = gpio_request(gpios[i].gpio, gpios[i].name);
|
||||
if (ret)
|
||||
goto undo;
|
||||
|
||||
gpios[i].desc = gpio_to_desc(gpios[i].gpio);
|
||||
}
|
||||
|
||||
ret = gpiod_direction_input(gpios[i].desc);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
|
||||
gpios[i].jack = jack;
|
||||
|
||||
ret = request_any_context_irq(gpio_to_irq(gpios[i].gpio),
|
||||
ret = request_any_context_irq(gpiod_to_irq(gpios[i].desc),
|
||||
gpio_handler,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
@ -331,15 +351,15 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
|
||||
goto err;
|
||||
|
||||
if (gpios[i].wake) {
|
||||
ret = irq_set_irq_wake(gpio_to_irq(gpios[i].gpio), 1);
|
||||
ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1);
|
||||
if (ret != 0)
|
||||
dev_err(jack->codec->dev, "ASoC: "
|
||||
"Failed to mark GPIO %d as wake source: %d\n",
|
||||
gpios[i].gpio, ret);
|
||||
dev_err(jack->codec->dev,
|
||||
"ASoC: Failed to mark GPIO at index %d as wake source: %d\n",
|
||||
i, ret);
|
||||
}
|
||||
|
||||
/* Expose GPIO value over sysfs for diagnostic purposes */
|
||||
gpio_export(gpios[i].gpio, false);
|
||||
gpiod_export(gpios[i].desc, false);
|
||||
|
||||
/* Update initial jack status */
|
||||
schedule_delayed_work(&gpios[i].work,
|
||||
@ -357,6 +377,30 @@ undo:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios);
|
||||
|
||||
/**
|
||||
* snd_soc_jack_add_gpiods - Associate GPIO descriptor pins with an ASoC jack
|
||||
*
|
||||
* @gpiod_dev: GPIO consumer device
|
||||
* @jack: ASoC jack
|
||||
* @count: number of pins
|
||||
* @gpios: array of gpio pins
|
||||
*
|
||||
* This function will request gpio, set data direction and request irq
|
||||
* for each gpio in the array.
|
||||
*/
|
||||
int snd_soc_jack_add_gpiods(struct device *gpiod_dev,
|
||||
struct snd_soc_jack *jack,
|
||||
int count, struct snd_soc_jack_gpio *gpios)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
gpios[i].gpiod_dev = gpiod_dev;
|
||||
|
||||
return snd_soc_jack_add_gpios(jack, count, gpios);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpiods);
|
||||
|
||||
/**
|
||||
* snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack
|
||||
*
|
||||
@ -372,10 +416,10 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
gpio_unexport(gpios[i].gpio);
|
||||
free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
|
||||
gpiod_unexport(gpios[i].desc);
|
||||
free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]);
|
||||
cancel_delayed_work_sync(&gpios[i].work);
|
||||
gpio_free(gpios[i].gpio);
|
||||
gpiod_put(gpios[i].desc);
|
||||
gpios[i].jack = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -125,6 +125,18 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_alc5632_card_remove(struct snd_soc_card *card)
|
||||
{
|
||||
struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1,
|
||||
&tegra_alc5632_hp_jack_gpio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_link tegra_alc5632_dai = {
|
||||
.name = "ALC5632",
|
||||
.stream_name = "ALC5632 PCM",
|
||||
@ -139,6 +151,7 @@ static struct snd_soc_dai_link tegra_alc5632_dai = {
|
||||
static struct snd_soc_card snd_soc_tegra_alc5632 = {
|
||||
.name = "tegra-alc5632",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = tegra_alc5632_card_remove,
|
||||
.dai_link = &tegra_alc5632_dai,
|
||||
.num_links = 1,
|
||||
.controls = tegra_alc5632_controls,
|
||||
@ -223,9 +236,6 @@ static int tegra_alc5632_remove(struct platform_device *pdev)
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1,
|
||||
&tegra_alc5632_hp_jack_gpio);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
tegra_asoc_utils_fini(&machine->util_data);
|
||||
|
@ -145,6 +145,18 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_max98090_card_remove(struct snd_soc_card *card)
|
||||
{
|
||||
struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
|
||||
&tegra_max98090_hp_jack_gpio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_link tegra_max98090_dai = {
|
||||
.name = "max98090",
|
||||
.stream_name = "max98090 PCM",
|
||||
@ -158,6 +170,7 @@ static struct snd_soc_dai_link tegra_max98090_dai = {
|
||||
static struct snd_soc_card snd_soc_tegra_max98090 = {
|
||||
.name = "tegra-max98090",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = tegra_max98090_card_remove,
|
||||
.dai_link = &tegra_max98090_dai,
|
||||
.num_links = 1,
|
||||
.controls = tegra_max98090_controls,
|
||||
@ -241,9 +254,6 @@ static int tegra_max98090_remove(struct platform_device *pdev)
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
|
||||
&tegra_max98090_hp_jack_gpio);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
tegra_asoc_utils_fini(&machine->util_data);
|
||||
|
@ -128,6 +128,18 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_rt5640_card_remove(struct snd_soc_card *card)
|
||||
{
|
||||
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1,
|
||||
&tegra_rt5640_hp_jack_gpio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_link tegra_rt5640_dai = {
|
||||
.name = "RT5640",
|
||||
.stream_name = "RT5640 PCM",
|
||||
@ -141,6 +153,7 @@ static struct snd_soc_dai_link tegra_rt5640_dai = {
|
||||
static struct snd_soc_card snd_soc_tegra_rt5640 = {
|
||||
.name = "tegra-rt5640",
|
||||
.owner = THIS_MODULE,
|
||||
.remove = tegra_rt5640_card_remove,
|
||||
.dai_link = &tegra_rt5640_dai,
|
||||
.num_links = 1,
|
||||
.controls = tegra_rt5640_controls,
|
||||
@ -224,9 +237,6 @@ static int tegra_rt5640_remove(struct platform_device *pdev)
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1,
|
||||
&tegra_rt5640_hp_jack_gpio);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
tegra_asoc_utils_fini(&machine->util_data);
|
||||
|
@ -206,6 +206,12 @@ static int tegra_wm8903_remove(struct snd_soc_card *card)
|
||||
struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]);
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (gpio_is_valid(machine->gpio_hp_det)) {
|
||||
snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1,
|
||||
&tegra_wm8903_hp_jack_gpio);
|
||||
}
|
||||
|
||||
wm8903_mic_detect(codec, NULL, 0, 0);
|
||||
|
||||
@ -228,9 +234,7 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = {
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &tegra_wm8903_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.remove = tegra_wm8903_remove,
|
||||
|
||||
.controls = tegra_wm8903_controls,
|
||||
.num_controls = ARRAY_SIZE(tegra_wm8903_controls),
|
||||
.dapm_widgets = tegra_wm8903_dapm_widgets,
|
||||
@ -368,9 +372,6 @@ static int tegra_wm8903_driver_remove(struct platform_device *pdev)
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
|
||||
|
||||
snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1,
|
||||
&tegra_wm8903_hp_jack_gpio);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
tegra_asoc_utils_fini(&machine->util_data);
|
||||
|
Loading…
Reference in New Issue
Block a user