mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-29 23:16:39 +07:00
Merge remote-tracking branch 'asoc/topic/davinci' into asoc-next
This commit is contained in:
commit
5561f17f26
19
Documentation/devicetree/bindings/sound/ak5386.txt
Normal file
19
Documentation/devicetree/bindings/sound/ak5386.txt
Normal file
@ -0,0 +1,19 @@
|
||||
AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
|
||||
|
||||
This device has no control interface.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "asahi-kasei,ak5386"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpio : a GPIO spec for the reset/power down pin.
|
||||
If specified, it will be deasserted at probe time.
|
||||
|
||||
Example:
|
||||
|
||||
spdif: ak5386@0 {
|
||||
compatible = "asahi-kasei,ak5386";
|
||||
reset-gpio = <&gpio0 23>;
|
||||
};
|
@ -1,12 +1,22 @@
|
||||
NVIDIA Tegra30 AHUB (Audio Hub)
|
||||
|
||||
Required properties:
|
||||
- compatible : "nvidia,tegra30-ahub"
|
||||
- compatible : "nvidia,tegra30-ahub", "nvidia,tegra114-ahub", etc.
|
||||
- reg : Should contain the register physical address and length for each of
|
||||
the AHUB's APBIF registers and the AHUB's own registers.
|
||||
the AHUB's register blocks.
|
||||
- Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks.
|
||||
- Tegra114 requires an additional entry, for the APBIF2 register block.
|
||||
- interrupts : Should contain AHUB interrupt
|
||||
- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
|
||||
request selector for the first APBIF channel.
|
||||
- nvidia,dma-request-selector : A list of the DMA channel specifiers. Each
|
||||
entry contains the Tegra DMA controller's phandle and request selector.
|
||||
If a single entry is present, the request selectors for the channels are
|
||||
assumed to be contiguous, and increment from this value.
|
||||
If multiple values are given, one value must be given per channel.
|
||||
- clocks : Must contain an entry for each required entry in clock-names.
|
||||
- clock-names : Must include the following entries:
|
||||
- Tegra30: Requires d_audio, apbif, i2s0, i2s1, i2s2, i2s3, i2s4, dam0,
|
||||
dam1, dam2, spdif_in.
|
||||
- Tegra114: Additionally requires amx, adx.
|
||||
- ranges : The bus address mapping for the configlink register bus.
|
||||
Can be empty since the mapping is 1:1.
|
||||
- #address-cells : For the configlink bus. Should be <1>;
|
||||
@ -25,7 +35,13 @@ ahub@70080000 {
|
||||
reg = <0x70080000 0x200 0x70080200 0x100>;
|
||||
interrupts = < 0 103 0x04 >;
|
||||
nvidia,dma-request-selector = <&apbdma 1>;
|
||||
|
||||
clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>,
|
||||
<&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>,
|
||||
<&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>,
|
||||
<&tegra_car 110>, <&tegra_car 162>;
|
||||
clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
|
||||
"i2s3", "i2s4", "dam0", "dam1", "dam2",
|
||||
"spdif_in";
|
||||
ranges;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
32
Documentation/devicetree/bindings/sound/ti,tas5086.txt
Normal file
32
Documentation/devicetree/bindings/sound/ti,tas5086.txt
Normal file
@ -0,0 +1,32 @@
|
||||
Texas Instruments TAS5086 6-channel PWM Processor
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should contain "ti,tas5086".
|
||||
- reg: The i2c address. Should contain <0x1b>.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpio: A GPIO spec to define which pin is connected to the
|
||||
chip's !RESET pin. If specified, the driver will
|
||||
assert a hardware reset at probe time.
|
||||
|
||||
- ti,charge-period: This property should contain the time in microseconds
|
||||
that closely matches the external single-ended
|
||||
split-capacitor charge period. The hardware chip
|
||||
waits for this period of time before starting the
|
||||
PWM signals. This helps reduce pops and clicks.
|
||||
|
||||
When not specified, the hardware default of 1300ms
|
||||
is retained.
|
||||
|
||||
Examples:
|
||||
|
||||
i2c_bus {
|
||||
tas5086@1b {
|
||||
compatible = "ti,tas5086";
|
||||
reg = <0x1b>;
|
||||
reset-gpio = <&gpio 23 0>;
|
||||
ti,charge-period = <156000>;
|
||||
};
|
||||
};
|
@ -25,11 +25,9 @@
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <plat/regs-ac97.h>
|
||||
#include <plat/regs-dma.h>
|
||||
#include <mach/regs-lcd.h>
|
||||
#include <mach/regs-sdi.h>
|
||||
#include <plat/regs-iis.h>
|
||||
#include <plat/regs-spi.h>
|
||||
|
||||
static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
|
||||
|
@ -25,11 +25,9 @@
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <plat/regs-ac97.h>
|
||||
#include <plat/regs-dma.h>
|
||||
#include <mach/regs-lcd.h>
|
||||
#include <mach/regs-sdi.h>
|
||||
#include <plat/regs-iis.h>
|
||||
#include <plat/regs-spi.h>
|
||||
|
||||
#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
|
||||
|
@ -25,11 +25,9 @@
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <plat/regs-ac97.h>
|
||||
#include <plat/regs-dma.h>
|
||||
#include <mach/regs-lcd.h>
|
||||
#include <mach/regs-sdi.h>
|
||||
#include <plat/regs-iis.h>
|
||||
#include <plat/regs-spi.h>
|
||||
|
||||
static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
|
||||
|
@ -25,11 +25,9 @@
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <plat/regs-ac97.h>
|
||||
#include <plat/regs-dma.h>
|
||||
#include <mach/regs-lcd.h>
|
||||
#include <mach/regs-sdi.h>
|
||||
#include <plat/regs-iis.h>
|
||||
#include <plat/regs-spi.h>
|
||||
|
||||
#define MAP(x) { \
|
||||
|
@ -146,14 +146,20 @@ struct platform_device s3c_device_camif = {
|
||||
|
||||
/* ASOC DMA */
|
||||
|
||||
#ifdef CONFIG_PLAT_S5P
|
||||
static struct resource samsung_asoc_idma_resource = DEFINE_RES_IRQ(IRQ_I2S0);
|
||||
|
||||
struct platform_device samsung_asoc_idma = {
|
||||
.name = "samsung-idma",
|
||||
.id = -1,
|
||||
.num_resources = 1,
|
||||
.resource = &samsung_asoc_idma_resource,
|
||||
.dev = {
|
||||
.dma_mask = &samsung_device_dma_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/* FB */
|
||||
|
||||
|
@ -100,6 +100,55 @@ static const char *arizona_cable[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
|
||||
unsigned int magic)
|
||||
{
|
||||
struct arizona *arizona = info->arizona;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&arizona->dapm->card->dapm_mutex);
|
||||
|
||||
arizona->hpdet_magic = magic;
|
||||
|
||||
/* Keep the HP output stages disabled while doing the magic */
|
||||
if (magic) {
|
||||
ret = regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT1L_ENA |
|
||||
ARIZONA_OUT1R_ENA, 0);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev,
|
||||
"Failed to disable headphone outputs: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
|
||||
magic);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to do magic: %d\n",
|
||||
ret);
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
|
||||
magic);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to do magic: %d\n",
|
||||
ret);
|
||||
|
||||
/* Restore the desired state while not doing the magic */
|
||||
if (!magic) {
|
||||
ret = regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT1L_ENA |
|
||||
ARIZONA_OUT1R_ENA, arizona->hp_ena);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev,
|
||||
"Failed to restore headphone outputs: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
mutex_unlock(&arizona->dapm->card->dapm_mutex);
|
||||
}
|
||||
|
||||
static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
|
||||
{
|
||||
struct arizona *arizona = info->arizona;
|
||||
@ -484,7 +533,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
||||
struct arizona *arizona = info->arizona;
|
||||
int id_gpio = arizona->pdata.hpdet_id_gpio;
|
||||
int report = ARIZONA_CABLE_HEADPHONE;
|
||||
unsigned int val;
|
||||
int ret, reading;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
@ -539,28 +587,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
||||
dev_err(arizona->dev, "Failed to report HP/line: %d\n",
|
||||
ret);
|
||||
|
||||
mutex_lock(&arizona->dapm->card->dapm_mutex);
|
||||
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to read output enables: %d\n",
|
||||
ret);
|
||||
val = 0;
|
||||
}
|
||||
|
||||
if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
|
||||
ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to undo magic: %d\n",
|
||||
ret);
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to undo magic: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
mutex_unlock(&arizona->dapm->card->dapm_mutex);
|
||||
arizona_extcon_do_magic(info, 0);
|
||||
|
||||
done:
|
||||
if (id_gpio)
|
||||
@ -606,13 +633,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
|
||||
if (info->mic)
|
||||
arizona_stop_mic(info);
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
|
||||
arizona_extcon_do_magic(info, 0x4000);
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_ACCESSORY_DETECT_MODE_1,
|
||||
@ -653,7 +674,6 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
|
||||
static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
|
||||
{
|
||||
struct arizona *arizona = info->arizona;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
dev_dbg(arizona->dev, "Starting identification via HPDET\n");
|
||||
@ -665,30 +685,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
|
||||
|
||||
arizona_extcon_pulse_micbias(info);
|
||||
|
||||
mutex_lock(&arizona->dapm->card->dapm_mutex);
|
||||
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to read output enables: %d\n",
|
||||
ret);
|
||||
val = 0;
|
||||
}
|
||||
|
||||
if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
|
||||
ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
|
||||
0x4000);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to do magic: %d\n",
|
||||
ret);
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
|
||||
0x4000);
|
||||
if (ret != 0)
|
||||
dev_warn(arizona->dev, "Failed to do magic: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
mutex_unlock(&arizona->dapm->card->dapm_mutex);
|
||||
arizona_extcon_do_magic(info, 0x4000);
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_ACCESSORY_DETECT_MODE_1,
|
||||
|
@ -290,12 +290,14 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */
|
||||
{ 0x00000177, 0x0181 }, /* R375 - FLL1 Loop Filter Test 1 */
|
||||
{ 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */
|
||||
{ 0x00000179, 0x0000 }, /* R377 - FLL1 Control 7 */
|
||||
{ 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */
|
||||
{ 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */
|
||||
{ 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */
|
||||
{ 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */
|
||||
{ 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */
|
||||
{ 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */
|
||||
{ 0x00000187, 0x0001 }, /* R391 - FLL1 Synchroniser 7 */
|
||||
{ 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */
|
||||
{ 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */
|
||||
{ 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */
|
||||
@ -306,12 +308,14 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */
|
||||
{ 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */
|
||||
{ 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */
|
||||
{ 0x00000199, 0x0000 }, /* R409 - FLL2 Control 7 */
|
||||
{ 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */
|
||||
{ 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */
|
||||
{ 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */
|
||||
{ 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */
|
||||
{ 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */
|
||||
{ 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */
|
||||
{ 0x000001A7, 0x0001 }, /* R423 - FLL2 Synchroniser 7 */
|
||||
{ 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */
|
||||
{ 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */
|
||||
{ 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */
|
||||
@ -1051,12 +1055,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_FLL1_CONTROL_6:
|
||||
case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
|
||||
case ARIZONA_FLL1_NCO_TEST_0:
|
||||
case ARIZONA_FLL1_CONTROL_7:
|
||||
case ARIZONA_FLL1_SYNCHRONISER_1:
|
||||
case ARIZONA_FLL1_SYNCHRONISER_2:
|
||||
case ARIZONA_FLL1_SYNCHRONISER_3:
|
||||
case ARIZONA_FLL1_SYNCHRONISER_4:
|
||||
case ARIZONA_FLL1_SYNCHRONISER_5:
|
||||
case ARIZONA_FLL1_SYNCHRONISER_6:
|
||||
case ARIZONA_FLL1_SYNCHRONISER_7:
|
||||
case ARIZONA_FLL1_SPREAD_SPECTRUM:
|
||||
case ARIZONA_FLL1_GPIO_CLOCK:
|
||||
case ARIZONA_FLL2_CONTROL_1:
|
||||
@ -1067,12 +1073,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_FLL2_CONTROL_6:
|
||||
case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
|
||||
case ARIZONA_FLL2_NCO_TEST_0:
|
||||
case ARIZONA_FLL2_CONTROL_7:
|
||||
case ARIZONA_FLL2_SYNCHRONISER_1:
|
||||
case ARIZONA_FLL2_SYNCHRONISER_2:
|
||||
case ARIZONA_FLL2_SYNCHRONISER_3:
|
||||
case ARIZONA_FLL2_SYNCHRONISER_4:
|
||||
case ARIZONA_FLL2_SYNCHRONISER_5:
|
||||
case ARIZONA_FLL2_SYNCHRONISER_6:
|
||||
case ARIZONA_FLL2_SYNCHRONISER_7:
|
||||
case ARIZONA_FLL2_SPREAD_SPECTRUM:
|
||||
case ARIZONA_FLL2_GPIO_CLOCK:
|
||||
case ARIZONA_MIC_CHARGE_PUMP_1:
|
||||
@ -1161,6 +1169,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_NOISE_GATE_CONTROL:
|
||||
case ARIZONA_PDM_SPK1_CTRL_1:
|
||||
case ARIZONA_PDM_SPK1_CTRL_2:
|
||||
case ARIZONA_SPK_CTRL_2:
|
||||
case ARIZONA_SPK_CTRL_3:
|
||||
case ARIZONA_DAC_COMP_1:
|
||||
case ARIZONA_DAC_COMP_2:
|
||||
case ARIZONA_DAC_COMP_3:
|
||||
|
@ -100,6 +100,9 @@ struct arizona {
|
||||
struct regmap_irq_chip_data *aod_irq_chip;
|
||||
struct regmap_irq_chip_data *irq_chip;
|
||||
|
||||
bool hpdet_magic;
|
||||
unsigned int hp_ena;
|
||||
|
||||
struct mutex clk_lock;
|
||||
int clk32k_ref;
|
||||
|
||||
|
@ -85,12 +85,14 @@
|
||||
#define ARIZONA_FLL1_CONTROL_6 0x176
|
||||
#define ARIZONA_FLL1_LOOP_FILTER_TEST_1 0x177
|
||||
#define ARIZONA_FLL1_NCO_TEST_0 0x178
|
||||
#define ARIZONA_FLL1_CONTROL_7 0x179
|
||||
#define ARIZONA_FLL1_SYNCHRONISER_1 0x181
|
||||
#define ARIZONA_FLL1_SYNCHRONISER_2 0x182
|
||||
#define ARIZONA_FLL1_SYNCHRONISER_3 0x183
|
||||
#define ARIZONA_FLL1_SYNCHRONISER_4 0x184
|
||||
#define ARIZONA_FLL1_SYNCHRONISER_5 0x185
|
||||
#define ARIZONA_FLL1_SYNCHRONISER_6 0x186
|
||||
#define ARIZONA_FLL1_SYNCHRONISER_7 0x187
|
||||
#define ARIZONA_FLL1_SPREAD_SPECTRUM 0x189
|
||||
#define ARIZONA_FLL1_GPIO_CLOCK 0x18A
|
||||
#define ARIZONA_FLL2_CONTROL_1 0x191
|
||||
@ -101,12 +103,14 @@
|
||||
#define ARIZONA_FLL2_CONTROL_6 0x196
|
||||
#define ARIZONA_FLL2_LOOP_FILTER_TEST_1 0x197
|
||||
#define ARIZONA_FLL2_NCO_TEST_0 0x198
|
||||
#define ARIZONA_FLL2_CONTROL_7 0x199
|
||||
#define ARIZONA_FLL2_SYNCHRONISER_1 0x1A1
|
||||
#define ARIZONA_FLL2_SYNCHRONISER_2 0x1A2
|
||||
#define ARIZONA_FLL2_SYNCHRONISER_3 0x1A3
|
||||
#define ARIZONA_FLL2_SYNCHRONISER_4 0x1A4
|
||||
#define ARIZONA_FLL2_SYNCHRONISER_5 0x1A5
|
||||
#define ARIZONA_FLL2_SYNCHRONISER_6 0x1A6
|
||||
#define ARIZONA_FLL2_SYNCHRONISER_7 0x1A7
|
||||
#define ARIZONA_FLL2_SPREAD_SPECTRUM 0x1A9
|
||||
#define ARIZONA_FLL2_GPIO_CLOCK 0x1AA
|
||||
#define ARIZONA_MIC_CHARGE_PUMP_1 0x200
|
||||
@ -213,6 +217,8 @@
|
||||
#define ARIZONA_PDM_SPK1_CTRL_2 0x491
|
||||
#define ARIZONA_PDM_SPK2_CTRL_1 0x492
|
||||
#define ARIZONA_PDM_SPK2_CTRL_2 0x493
|
||||
#define ARIZONA_SPK_CTRL_2 0x4B5
|
||||
#define ARIZONA_SPK_CTRL_3 0x4B6
|
||||
#define ARIZONA_DAC_COMP_1 0x4DC
|
||||
#define ARIZONA_DAC_COMP_2 0x4DD
|
||||
#define ARIZONA_DAC_COMP_3 0x4DE
|
||||
@ -1677,6 +1683,13 @@
|
||||
#define ARIZONA_FLL1_FRC_INTEG_VAL_SHIFT 0 /* FLL1_FRC_INTEG_VAL - [11:0] */
|
||||
#define ARIZONA_FLL1_FRC_INTEG_VAL_WIDTH 12 /* FLL1_FRC_INTEG_VAL - [11:0] */
|
||||
|
||||
/*
|
||||
* R377 (0x179) - FLL1 Control 7
|
||||
*/
|
||||
#define ARIZONA_FLL1_GAIN_MASK 0x003c /* FLL1_GAIN */
|
||||
#define ARIZONA_FLL1_GAIN_SHIFT 2 /* FLL1_GAIN */
|
||||
#define ARIZONA_FLL1_GAIN_WIDTH 4 /* FLL1_GAIN */
|
||||
|
||||
/*
|
||||
* R385 (0x181) - FLL1 Synchroniser 1
|
||||
*/
|
||||
@ -1723,6 +1736,17 @@
|
||||
#define ARIZONA_FLL1_CLK_SYNC_SRC_SHIFT 0 /* FLL1_CLK_SYNC_SRC - [3:0] */
|
||||
#define ARIZONA_FLL1_CLK_SYNC_SRC_WIDTH 4 /* FLL1_CLK_SYNC_SRC - [3:0] */
|
||||
|
||||
/*
|
||||
* R391 (0x187) - FLL1 Synchroniser 7
|
||||
*/
|
||||
#define ARIZONA_FLL1_SYNC_GAIN_MASK 0x003c /* FLL1_SYNC_GAIN */
|
||||
#define ARIZONA_FLL1_SYNC_GAIN_SHIFT 2 /* FLL1_SYNC_GAIN */
|
||||
#define ARIZONA_FLL1_SYNC_GAIN_WIDTH 4 /* FLL1_SYNC_GAIN */
|
||||
#define ARIZONA_FLL1_SYNC_BW 0x0001 /* FLL1_SYNC_BW */
|
||||
#define ARIZONA_FLL1_SYNC_BW_MASK 0x0001 /* FLL1_SYNC_BW */
|
||||
#define ARIZONA_FLL1_SYNC_BW_SHIFT 0 /* FLL1_SYNC_BW */
|
||||
#define ARIZONA_FLL1_SYNC_BW_WIDTH 1 /* FLL1_SYNC_BW */
|
||||
|
||||
/*
|
||||
* R393 (0x189) - FLL1 Spread Spectrum
|
||||
*/
|
||||
@ -1815,6 +1839,13 @@
|
||||
#define ARIZONA_FLL2_FRC_INTEG_VAL_SHIFT 0 /* FLL2_FRC_INTEG_VAL - [11:0] */
|
||||
#define ARIZONA_FLL2_FRC_INTEG_VAL_WIDTH 12 /* FLL2_FRC_INTEG_VAL - [11:0] */
|
||||
|
||||
/*
|
||||
* R409 (0x199) - FLL2 Control 7
|
||||
*/
|
||||
#define ARIZONA_FLL2_GAIN_MASK 0x003c /* FLL2_GAIN */
|
||||
#define ARIZONA_FLL2_GAIN_SHIFT 2 /* FLL2_GAIN */
|
||||
#define ARIZONA_FLL2_GAIN_WIDTH 4 /* FLL2_GAIN */
|
||||
|
||||
/*
|
||||
* R417 (0x1A1) - FLL2 Synchroniser 1
|
||||
*/
|
||||
@ -1861,6 +1892,17 @@
|
||||
#define ARIZONA_FLL2_CLK_SYNC_SRC_SHIFT 0 /* FLL2_CLK_SYNC_SRC - [3:0] */
|
||||
#define ARIZONA_FLL2_CLK_SYNC_SRC_WIDTH 4 /* FLL2_CLK_SYNC_SRC - [3:0] */
|
||||
|
||||
/*
|
||||
* R423 (0x1A7) - FLL2 Synchroniser 7
|
||||
*/
|
||||
#define ARIZONA_FLL2_SYNC_GAIN_MASK 0x003c /* FLL2_SYNC_GAIN */
|
||||
#define ARIZONA_FLL2_SYNC_GAIN_SHIFT 2 /* FLL2_SYNC_GAIN */
|
||||
#define ARIZONA_FLL2_SYNC_GAIN_WIDTH 4 /* FLL2_SYNC_GAIN */
|
||||
#define ARIZONA_FLL2_SYNC_BW_MASK 0x0001 /* FLL2_SYNC_BW */
|
||||
#define ARIZONA_FLL2_SYNC_BW_MASK 0x0001 /* FLL2_SYNC_BW */
|
||||
#define ARIZONA_FLL2_SYNC_BW_SHIFT 0 /* FLL2_SYNC_BW */
|
||||
#define ARIZONA_FLL2_SYNC_BW_WIDTH 1 /* FLL2_SYNC_BW */
|
||||
|
||||
/*
|
||||
* R425 (0x1A9) - FLL2 Spread Spectrum
|
||||
*/
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#define WM8994_NUM_LDO 2
|
||||
#define WM8994_NUM_GPIO 11
|
||||
#define WM8994_NUM_AIF 3
|
||||
|
||||
struct wm8994_ldo_pdata {
|
||||
/** GPIOs to enable regulator, 0 or less if not available */
|
||||
@ -215,6 +216,13 @@ struct wm8994_pdata {
|
||||
* system.
|
||||
*/
|
||||
bool spkmode_pu;
|
||||
|
||||
/**
|
||||
* Maximum number of channels clocks will be generated for,
|
||||
* useful for systems where and I2S bus with multiple data
|
||||
* lines is mastered.
|
||||
*/
|
||||
int max_channels_clocked[WM8994_NUM_AIF];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -32,9 +32,6 @@ snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream)
|
||||
return DMA_DEV_TO_MEM;
|
||||
}
|
||||
|
||||
void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data);
|
||||
void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream);
|
||||
|
||||
int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
|
||||
const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config);
|
||||
int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
|
||||
@ -47,4 +44,28 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream);
|
||||
|
||||
struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
|
||||
|
||||
/**
|
||||
* struct snd_dmaengine_dai_dma_data - DAI DMA configuration data
|
||||
* @addr: Address of the DAI data source or destination register.
|
||||
* @addr_width: Width of the DAI data source or destination register.
|
||||
* @maxburst: Maximum number of words(note: words, as in units of the
|
||||
* src_addr_width member, not bytes) that can be send to or received from the
|
||||
* DAI in one burst.
|
||||
* @slave_id: Slave requester id for the DMA channel.
|
||||
* @filter_data: Custom DMA channel filter data, this will usually be used when
|
||||
* requesting the DMA channel.
|
||||
*/
|
||||
struct snd_dmaengine_dai_dma_data {
|
||||
dma_addr_t addr;
|
||||
enum dma_slave_buswidth addr_width;
|
||||
u32 maxburst;
|
||||
unsigned int slave_id;
|
||||
void *filter_data;
|
||||
};
|
||||
|
||||
void snd_dmaengine_pcm_set_config_from_dai_data(
|
||||
const struct snd_pcm_substream *substream,
|
||||
const struct snd_dmaengine_dai_dma_data *dma_data,
|
||||
struct dma_slave_config *config);
|
||||
|
||||
#endif
|
||||
|
@ -95,14 +95,6 @@ struct snd_soc_dai_driver;
|
||||
struct snd_soc_dai;
|
||||
struct snd_ac97_bus_ops;
|
||||
|
||||
/* Digital Audio Interface registration */
|
||||
int snd_soc_register_dai(struct device *dev,
|
||||
struct snd_soc_dai_driver *dai_drv);
|
||||
void snd_soc_unregister_dai(struct device *dev);
|
||||
int snd_soc_register_dais(struct device *dev,
|
||||
struct snd_soc_dai_driver *dai_drv, size_t count);
|
||||
void snd_soc_unregister_dais(struct device *dev, size_t count);
|
||||
|
||||
/* Digital Audio Interface clocking API.*/
|
||||
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
unsigned int freq, int dir);
|
||||
|
@ -324,6 +324,8 @@ struct snd_soc_dai_link;
|
||||
struct snd_soc_platform_driver;
|
||||
struct snd_soc_codec;
|
||||
struct snd_soc_codec_driver;
|
||||
struct snd_soc_component;
|
||||
struct snd_soc_component_driver;
|
||||
struct soc_enum;
|
||||
struct snd_soc_jack;
|
||||
struct snd_soc_jack_zone;
|
||||
@ -377,6 +379,10 @@ int snd_soc_register_codec(struct device *dev,
|
||||
const struct snd_soc_codec_driver *codec_drv,
|
||||
struct snd_soc_dai_driver *dai_drv, int num_dai);
|
||||
void snd_soc_unregister_codec(struct device *dev);
|
||||
int snd_soc_register_component(struct device *dev,
|
||||
const struct snd_soc_component_driver *cmpnt_drv,
|
||||
struct snd_soc_dai_driver *dai_drv, int num_dai);
|
||||
void snd_soc_unregister_component(struct device *dev);
|
||||
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
|
||||
unsigned int reg);
|
||||
int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
|
||||
@ -841,6 +847,20 @@ struct snd_soc_platform {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct snd_soc_component_driver {
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct snd_soc_component {
|
||||
const char *name;
|
||||
int id;
|
||||
int num_dai;
|
||||
struct device *dev;
|
||||
struct list_head list;
|
||||
|
||||
const struct snd_soc_component_driver *driver;
|
||||
};
|
||||
|
||||
struct snd_soc_dai_link {
|
||||
/* config - must be set by machine driver */
|
||||
const char *name; /* Codec name */
|
||||
|
7
include/sound/tas5086.h
Normal file
7
include/sound/tas5086.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _SND_SOC_CODEC_TAS5086_H_
|
||||
#define _SND_SOC_CODEC_TAS5086_H_
|
||||
|
||||
#define TAS5086_CLK_IDX_MCLK 0
|
||||
#define TAS5086_CLK_IDX_SCLK 1
|
||||
|
||||
#endif /* _SND_SOC_CODEC_TAS5086_H_ */
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 NVIDIA, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_TEGRA_WM38903_H
|
||||
#define __SOUND_TEGRA_WM38903_H
|
||||
|
||||
struct tegra_wm8903_platform_data {
|
||||
int gpio_spkr_en;
|
||||
int gpio_hp_det;
|
||||
int gpio_hp_mute;
|
||||
int gpio_int_mic_en;
|
||||
int gpio_ext_mic_en;
|
||||
};
|
||||
|
||||
#endif
|
@ -67,9 +67,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
|
||||
static void atmel_pcm_dma_irq(u32 ssc_sr,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct atmel_pcm_dma_params *prtd;
|
||||
|
||||
prtd = snd_dmaengine_pcm_get_data(substream);
|
||||
prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
if (ssc_sr & prtd->mask->ssc_error) {
|
||||
if (snd_pcm_running(substream))
|
||||
@ -104,15 +105,13 @@ static bool filter(struct dma_chan *chan, void *slave)
|
||||
}
|
||||
|
||||
static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd)
|
||||
{
|
||||
struct atmel_pcm_dma_params *prtd;
|
||||
struct ssc_device *ssc;
|
||||
struct dma_chan *dma_chan;
|
||||
struct dma_slave_config slave_config;
|
||||
int ret;
|
||||
|
||||
prtd = snd_dmaengine_pcm_get_data(substream);
|
||||
ssc = prtd->ssc;
|
||||
|
||||
ret = snd_hwparams_to_dma_slave_config(substream, params,
|
||||
@ -130,8 +129,6 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
|
||||
slave_config.src_maxburst = 1;
|
||||
}
|
||||
|
||||
slave_config.device_fc = false;
|
||||
|
||||
dma_chan = snd_dmaengine_pcm_get_chan(substream);
|
||||
if (dmaengine_slave_config(dma_chan, &slave_config)) {
|
||||
pr_err("atmel-pcm: failed to configure dma channel\n");
|
||||
@ -164,9 +161,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_dmaengine_pcm_set_data(substream, prtd);
|
||||
|
||||
ret = atmel_pcm_configure_dma(substream, params);
|
||||
ret = atmel_pcm_configure_dma(substream, params, prtd);
|
||||
if (ret) {
|
||||
pr_err("atmel-pcm: failed to configure dmai\n");
|
||||
goto err;
|
||||
@ -182,9 +177,10 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct atmel_pcm_dma_params *prtd;
|
||||
|
||||
prtd = snd_dmaengine_pcm_get_data(substream);
|
||||
prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error);
|
||||
ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable);
|
||||
@ -199,16 +195,9 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_dmaengine_pcm_close(substream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops atmel_pcm_ops = {
|
||||
.open = atmel_pcm_open,
|
||||
.close = atmel_pcm_close,
|
||||
.close = snd_dmaengine_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = atmel_pcm_hw_params,
|
||||
.prepare = atmel_pcm_dma_prepare,
|
||||
|
@ -533,6 +533,49 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
|
||||
/*
|
||||
* DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
|
||||
*
|
||||
* The SSC transmit clock is obtained from the BCLK signal on
|
||||
* on the TK line, and the SSC receive clock is
|
||||
* generated from the transmit clock.
|
||||
*
|
||||
* Data is transferred on first BCLK after LRC pulse rising
|
||||
* edge.If stereo, the right channel data is contiguous with
|
||||
* the left channel data.
|
||||
*/
|
||||
rcmr = SSC_BF(RCMR_PERIOD, 0)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(RCMR_CKS, SSC_CKS_PIN);
|
||||
|
||||
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
|
||||
| SSC_BF(RFMR_FSLEN, 0)
|
||||
| SSC_BF(RFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(RFMR_MSBF)
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, 0)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
|
||||
| SSC_BF(TCMR_CKS, SSC_CKS_PIN);
|
||||
|
||||
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
|
||||
| SSC_BF(TFMR_FSDEN, 0)
|
||||
| SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
|
||||
| SSC_BF(TFMR_FSLEN, 0)
|
||||
| SSC_BF(TFMR_DATNB, (channels - 1))
|
||||
| SSC_BIT(TFMR_MSBF)
|
||||
| SSC_BF(TFMR_DATDEF, 0)
|
||||
| SSC_BF(TFMR_DATLEN, (bits - 1));
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
|
||||
ssc_p->daifmt);
|
||||
@ -707,13 +750,18 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
|
||||
.ops = &atmel_ssc_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver atmel_ssc_component = {
|
||||
.name = "atmel-ssc",
|
||||
};
|
||||
|
||||
static int asoc_ssc_init(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ssc_device *ssc = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_register_dai(dev, &atmel_ssc_dai);
|
||||
ret = snd_soc_register_component(dev, &atmel_ssc_component,
|
||||
&atmel_ssc_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not register DAI: %d\n", ret);
|
||||
goto err;
|
||||
@ -732,7 +780,7 @@ static int asoc_ssc_init(struct device *dev)
|
||||
return 0;
|
||||
|
||||
err_unregister_dai:
|
||||
snd_soc_unregister_dai(dev);
|
||||
snd_soc_unregister_component(dev);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
@ -747,7 +795,7 @@ static void asoc_ssc_exit(struct device *dev)
|
||||
else
|
||||
atmel_pcm_pdc_platform_unregister(dev);
|
||||
|
||||
snd_soc_unregister_dai(dev);
|
||||
snd_soc_unregister_component(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,6 +223,10 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = {
|
||||
.ops = &alchemy_ac97c_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver au1xac97c_component = {
|
||||
.name = "au1xac97c",
|
||||
};
|
||||
|
||||
static int au1xac97c_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
@ -268,7 +272,8 @@ static int au1xac97c_drvprobe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
|
||||
ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component,
|
||||
&au1xac97c_dai_driver, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -280,7 +285,7 @@ static int au1xac97c_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */
|
||||
|
||||
|
@ -225,6 +225,10 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = {
|
||||
.ops = &au1xi2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver au1xi2s_component = {
|
||||
.name = "au1xi2s",
|
||||
};
|
||||
|
||||
static int au1xi2s_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *iores, *dmares;
|
||||
@ -260,14 +264,15 @@ static int au1xi2s_drvprobe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
return snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
|
||||
return snd_soc_register_component(&pdev->dev, &au1xi2s_component,
|
||||
&au1xi2s_dai_driver, 1);
|
||||
}
|
||||
|
||||
static int au1xi2s_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */
|
||||
|
||||
|
@ -361,6 +361,10 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
|
||||
.ops = &au1xpsc_ac97_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver au1xpsc_ac97_component = {
|
||||
.name = "au1xpsc-ac97",
|
||||
};
|
||||
|
||||
static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
@ -419,7 +423,8 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, wd);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
|
||||
ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
|
||||
&wd->dai_drv, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -431,7 +436,7 @@ static int au1xpsc_ac97_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
/* disable PSC completely */
|
||||
au_writel(0, AC97_CFG(wd));
|
||||
|
@ -288,6 +288,10 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
|
||||
.ops = &au1xpsc_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver au1xpsc_i2s_component = {
|
||||
.name = "au1xpsc-i2s",
|
||||
};
|
||||
|
||||
static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *iores, *dmares;
|
||||
@ -350,14 +354,15 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, wd);
|
||||
|
||||
return snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
|
||||
return snd_soc_register_component(&pdev->dev, &au1xpsc_i2s_component,
|
||||
&wd->dai_drv, 1);
|
||||
}
|
||||
|
||||
static int au1xpsc_i2s_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
au_writel(0, I2S_CFG(wd));
|
||||
au_sync();
|
||||
|
@ -282,6 +282,10 @@ static struct snd_soc_dai_driver bfin_ac97_dai = {
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bfin_ac97_component = {
|
||||
.name = "bfin-ac97",
|
||||
};
|
||||
|
||||
static int asoc_bfin_ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle;
|
||||
@ -331,7 +335,8 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
|
||||
&bfin_ac97_dai, 1);
|
||||
if (ret) {
|
||||
pr_err("Failed to register DAI: %d\n", ret);
|
||||
goto sport_config_err;
|
||||
@ -356,7 +361,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_done(sport_handle);
|
||||
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
|
||||
gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
|
||||
|
@ -245,6 +245,10 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
|
||||
.ops = &bf5xx_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bf5xx_i2s_component = {
|
||||
.name = "bf5xx-i2s",
|
||||
};
|
||||
|
||||
static int bf5xx_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle;
|
||||
@ -257,7 +261,8 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
|
||||
/* register with the ASoC layers */
|
||||
ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
|
||||
&bf5xx_i2s_dai, 1);
|
||||
if (ret) {
|
||||
pr_err("Failed to register DAI: %d\n", ret);
|
||||
sport_done(sport_handle);
|
||||
@ -273,7 +278,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev)
|
||||
|
||||
pr_debug("%s enter\n", __func__);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_done(sport_handle);
|
||||
|
||||
return 0;
|
||||
|
@ -249,6 +249,10 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
|
||||
.ops = &bf5xx_tdm_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bf5xx_tdm_component = {
|
||||
.name = "bf5xx-tdm",
|
||||
};
|
||||
|
||||
static int bfin_tdm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle;
|
||||
@ -282,7 +286,8 @@ static int bfin_tdm_probe(struct platform_device *pdev)
|
||||
goto sport_config_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component,
|
||||
&bf5xx_tdm_dai, 1);
|
||||
if (ret) {
|
||||
pr_err("Failed to register DAI: %d\n", ret);
|
||||
goto sport_config_err;
|
||||
@ -299,7 +304,7 @@ static int bfin_tdm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport_handle = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_done(sport_handle);
|
||||
|
||||
return 0;
|
||||
|
@ -186,6 +186,10 @@ static struct snd_soc_dai_driver bfin_i2s_dai = {
|
||||
.ops = &bfin_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver bfin_i2s_component = {
|
||||
.name = "bfin-i2s",
|
||||
};
|
||||
|
||||
static int bfin_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport;
|
||||
@ -197,7 +201,8 @@ static int bfin_i2s_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
|
||||
/* register with the ASoC layers */
|
||||
ret = snd_soc_register_dai(dev, &bfin_i2s_dai);
|
||||
ret = snd_soc_register_component(dev, &bfin_i2s_component,
|
||||
&bfin_i2s_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register DAI: %d\n", ret);
|
||||
sport_delete(sport);
|
||||
@ -212,7 +217,7 @@ static int bfin_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sport_device *sport = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
sport_delete(sport);
|
||||
|
||||
return 0;
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <sound/soc.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <mach/hardware.h>
|
||||
#include "ep93xx-pcm.h"
|
||||
|
||||
static int edb93xx_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <linux/platform_data/dma-ep93xx.h>
|
||||
#include "ep93xx-pcm.h"
|
||||
|
||||
/*
|
||||
* Per channel (1-4) registers.
|
||||
@ -101,14 +100,16 @@ struct ep93xx_ac97_info {
|
||||
/* currently ALSA only supports a single AC97 device */
|
||||
static struct ep93xx_ac97_info *ep93xx_ac97_info;
|
||||
|
||||
static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
|
||||
static struct ep93xx_dma_data ep93xx_ac97_pcm_out = {
|
||||
.name = "ac97-pcm-out",
|
||||
.dma_port = EP93XX_DMA_AAC1,
|
||||
.direction = DMA_MEM_TO_DEV,
|
||||
};
|
||||
|
||||
static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
|
||||
static struct ep93xx_dma_data ep93xx_ac97_pcm_in = {
|
||||
.name = "ac97-pcm-in",
|
||||
.dma_port = EP93XX_DMA_AAC1,
|
||||
.direction = DMA_DEV_TO_MEM,
|
||||
};
|
||||
|
||||
static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
|
||||
@ -316,7 +317,7 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
|
||||
static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct ep93xx_pcm_dma_params *dma_data;
|
||||
struct ep93xx_dma_data *dma_data;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dma_data = &ep93xx_ac97_pcm_out;
|
||||
@ -353,6 +354,10 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
|
||||
.ops = &ep93xx_ac97_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver ep93xx_ac97_component = {
|
||||
.name = "ep93xx-ac97",
|
||||
};
|
||||
|
||||
static int ep93xx_ac97_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_ac97_info *info;
|
||||
@ -390,7 +395,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
|
||||
ep93xx_ac97_info = info;
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component,
|
||||
&ep93xx_ac97_dai, 1);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
@ -407,7 +413,7 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
/* disable the AC97 controller */
|
||||
ep93xx_ac97_write_reg(info, AC97GCR, 0);
|
||||
|
@ -30,8 +30,6 @@
|
||||
#include <mach/ep93xx-regs.h>
|
||||
#include <linux/platform_data/dma-ep93xx.h>
|
||||
|
||||
#include "ep93xx-pcm.h"
|
||||
|
||||
#define EP93XX_I2S_TXCLKCFG 0x00
|
||||
#define EP93XX_I2S_RXCLKCFG 0x04
|
||||
#define EP93XX_I2S_GLCTRL 0x0C
|
||||
@ -62,18 +60,20 @@ struct ep93xx_i2s_info {
|
||||
struct clk *mclk;
|
||||
struct clk *sclk;
|
||||
struct clk *lrclk;
|
||||
struct ep93xx_pcm_dma_params *dma_params;
|
||||
struct ep93xx_dma_data *dma_data;
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
|
||||
struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
|
||||
[SNDRV_PCM_STREAM_PLAYBACK] = {
|
||||
.name = "i2s-pcm-out",
|
||||
.dma_port = EP93XX_DMA_I2S1,
|
||||
.port = EP93XX_DMA_I2S1,
|
||||
.direction = DMA_MEM_TO_DEV,
|
||||
},
|
||||
[SNDRV_PCM_STREAM_CAPTURE] = {
|
||||
.name = "i2s-pcm-in",
|
||||
.dma_port = EP93XX_DMA_I2S1,
|
||||
.port = EP93XX_DMA_I2S1,
|
||||
.direction = DMA_DEV_TO_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
@ -147,7 +147,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
|
||||
snd_soc_dai_set_dma_data(cpu_dai, substream,
|
||||
&info->dma_params[substream->stream]);
|
||||
&info->dma_data[substream->stream]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -366,6 +366,10 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = {
|
||||
.ops = &ep93xx_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver ep93xx_i2s_component = {
|
||||
.name = "ep93xx-i2s",
|
||||
};
|
||||
|
||||
static int ep93xx_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_i2s_info *info;
|
||||
@ -403,9 +407,10 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, info);
|
||||
info->dma_params = ep93xx_i2s_dma_params;
|
||||
info->dma_data = ep93xx_i2s_dma_data;
|
||||
|
||||
err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
|
||||
err = snd_soc_register_component(&pdev->dev, &ep93xx_i2s_component,
|
||||
&ep93xx_i2s_dai, 1);
|
||||
if (err)
|
||||
goto fail_put_lrclk;
|
||||
|
||||
@ -426,7 +431,7 @@ static int ep93xx_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
clk_put(info->lrclk);
|
||||
clk_put(info->sclk);
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/ep93xx-regs.h>
|
||||
|
||||
#include "ep93xx-pcm.h"
|
||||
|
||||
static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
|
||||
.info = (SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
@ -68,40 +66,11 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
|
||||
static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct ep93xx_pcm_dma_params *dma_params;
|
||||
struct ep93xx_dma_data *dma_data;
|
||||
int ret;
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
|
||||
|
||||
dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL);
|
||||
if (!dma_data)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
|
||||
dma_data->port = dma_params->dma_port;
|
||||
dma_data->name = dma_params->name;
|
||||
dma_data->direction = snd_pcm_substream_to_dma_direction(substream);
|
||||
|
||||
ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data);
|
||||
if (ret) {
|
||||
kfree(dma_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_dmaengine_pcm_set_data(substream, dma_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
|
||||
|
||||
snd_dmaengine_pcm_close(substream);
|
||||
kfree(dma_data);
|
||||
return 0;
|
||||
return snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter,
|
||||
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
|
||||
}
|
||||
|
||||
static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
@ -131,7 +100,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
|
||||
static struct snd_pcm_ops ep93xx_pcm_ops = {
|
||||
.open = ep93xx_pcm_open,
|
||||
.close = ep93xx_pcm_close,
|
||||
.close = snd_dmaengine_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = ep93xx_pcm_hw_params,
|
||||
.hw_free = ep93xx_pcm_hw_free,
|
||||
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
|
||||
*
|
||||
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
|
||||
* Copyright (C) 2006 Applied Data Systems
|
||||
*
|
||||
* 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 _EP93XX_SND_SOC_PCM_H
|
||||
#define _EP93XX_SND_SOC_PCM_H
|
||||
|
||||
struct ep93xx_pcm_dma_params {
|
||||
char *name;
|
||||
int dma_port;
|
||||
};
|
||||
|
||||
#endif /* _EP93XX_SND_SOC_PCM_H */
|
@ -21,8 +21,6 @@
|
||||
#include <asm/mach-types.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include "ep93xx-pcm.h"
|
||||
|
||||
static struct snd_soc_dai_link simone_dai = {
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include "../codecs/tlv320aic23.h"
|
||||
#include "ep93xx-pcm.h"
|
||||
|
||||
#define CODEC_CLOCK 5644800
|
||||
|
||||
|
@ -26,6 +26,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_AK4641 if I2C
|
||||
select SND_SOC_AK4642 if I2C
|
||||
select SND_SOC_AK4671 if I2C
|
||||
select SND_SOC_AK5386
|
||||
select SND_SOC_ALC5623 if I2C
|
||||
select SND_SOC_ALC5632 if I2C
|
||||
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
|
||||
@ -63,6 +64,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_STA32X if I2C
|
||||
select SND_SOC_STA529 if I2C
|
||||
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_TAS5086 if I2C
|
||||
select SND_SOC_TLV320AIC23 if I2C
|
||||
select SND_SOC_TLV320AIC26 if SPI_MASTER
|
||||
select SND_SOC_TLV320AIC32X4 if I2C
|
||||
@ -203,6 +205,9 @@ config SND_SOC_AK4642
|
||||
config SND_SOC_AK4671
|
||||
tristate
|
||||
|
||||
config SND_SOC_AK5386
|
||||
tristate
|
||||
|
||||
config SND_SOC_ALC5623
|
||||
tristate
|
||||
config SND_SOC_ALC5632
|
||||
@ -320,6 +325,9 @@ config SND_SOC_STA529
|
||||
config SND_SOC_STAC9766
|
||||
tristate
|
||||
|
||||
config SND_SOC_TAS5086
|
||||
tristate
|
||||
|
||||
config SND_SOC_TLV320AIC23
|
||||
tristate
|
||||
|
||||
|
@ -14,6 +14,7 @@ snd-soc-ak4535-objs := ak4535.o
|
||||
snd-soc-ak4641-objs := ak4641.o
|
||||
snd-soc-ak4642-objs := ak4642.o
|
||||
snd-soc-ak4671-objs := ak4671.o
|
||||
snd-soc-ak5386-objs := ak5386.o
|
||||
snd-soc-arizona-objs := arizona.o
|
||||
snd-soc-cq93vc-objs := cq93vc.o
|
||||
snd-soc-cs42l51-objs := cs42l51.o
|
||||
@ -55,6 +56,7 @@ snd-soc-ssm2602-objs := ssm2602.o
|
||||
snd-soc-sta32x-objs := sta32x.o
|
||||
snd-soc-sta529-objs := sta529.o
|
||||
snd-soc-stac9766-objs := stac9766.o
|
||||
snd-soc-tas5086-objs := tas5086.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
||||
snd-soc-tlv320aic26-objs := tlv320aic26.o
|
||||
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
|
||||
@ -137,6 +139,7 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
|
||||
obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o
|
||||
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
|
||||
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
|
||||
obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.o
|
||||
obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
|
||||
obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
|
||||
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
|
||||
@ -177,6 +180,7 @@ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
|
||||
obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o
|
||||
obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
|
||||
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
|
||||
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
|
||||
|
@ -133,6 +133,8 @@ struct adau1373 {
|
||||
#define ADAU1373_DAI_FORMAT_DSP 0x3
|
||||
|
||||
#define ADAU1373_BCLKDIV_SOURCE BIT(5)
|
||||
#define ADAU1373_BCLKDIV_SR_MASK (0x07 << 2)
|
||||
#define ADAU1373_BCLKDIV_BCLK_MASK 0x03
|
||||
#define ADAU1373_BCLKDIV_32 0x03
|
||||
#define ADAU1373_BCLKDIV_64 0x02
|
||||
#define ADAU1373_BCLKDIV_128 0x01
|
||||
@ -937,7 +939,8 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
|
||||
adau1373_dai->enable_src = (div != 0);
|
||||
|
||||
snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id),
|
||||
~ADAU1373_BCLKDIV_SOURCE, (div << 2) | ADAU1373_BCLKDIV_64);
|
||||
ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
|
||||
(div << 2) | ADAU1373_BCLKDIV_64);
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
|
@ -55,6 +55,7 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
int val = 0;
|
||||
int ret;
|
||||
|
||||
@ -77,9 +78,9 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
|
||||
return -EINVAL;
|
||||
|
||||
ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
|
||||
val);
|
||||
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
|
||||
val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -91,11 +92,12 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
int val = 0;
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, val = 0;
|
||||
|
||||
/* set the IEC958 bits: consumer mode, no copyright bit */
|
||||
val |= IEC958_AES0_CON_NOT_COPYRIGHT;
|
||||
snd_soc_write(codec, AK4104_REG_CHN_STATUS(0), val);
|
||||
regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
|
||||
|
||||
val = 0;
|
||||
|
||||
@ -132,11 +134,33 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snd_soc_write(codec, AK4104_REG_CHN_STATUS(3), val);
|
||||
ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* enable transmitter */
|
||||
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
|
||||
AK4104_TX_TXE, AK4104_TX_TXE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4104_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* disable transmitter */
|
||||
return regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
|
||||
AK4104_TX_TXE, 0);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ak4101_dai_ops = {
|
||||
.hw_params = ak4104_hw_params,
|
||||
.hw_free = ak4104_hw_free,
|
||||
.set_fmt = ak4104_set_dai_fmt,
|
||||
};
|
||||
|
||||
@ -160,20 +184,17 @@ static int ak4104_probe(struct snd_soc_codec *codec)
|
||||
int ret;
|
||||
|
||||
codec->control_data = ak4104->regmap;
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* set power-up and non-reset bits */
|
||||
ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
|
||||
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* enable transmitter */
|
||||
ret = snd_soc_update_bits(codec, AK4104_REG_TX,
|
||||
AK4104_TX_TXE, AK4104_TX_TXE);
|
||||
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
|
||||
AK4104_TX_TXE, AK4104_TX_TXE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -182,8 +203,10 @@ static int ak4104_probe(struct snd_soc_codec *codec)
|
||||
|
||||
static int ak4104_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
|
||||
AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
152
sound/soc/codecs/ak5386.c
Normal file
152
sound/soc/codecs/ak5386.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* ALSA SoC driver for
|
||||
* Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
|
||||
*
|
||||
* (c) 2013 Daniel Mack <zonque@gmail.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/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
struct ak5386_priv {
|
||||
int reset_gpio;
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_ak5386;
|
||||
|
||||
static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
|
||||
format &= SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
if (format != SND_SOC_DAIFMT_LEFT_J &&
|
||||
format != SND_SOC_DAIFMT_I2S) {
|
||||
dev_err(codec->dev, "Invalid DAI format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak5386_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 ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/*
|
||||
* From the datasheet:
|
||||
*
|
||||
* All external clocks (MCLK, SCLK and LRCK) must be present unless
|
||||
* PDN pin = “L”. If these clocks are not provided, the AK5386 may
|
||||
* draw excess current due to its use of internal dynamically
|
||||
* refreshed logic. If the external clocks are not present, place
|
||||
* the AK5386 in power-down mode (PDN pin = “L”).
|
||||
*/
|
||||
|
||||
if (gpio_is_valid(priv->reset_gpio))
|
||||
gpio_set_value(priv->reset_gpio, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak5386_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (gpio_is_valid(priv->reset_gpio))
|
||||
gpio_set_value(priv->reset_gpio, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ak5386_dai_ops = {
|
||||
.set_fmt = ak5386_set_dai_fmt,
|
||||
.hw_params = ak5386_hw_params,
|
||||
.hw_free = ak5386_hw_free,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ak5386_dai = {
|
||||
.name = "ak5386-hifi",
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
},
|
||||
.ops = &ak5386_dai_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ak5386_dt_ids[] = {
|
||||
{ .compatible = "asahi-kasei,ak5386", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak5386_dt_ids);
|
||||
#endif
|
||||
|
||||
static int ak5386_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ak5386_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->reset_gpio = -EINVAL;
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
||||
if (of_match_device(of_match_ptr(ak5386_dt_ids), dev))
|
||||
priv->reset_gpio = of_get_named_gpio(dev->of_node,
|
||||
"reset-gpio", 0);
|
||||
|
||||
if (gpio_is_valid(priv->reset_gpio))
|
||||
if (devm_gpio_request_one(dev, priv->reset_gpio,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"AK5386 Reset"))
|
||||
priv->reset_gpio = -EINVAL;
|
||||
|
||||
return snd_soc_register_codec(dev, &soc_codec_ak5386,
|
||||
&ak5386_dai, 1);
|
||||
}
|
||||
|
||||
static int ak5386_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ak5386_driver = {
|
||||
.probe = ak5386_probe,
|
||||
.remove = ak5386_remove,
|
||||
.driver = {
|
||||
.name = "ak5386",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(ak5386_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ak5386_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC driver for AK5386 ADC");
|
||||
MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -10,6 +10,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -65,6 +66,163 @@
|
||||
#define arizona_aif_dbg(_dai, fmt, ...) \
|
||||
dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
|
||||
|
||||
static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
bool manual_ena = false;
|
||||
int val;
|
||||
|
||||
switch (arizona->type) {
|
||||
case WM5102:
|
||||
switch (arizona->rev) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
manual_ena = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
if (!priv->spk_ena && manual_ena) {
|
||||
snd_soc_write(codec, 0x4f5, 0x25a);
|
||||
priv->spk_ena_pending = true;
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
|
||||
if (val & ARIZONA_SPK_SHUTDOWN_STS) {
|
||||
dev_crit(arizona->dev,
|
||||
"Speaker not enabled due to temperature\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
|
||||
1 << w->shift, 1 << w->shift);
|
||||
|
||||
if (priv->spk_ena_pending) {
|
||||
msleep(75);
|
||||
snd_soc_write(codec, 0x4f5, 0xda);
|
||||
priv->spk_ena_pending = false;
|
||||
priv->spk_ena++;
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
if (manual_ena) {
|
||||
priv->spk_ena--;
|
||||
if (!priv->spk_ena)
|
||||
snd_soc_write(codec, 0x4f5, 0x25a);
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
|
||||
1 << w->shift, 0);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
if (manual_ena) {
|
||||
if (!priv->spk_ena)
|
||||
snd_soc_write(codec, 0x4f5, 0x0da);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t arizona_thermal_warn(int irq, void *data)
|
||||
{
|
||||
struct arizona *arizona = data;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
|
||||
&val);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to read thermal status: %d\n",
|
||||
ret);
|
||||
} else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
|
||||
dev_crit(arizona->dev, "Thermal warning\n");
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
|
||||
{
|
||||
struct arizona *arizona = data;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
|
||||
&val);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to read thermal status: %d\n",
|
||||
ret);
|
||||
} else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
|
||||
dev_crit(arizona->dev, "Thermal shutdown\n");
|
||||
ret = regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT4L_ENA |
|
||||
ARIZONA_OUT4R_ENA, 0);
|
||||
if (ret != 0)
|
||||
dev_crit(arizona->dev,
|
||||
"Failed to disable speaker outputs: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget arizona_spkl =
|
||||
SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
|
||||
ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
|
||||
|
||||
static const struct snd_soc_dapm_widget arizona_spkr =
|
||||
SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
|
||||
ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
|
||||
|
||||
int arizona_init_spk(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct arizona *arizona = priv->arizona;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
|
||||
"Thermal warning", arizona_thermal_warn,
|
||||
arizona);
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev,
|
||||
"Failed to get thermal warning IRQ: %d\n",
|
||||
ret);
|
||||
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
|
||||
"Thermal shutdown", arizona_thermal_shutdown,
|
||||
arizona);
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev,
|
||||
"Failed to get thermal shutdown IRQ: %d\n",
|
||||
ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_init_spk);
|
||||
|
||||
const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
|
||||
"None",
|
||||
"Tone Generator 1",
|
||||
@ -274,6 +432,33 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values);
|
||||
const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
|
||||
EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
|
||||
|
||||
const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
|
||||
"SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_rate_text);
|
||||
|
||||
const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
|
||||
0, 1, 2, 8,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_rate_val);
|
||||
|
||||
|
||||
const struct soc_enum arizona_isrc_fsl[] = {
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
|
||||
ARIZONA_ISRC1_FSL_SHIFT, 0xf,
|
||||
ARIZONA_RATE_ENUM_SIZE,
|
||||
arizona_rate_text, arizona_rate_val),
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
|
||||
ARIZONA_ISRC2_FSL_SHIFT, 0xf,
|
||||
ARIZONA_RATE_ENUM_SIZE,
|
||||
arizona_rate_text, arizona_rate_val),
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
|
||||
ARIZONA_ISRC3_FSL_SHIFT, 0xf,
|
||||
ARIZONA_RATE_ENUM_SIZE,
|
||||
arizona_rate_text, arizona_rate_val),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
|
||||
|
||||
static const char *arizona_vol_ramp_text[] = {
|
||||
"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
|
||||
"15ms/6dB", "30ms/6dB",
|
||||
@ -332,9 +517,27 @@ const struct soc_enum arizona_ng_hold =
|
||||
4, arizona_ng_hold_text);
|
||||
EXPORT_SYMBOL_GPL(arizona_ng_hold);
|
||||
|
||||
static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
int i;
|
||||
|
||||
if (ena)
|
||||
val = ARIZONA_IN_VU;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
for (i = 0; i < priv->num_inputs; i++)
|
||||
snd_soc_update_bits(codec,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
|
||||
ARIZONA_IN_VU, val);
|
||||
}
|
||||
|
||||
int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
|
||||
unsigned int reg;
|
||||
|
||||
if (w->shift % 2)
|
||||
@ -343,13 +546,29 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
|
||||
reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
priv->in_pending++;
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
|
||||
|
||||
/* If this is the last input pending then allow VU */
|
||||
priv->in_pending--;
|
||||
if (priv->in_pending == 0) {
|
||||
msleep(1);
|
||||
arizona_in_set_vu(w->codec, 1);
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE,
|
||||
ARIZONA_IN1L_MUTE);
|
||||
snd_soc_update_bits(w->codec, reg,
|
||||
ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
|
||||
ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
/* Disable volume updates if no inputs are enabled */
|
||||
reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
|
||||
if (reg == 0)
|
||||
arizona_in_set_vu(w->codec, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -360,10 +579,61 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
switch (w->shift) {
|
||||
case ARIZONA_OUT1L_ENA_SHIFT:
|
||||
case ARIZONA_OUT1R_ENA_SHIFT:
|
||||
case ARIZONA_OUT2L_ENA_SHIFT:
|
||||
case ARIZONA_OUT2R_ENA_SHIFT:
|
||||
case ARIZONA_OUT3L_ENA_SHIFT:
|
||||
case ARIZONA_OUT3R_ENA_SHIFT:
|
||||
msleep(17);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_out_ev);
|
||||
|
||||
int arizona_hp_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
|
||||
unsigned int mask = 1 << w->shift;
|
||||
unsigned int val;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
val = mask;
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Store the desired state for the HP outputs */
|
||||
priv->arizona->hp_ena &= ~mask;
|
||||
priv->arizona->hp_ena |= val;
|
||||
|
||||
/* Force off if HPDET magic is active */
|
||||
if (priv->arizona->hpdet_magic)
|
||||
val = 0;
|
||||
|
||||
snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
|
||||
|
||||
return arizona_out_ev(w, kcontrol, event);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_hp_ev);
|
||||
|
||||
static unsigned int arizona_sysclk_48k_rates[] = {
|
||||
6144000,
|
||||
12288000,
|
||||
@ -469,27 +739,27 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
break;
|
||||
case 11289600:
|
||||
case 12288000:
|
||||
val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
break;
|
||||
case 22579200:
|
||||
case 24576000:
|
||||
val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
break;
|
||||
case 45158400:
|
||||
case 49152000:
|
||||
val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
break;
|
||||
case 67737600:
|
||||
case 73728000:
|
||||
val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
break;
|
||||
case 90316800:
|
||||
case 98304000:
|
||||
val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
break;
|
||||
case 135475200:
|
||||
case 147456000:
|
||||
val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
|
||||
break;
|
||||
case 0:
|
||||
dev_dbg(arizona->dev, "%s cleared\n", name);
|
||||
@ -783,7 +1053,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
|
||||
struct arizona *arizona = priv->arizona;
|
||||
int base = dai->driver->base;
|
||||
const int *rates;
|
||||
int i, ret;
|
||||
int i, ret, val;
|
||||
int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
|
||||
int bclk, lrclk, wl, frame, bclk_target;
|
||||
|
||||
@ -799,6 +1069,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
|
||||
bclk_target *= chan_limit;
|
||||
}
|
||||
|
||||
/* Force stereo for I2S mode */
|
||||
val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
|
||||
if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
|
||||
arizona_aif_dbg(dai, "Forcing stereo mode\n");
|
||||
bclk_target *= 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
|
||||
if (rates[i] >= bclk_target &&
|
||||
rates[i] % params_rate(params) == 0) {
|
||||
@ -955,6 +1232,16 @@ static struct {
|
||||
{ 1000000, 13500000, 0, 1 },
|
||||
};
|
||||
|
||||
static struct {
|
||||
unsigned int min;
|
||||
unsigned int max;
|
||||
u16 gain;
|
||||
} fll_gains[] = {
|
||||
{ 0, 256000, 0 },
|
||||
{ 256000, 1000000, 2 },
|
||||
{ 1000000, 13500000, 4 },
|
||||
};
|
||||
|
||||
struct arizona_fll_cfg {
|
||||
int n;
|
||||
int theta;
|
||||
@ -962,6 +1249,7 @@ struct arizona_fll_cfg {
|
||||
int refdiv;
|
||||
int outdiv;
|
||||
int fratio;
|
||||
int gain;
|
||||
};
|
||||
|
||||
static int arizona_calc_fll(struct arizona_fll *fll,
|
||||
@ -1021,6 +1309,18 @@ static int arizona_calc_fll(struct arizona_fll *fll,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
|
||||
if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
|
||||
cfg->gain = fll_gains[i].gain;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_SIZE(fll_gains)) {
|
||||
arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
|
||||
Fref);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cfg->n = target / (ratio * Fref);
|
||||
|
||||
if (target % (ratio * Fref)) {
|
||||
@ -1048,13 +1348,15 @@ static int arizona_calc_fll(struct arizona_fll *fll,
|
||||
cfg->n, cfg->theta, cfg->lambda);
|
||||
arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
|
||||
cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
|
||||
arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
|
||||
struct arizona_fll_cfg *cfg, int source)
|
||||
struct arizona_fll_cfg *cfg, int source,
|
||||
bool sync)
|
||||
{
|
||||
regmap_update_bits(arizona->regmap, base + 3,
|
||||
ARIZONA_FLL1_THETA_MASK, cfg->theta);
|
||||
@ -1069,87 +1371,84 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
|
||||
cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
|
||||
source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
|
||||
|
||||
if (sync)
|
||||
regmap_update_bits(arizona->regmap, base + 0x7,
|
||||
ARIZONA_FLL1_GAIN_MASK,
|
||||
cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
|
||||
else
|
||||
regmap_update_bits(arizona->regmap, base + 0x9,
|
||||
ARIZONA_FLL1_GAIN_MASK,
|
||||
cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
|
||||
|
||||
regmap_update_bits(arizona->regmap, base + 2,
|
||||
ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
|
||||
ARIZONA_FLL1_CTRL_UPD | cfg->n);
|
||||
}
|
||||
|
||||
int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
unsigned int Fref, unsigned int Fout)
|
||||
static bool arizona_is_enabled_fll(struct arizona_fll *fll)
|
||||
{
|
||||
struct arizona *arizona = fll->arizona;
|
||||
struct arizona_fll_cfg cfg, sync;
|
||||
unsigned int reg, val;
|
||||
int syncsrc;
|
||||
bool ena;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
if (fll->fref == Fref && fll->fout == Fout)
|
||||
return 0;
|
||||
|
||||
ret = regmap_read(arizona->regmap, fll->base + 1, ®);
|
||||
if (ret != 0) {
|
||||
arizona_fll_err(fll, "Failed to read current state: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
ena = reg & ARIZONA_FLL1_ENA;
|
||||
|
||||
if (Fout) {
|
||||
/* Do we have a 32kHz reference? */
|
||||
regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
|
||||
switch (val & ARIZONA_CLK_32K_SRC_MASK) {
|
||||
case ARIZONA_CLK_SRC_MCLK1:
|
||||
case ARIZONA_CLK_SRC_MCLK2:
|
||||
syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
|
||||
break;
|
||||
default:
|
||||
syncsrc = -1;
|
||||
}
|
||||
return reg & ARIZONA_FLL1_ENA;
|
||||
}
|
||||
|
||||
if (source == syncsrc)
|
||||
syncsrc = -1;
|
||||
static void arizona_enable_fll(struct arizona_fll *fll,
|
||||
struct arizona_fll_cfg *ref,
|
||||
struct arizona_fll_cfg *sync)
|
||||
{
|
||||
struct arizona *arizona = fll->arizona;
|
||||
int ret;
|
||||
|
||||
if (syncsrc >= 0) {
|
||||
ret = arizona_calc_fll(fll, &sync, Fref, Fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
/*
|
||||
* If we have both REFCLK and SYNCCLK then enable both,
|
||||
* otherwise apply the SYNCCLK settings to REFCLK.
|
||||
*/
|
||||
if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
|
||||
regmap_update_bits(arizona->regmap, fll->base + 5,
|
||||
ARIZONA_FLL1_OUTDIV_MASK,
|
||||
ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
|
||||
|
||||
arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
|
||||
false);
|
||||
if (fll->sync_src >= 0)
|
||||
arizona_apply_fll(arizona, fll->base + 0x10, sync,
|
||||
fll->sync_src, true);
|
||||
} else if (fll->sync_src >= 0) {
|
||||
regmap_update_bits(arizona->regmap, fll->base + 5,
|
||||
ARIZONA_FLL1_OUTDIV_MASK,
|
||||
sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
|
||||
|
||||
arizona_apply_fll(arizona, fll->base, sync,
|
||||
fll->sync_src, false);
|
||||
|
||||
ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
} else {
|
||||
ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
regmap_update_bits(arizona->regmap, fll->base + 1,
|
||||
ARIZONA_FLL1_ENA, 0);
|
||||
regmap_update_bits(arizona->regmap, fll->base + 0x11,
|
||||
ARIZONA_FLL1_SYNC_ENA, 0);
|
||||
|
||||
if (ena)
|
||||
pm_runtime_put_autosuspend(arizona->dev);
|
||||
|
||||
fll->fref = Fref;
|
||||
fll->fout = Fout;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
regmap_update_bits(arizona->regmap, fll->base + 5,
|
||||
ARIZONA_FLL1_OUTDIV_MASK,
|
||||
cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
|
||||
|
||||
if (syncsrc >= 0) {
|
||||
arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
|
||||
arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
|
||||
} else {
|
||||
arizona_apply_fll(arizona, fll->base, &cfg, source);
|
||||
arizona_fll_err(fll, "No clocks provided\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ena)
|
||||
/*
|
||||
* Increase the bandwidth if we're not using a low frequency
|
||||
* sync source.
|
||||
*/
|
||||
if (fll->sync_src >= 0 && fll->sync_freq > 100000)
|
||||
regmap_update_bits(arizona->regmap, fll->base + 0x17,
|
||||
ARIZONA_FLL1_SYNC_BW, 0);
|
||||
else
|
||||
regmap_update_bits(arizona->regmap, fll->base + 0x17,
|
||||
ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
|
||||
|
||||
if (!arizona_is_enabled_fll(fll))
|
||||
pm_runtime_get(arizona->dev);
|
||||
|
||||
/* Clear any pending completions */
|
||||
@ -1157,7 +1456,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
|
||||
regmap_update_bits(arizona->regmap, fll->base + 1,
|
||||
ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
|
||||
if (syncsrc >= 0)
|
||||
if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
|
||||
fll->ref_src != fll->sync_src)
|
||||
regmap_update_bits(arizona->regmap, fll->base + 0x11,
|
||||
ARIZONA_FLL1_SYNC_ENA,
|
||||
ARIZONA_FLL1_SYNC_ENA);
|
||||
@ -1166,10 +1466,88 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
msecs_to_jiffies(250));
|
||||
if (ret == 0)
|
||||
arizona_fll_warn(fll, "Timed out waiting for lock\n");
|
||||
}
|
||||
|
||||
fll->fref = Fref;
|
||||
static void arizona_disable_fll(struct arizona_fll *fll)
|
||||
{
|
||||
struct arizona *arizona = fll->arizona;
|
||||
bool change;
|
||||
|
||||
regmap_update_bits_check(arizona->regmap, fll->base + 1,
|
||||
ARIZONA_FLL1_ENA, 0, &change);
|
||||
regmap_update_bits(arizona->regmap, fll->base + 0x11,
|
||||
ARIZONA_FLL1_SYNC_ENA, 0);
|
||||
|
||||
if (change)
|
||||
pm_runtime_put_autosuspend(arizona->dev);
|
||||
}
|
||||
|
||||
int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
|
||||
unsigned int Fref, unsigned int Fout)
|
||||
{
|
||||
struct arizona_fll_cfg ref, sync;
|
||||
int ret;
|
||||
|
||||
if (fll->ref_src == source && fll->ref_freq == Fref)
|
||||
return 0;
|
||||
|
||||
if (fll->fout && Fref > 0) {
|
||||
ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
if (fll->sync_src >= 0) {
|
||||
ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
|
||||
fll->fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fll->ref_src = source;
|
||||
fll->ref_freq = Fref;
|
||||
|
||||
if (fll->fout && Fref > 0) {
|
||||
arizona_enable_fll(fll, &ref, &sync);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
|
||||
|
||||
int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
unsigned int Fref, unsigned int Fout)
|
||||
{
|
||||
struct arizona_fll_cfg ref, sync;
|
||||
int ret;
|
||||
|
||||
if (fll->sync_src == source &&
|
||||
fll->sync_freq == Fref && fll->fout == Fout)
|
||||
return 0;
|
||||
|
||||
if (Fout) {
|
||||
if (fll->ref_src >= 0) {
|
||||
ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
|
||||
Fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = arizona_calc_fll(fll, &sync, Fref, Fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fll->sync_src = source;
|
||||
fll->sync_freq = Fref;
|
||||
fll->fout = Fout;
|
||||
|
||||
if (Fout) {
|
||||
arizona_enable_fll(fll, &ref, &sync);
|
||||
} else {
|
||||
arizona_disable_fll(fll);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_set_fll);
|
||||
@ -1178,12 +1556,26 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
|
||||
int ok_irq, struct arizona_fll *fll)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
init_completion(&fll->ok);
|
||||
|
||||
fll->id = id;
|
||||
fll->base = base;
|
||||
fll->arizona = arizona;
|
||||
fll->sync_src = ARIZONA_FLL_SRC_NONE;
|
||||
|
||||
/* Configure default refclk to 32kHz if we have one */
|
||||
regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
|
||||
switch (val & ARIZONA_CLK_32K_SRC_MASK) {
|
||||
case ARIZONA_CLK_SRC_MCLK1:
|
||||
case ARIZONA_CLK_SRC_MCLK2:
|
||||
fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
|
||||
break;
|
||||
default:
|
||||
fll->ref_src = ARIZONA_FLL_SRC_NONE;
|
||||
}
|
||||
fll->ref_freq = 32768;
|
||||
|
||||
snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
|
||||
snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define ARIZONA_CLK_SRC_AIF2BCLK 0x9
|
||||
#define ARIZONA_CLK_SRC_AIF3BCLK 0xa
|
||||
|
||||
#define ARIZONA_FLL_SRC_NONE -1
|
||||
#define ARIZONA_FLL_SRC_MCLK1 0
|
||||
#define ARIZONA_FLL_SRC_MCLK2 1
|
||||
#define ARIZONA_FLL_SRC_SLIMCLK 3
|
||||
@ -48,6 +49,14 @@
|
||||
#define ARIZONA_MIXER_VOL_SHIFT 1
|
||||
#define ARIZONA_MIXER_VOL_WIDTH 7
|
||||
|
||||
#define ARIZONA_CLK_6MHZ 0
|
||||
#define ARIZONA_CLK_12MHZ 1
|
||||
#define ARIZONA_CLK_24MHZ 2
|
||||
#define ARIZONA_CLK_49MHZ 3
|
||||
#define ARIZONA_CLK_73MHZ 4
|
||||
#define ARIZONA_CLK_98MHZ 5
|
||||
#define ARIZONA_CLK_147MHZ 6
|
||||
|
||||
#define ARIZONA_MAX_DAI 4
|
||||
#define ARIZONA_MAX_ADSP 4
|
||||
|
||||
@ -64,6 +73,12 @@ struct arizona_priv {
|
||||
int sysclk;
|
||||
int asyncclk;
|
||||
struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
|
||||
|
||||
int num_inputs;
|
||||
unsigned int in_pending;
|
||||
|
||||
unsigned int spk_ena:2;
|
||||
unsigned int spk_ena_pending:1;
|
||||
};
|
||||
|
||||
#define ARIZONA_NUM_MIXER_INPUTS 99
|
||||
@ -165,6 +180,12 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
|
||||
ARIZONA_MIXER_ROUTES(name, name "L"), \
|
||||
ARIZONA_MIXER_ROUTES(name, name "R")
|
||||
|
||||
#define ARIZONA_RATE_ENUM_SIZE 4
|
||||
extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
|
||||
extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
|
||||
|
||||
extern const struct soc_enum arizona_isrc_fsl[];
|
||||
|
||||
extern const struct soc_enum arizona_in_vi_ramp;
|
||||
extern const struct soc_enum arizona_in_vd_ramp;
|
||||
|
||||
@ -184,6 +205,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
|
||||
extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event);
|
||||
|
||||
extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
int source, unsigned int freq, int dir);
|
||||
@ -198,8 +222,12 @@ struct arizona_fll {
|
||||
unsigned int base;
|
||||
unsigned int vco_mult;
|
||||
struct completion ok;
|
||||
unsigned int fref;
|
||||
|
||||
unsigned int fout;
|
||||
int sync_src;
|
||||
unsigned int sync_freq;
|
||||
int ref_src;
|
||||
unsigned int ref_freq;
|
||||
|
||||
char lock_name[ARIZONA_FLL_NAME_LEN];
|
||||
char clock_ok_name[ARIZONA_FLL_NAME_LEN];
|
||||
@ -207,9 +235,13 @@ struct arizona_fll {
|
||||
|
||||
extern int arizona_init_fll(struct arizona *arizona, int id, int base,
|
||||
int lock_irq, int ok_irq, struct arizona_fll *fll);
|
||||
extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
|
||||
unsigned int Fref, unsigned int Fout);
|
||||
extern int arizona_set_fll(struct arizona_fll *fll, int source,
|
||||
unsigned int Fref, unsigned int Fout);
|
||||
|
||||
extern int arizona_init_spk(struct snd_soc_codec *codec);
|
||||
|
||||
extern int arizona_init_dai(struct arizona_priv *priv, int dai);
|
||||
|
||||
int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
|
||||
|
@ -1180,7 +1180,11 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
priv->config[id].mmcc &= 0xC0;
|
||||
priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc;
|
||||
priv->config[id].spc &= 0xFC;
|
||||
priv->config[id].spc |= MCK_SCLK_MCLK;
|
||||
/* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */
|
||||
if (priv->mclk >= 6400000)
|
||||
priv->config[id].spc |= MCK_SCLK_64FS;
|
||||
else
|
||||
priv->config[id].spc |= MCK_SCLK_MCLK;
|
||||
} else {
|
||||
/* CS42L73 Slave */
|
||||
priv->config[id].spc &= 0xFC;
|
||||
|
@ -739,14 +739,32 @@ static const unsigned int max98088_micboost_tlv[] = {
|
||||
2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
|
||||
};
|
||||
|
||||
static const unsigned int max98088_hp_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(5),
|
||||
0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
|
||||
7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
|
||||
15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
|
||||
22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
|
||||
28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
|
||||
};
|
||||
|
||||
static const unsigned int max98088_spk_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(5),
|
||||
0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
|
||||
7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
|
||||
15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
|
||||
22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
|
||||
28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new max98088_snd_controls[] = {
|
||||
|
||||
SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
|
||||
M98088_REG_3A_LVL_HP_R, 0, 31, 0),
|
||||
SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
|
||||
M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
|
||||
SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
|
||||
M98088_REG_3C_LVL_REC_R, 0, 31, 0),
|
||||
SOC_DOUBLE_R_TLV("Headphone Volume", M98088_REG_39_LVL_HP_L,
|
||||
M98088_REG_3A_LVL_HP_R, 0, 31, 0, max98088_hp_tlv),
|
||||
SOC_DOUBLE_R_TLV("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
|
||||
M98088_REG_3E_LVL_SPK_R, 0, 31, 0, max98088_spk_tlv),
|
||||
SOC_DOUBLE_R_TLV("Receiver Volume", M98088_REG_3B_LVL_REC_L,
|
||||
M98088_REG_3C_LVL_REC_R, 0, 31, 0, max98088_spk_tlv),
|
||||
|
||||
SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
|
||||
M98088_REG_3A_LVL_HP_R, 7, 1, 1),
|
||||
|
@ -23,8 +23,6 @@
|
||||
#include <sound/max98090.h>
|
||||
#include "max98090.h"
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#define DEBUG
|
||||
#define EXTMIC_METHOD
|
||||
#define EXTMIC_METHOD_TEST
|
||||
@ -509,16 +507,16 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * max98090_perf_pwr_text[] =
|
||||
static const char *max98090_perf_pwr_text[] =
|
||||
{ "High Performance", "Low Power" };
|
||||
static const char * max98090_pwr_perf_text[] =
|
||||
static const char *max98090_pwr_perf_text[] =
|
||||
{ "Low Power", "High Performance" };
|
||||
|
||||
static const struct soc_enum max98090_vcmbandgap_enum =
|
||||
SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT,
|
||||
ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
|
||||
|
||||
static const char * max98090_osr128_text[] = { "64*fs", "128*fs" };
|
||||
static const char *max98090_osr128_text[] = { "64*fs", "128*fs" };
|
||||
|
||||
static const struct soc_enum max98090_osr128_enum =
|
||||
SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT,
|
||||
@ -535,28 +533,28 @@ static const struct soc_enum max98090_filter_dmic34mode_enum =
|
||||
M98090_FLT_DMIC34MODE_SHIFT,
|
||||
ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
|
||||
|
||||
static const char * max98090_drcatk_text[] =
|
||||
static const char *max98090_drcatk_text[] =
|
||||
{ "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" };
|
||||
|
||||
static const struct soc_enum max98090_drcatk_enum =
|
||||
SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT,
|
||||
ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text);
|
||||
|
||||
static const char * max98090_drcrls_text[] =
|
||||
static const char *max98090_drcrls_text[] =
|
||||
{ "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" };
|
||||
|
||||
static const struct soc_enum max98090_drcrls_enum =
|
||||
SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT,
|
||||
ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text);
|
||||
|
||||
static const char * max98090_alccmp_text[] =
|
||||
static const char *max98090_alccmp_text[] =
|
||||
{ "1:1", "1:1.5", "1:2", "1:4", "1:INF" };
|
||||
|
||||
static const struct soc_enum max98090_alccmp_enum =
|
||||
SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT,
|
||||
ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text);
|
||||
|
||||
static const char * max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
|
||||
static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
|
||||
|
||||
static const struct soc_enum max98090_drcexp_enum =
|
||||
SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT,
|
||||
@ -859,7 +857,7 @@ static const struct soc_enum mic2_mux_enum =
|
||||
static const struct snd_kcontrol_new max98090_mic2_mux =
|
||||
SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
|
||||
|
||||
static const char * max98090_micpre_text[] = { "Off", "On" };
|
||||
static const char *max98090_micpre_text[] = { "Off", "On" };
|
||||
|
||||
static const struct soc_enum max98090_pa1en_enum =
|
||||
SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
|
||||
@ -1703,9 +1701,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
|
||||
* seen for the case of TDM mode. The remaining cases have
|
||||
* normal logic.
|
||||
*/
|
||||
if (max98090->tdm_slots > 1) {
|
||||
if (max98090->tdm_slots > 1)
|
||||
regval ^= M98090_BCI_MASK;
|
||||
}
|
||||
|
||||
snd_soc_write(codec,
|
||||
M98090_REG_INTERFACE_FORMAT, regval);
|
||||
@ -2059,17 +2056,14 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
|
||||
if (!active)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (active & M98090_CLD_MASK) {
|
||||
if (active & M98090_CLD_MASK)
|
||||
dev_err(codec->dev, "M98090_CLD_MASK\n");
|
||||
}
|
||||
|
||||
if (active & M98090_SLD_MASK) {
|
||||
if (active & M98090_SLD_MASK)
|
||||
dev_dbg(codec->dev, "M98090_SLD_MASK\n");
|
||||
}
|
||||
|
||||
if (active & M98090_ULK_MASK) {
|
||||
if (active & M98090_ULK_MASK)
|
||||
dev_err(codec->dev, "M98090_ULK_MASK\n");
|
||||
}
|
||||
|
||||
if (active & M98090_JDET_MASK) {
|
||||
dev_dbg(codec->dev, "M98090_JDET_MASK\n");
|
||||
@ -2080,13 +2074,11 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
|
||||
msecs_to_jiffies(100));
|
||||
}
|
||||
|
||||
if (active & M98090_DRCACT_MASK) {
|
||||
if (active & M98090_DRCACT_MASK)
|
||||
dev_dbg(codec->dev, "M98090_DRCACT_MASK\n");
|
||||
}
|
||||
|
||||
if (active & M98090_DRCCLP_MASK) {
|
||||
if (active & M98090_DRCCLP_MASK)
|
||||
dev_err(codec->dev, "M98090_DRCCLP_MASK\n");
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -2324,7 +2316,7 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
|
||||
max98090->pdata = i2c->dev.platform_data;
|
||||
max98090->irq = i2c->irq;
|
||||
|
||||
max98090->regmap = regmap_init_i2c(i2c, &max98090_regmap);
|
||||
max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
|
||||
if (IS_ERR(max98090->regmap)) {
|
||||
ret = PTR_ERR(max98090->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
|
||||
@ -2334,18 +2326,13 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_max98090, max98090_dai,
|
||||
ARRAY_SIZE(max98090_dai));
|
||||
if (ret < 0)
|
||||
regmap_exit(max98090->regmap);
|
||||
|
||||
err_enable:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max98090_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct max98090_priv *max98090 = dev_get_drvdata(&client->dev);
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
regmap_exit(max98090->regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2369,7 +2356,7 @@ static int max98090_runtime_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops max98090_pm = {
|
||||
static const struct dev_pm_ops max98090_pm = {
|
||||
SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
|
||||
max98090_runtime_resume, NULL)
|
||||
};
|
||||
|
@ -1,3 +1,22 @@
|
||||
/*
|
||||
* sound/soc/codecs/si476x.c -- Codec driver for SI476X chips
|
||||
*
|
||||
* Copyright (C) 2012 Innovative Converged Devices(ICD)
|
||||
* Copyright (C) 2013 Andrey Smirnov
|
||||
*
|
||||
* Author: Andrey Smirnov <andrew.smirnov@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/pcm.h>
|
||||
@ -45,13 +64,23 @@ static unsigned int si476x_codec_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
int err;
|
||||
unsigned int val;
|
||||
struct si476x_core *core = codec->control_data;
|
||||
|
||||
si476x_core_lock(core);
|
||||
err = si476x_core_cmd_get_property(core, reg);
|
||||
if (!si476x_core_is_powered_up(core))
|
||||
regcache_cache_only(core->regmap, true);
|
||||
|
||||
err = regmap_read(core->regmap, reg, &val);
|
||||
|
||||
if (!si476x_core_is_powered_up(core))
|
||||
regcache_cache_only(core->regmap, false);
|
||||
si476x_core_unlock(core);
|
||||
|
||||
return err;
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int si476x_codec_write(struct snd_soc_codec *codec,
|
||||
@ -61,7 +90,13 @@ static int si476x_codec_write(struct snd_soc_codec *codec,
|
||||
struct si476x_core *core = codec->control_data;
|
||||
|
||||
si476x_core_lock(core);
|
||||
err = si476x_core_cmd_set_property(core, reg, val);
|
||||
if (!si476x_core_is_powered_up(core))
|
||||
regcache_cache_only(core->regmap, true);
|
||||
|
||||
err = regmap_write(core->regmap, reg, val);
|
||||
|
||||
if (!si476x_core_is_powered_up(core))
|
||||
regcache_cache_only(core->regmap, false);
|
||||
si476x_core_unlock(core);
|
||||
|
||||
return err;
|
||||
@ -140,7 +175,7 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
dev_err(codec_dai->codec->dev, "Failed to set output format\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -182,7 +217,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
|
||||
SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK,
|
||||
(width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) |
|
||||
(width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) |
|
||||
(width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
|
||||
if (err < 0) {
|
||||
dev_err(dai->codec->dev, "Failed to set output width\n");
|
||||
@ -251,6 +286,6 @@ static struct platform_driver si476x_platform_driver = {
|
||||
};
|
||||
module_platform_driver(si476x_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Andrey Smirnov <andrey.smirnov@convergeddevices.net>");
|
||||
MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
|
||||
MODULE_DESCRIPTION("ASoC Si4761/64 codec driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
591
sound/soc/codecs/tas5086.c
Normal file
591
sound/soc/codecs/tas5086.c
Normal file
@ -0,0 +1,591 @@
|
||||
/*
|
||||
* TAS5086 ASoC codec driver
|
||||
*
|
||||
* Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* TODO:
|
||||
* - implement DAPM and input muxing
|
||||
* - implement modulation limit
|
||||
* - implement non-default PWM start
|
||||
*
|
||||
* Note that this chip has a very unusual register layout, specifically
|
||||
* because the registers are of unequal size, and multi-byte registers
|
||||
* require bulk writes to take effect. Regmap does not support that kind
|
||||
* of devices.
|
||||
*
|
||||
* Currently, the driver does not touch any of the registers >= 0x20, so
|
||||
* it doesn't matter because the entire map can be accessed as 8-bit
|
||||
* array. In case more features will be added in the future
|
||||
* that require access to higher registers, the entire regmap H/W I/O
|
||||
* routines have to be open-coded.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/tas5086.h>
|
||||
|
||||
#define TAS5086_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_3LE)
|
||||
|
||||
#define TAS5086_PCM_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
|
||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
|
||||
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
|
||||
SNDRV_PCM_RATE_192000)
|
||||
|
||||
/*
|
||||
* TAS5086 registers
|
||||
*/
|
||||
#define TAS5086_CLOCK_CONTROL 0x00 /* Clock control register */
|
||||
#define TAS5086_CLOCK_RATE(val) (val << 5)
|
||||
#define TAS5086_CLOCK_RATE_MASK (0x7 << 5)
|
||||
#define TAS5086_CLOCK_RATIO(val) (val << 2)
|
||||
#define TAS5086_CLOCK_RATIO_MASK (0x7 << 2)
|
||||
#define TAS5086_CLOCK_SCLK_RATIO_48 (1 << 1)
|
||||
#define TAS5086_CLOCK_VALID (1 << 0)
|
||||
|
||||
#define TAS5086_DEEMPH_MASK 0x03
|
||||
#define TAS5086_SOFT_MUTE_ALL 0x3f
|
||||
|
||||
#define TAS5086_DEV_ID 0x01 /* Device ID register */
|
||||
#define TAS5086_ERROR_STATUS 0x02 /* Error status register */
|
||||
#define TAS5086_SYS_CONTROL_1 0x03 /* System control register 1 */
|
||||
#define TAS5086_SERIAL_DATA_IF 0x04 /* Serial data interface register */
|
||||
#define TAS5086_SYS_CONTROL_2 0x05 /* System control register 2 */
|
||||
#define TAS5086_SOFT_MUTE 0x06 /* Soft mute register */
|
||||
#define TAS5086_MASTER_VOL 0x07 /* Master volume */
|
||||
#define TAS5086_CHANNEL_VOL(X) (0x08 + (X)) /* Channel 1-6 volume */
|
||||
#define TAS5086_VOLUME_CONTROL 0x09 /* Volume control register */
|
||||
#define TAS5086_MOD_LIMIT 0x10 /* Modulation limit register */
|
||||
#define TAS5086_PWM_START 0x18 /* PWM start register */
|
||||
#define TAS5086_SURROUND 0x19 /* Surround register */
|
||||
#define TAS5086_SPLIT_CAP_CHARGE 0x1a /* Split cap charge period register */
|
||||
#define TAS5086_OSC_TRIM 0x1b /* Oscillator trim register */
|
||||
#define TAS5086_BKNDERR 0x1c
|
||||
|
||||
/*
|
||||
* Default TAS5086 power-up configuration
|
||||
*/
|
||||
static const struct reg_default tas5086_reg_defaults[] = {
|
||||
{ 0x00, 0x6c },
|
||||
{ 0x01, 0x03 },
|
||||
{ 0x02, 0x00 },
|
||||
{ 0x03, 0xa0 },
|
||||
{ 0x04, 0x05 },
|
||||
{ 0x05, 0x60 },
|
||||
{ 0x06, 0x00 },
|
||||
{ 0x07, 0xff },
|
||||
{ 0x08, 0x30 },
|
||||
{ 0x09, 0x30 },
|
||||
{ 0x0a, 0x30 },
|
||||
{ 0x0b, 0x30 },
|
||||
{ 0x0c, 0x30 },
|
||||
{ 0x0d, 0x30 },
|
||||
{ 0x0e, 0xb1 },
|
||||
{ 0x0f, 0x00 },
|
||||
{ 0x10, 0x02 },
|
||||
{ 0x11, 0x00 },
|
||||
{ 0x12, 0x00 },
|
||||
{ 0x13, 0x00 },
|
||||
{ 0x14, 0x00 },
|
||||
{ 0x15, 0x00 },
|
||||
{ 0x16, 0x00 },
|
||||
{ 0x17, 0x00 },
|
||||
{ 0x18, 0x3f },
|
||||
{ 0x19, 0x00 },
|
||||
{ 0x1a, 0x18 },
|
||||
{ 0x1b, 0x82 },
|
||||
{ 0x1c, 0x05 },
|
||||
};
|
||||
|
||||
static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17));
|
||||
}
|
||||
|
||||
static bool tas5086_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TAS5086_DEV_ID:
|
||||
case TAS5086_ERROR_STATUS:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tas5086_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID);
|
||||
}
|
||||
|
||||
struct tas5086_private {
|
||||
struct regmap *regmap;
|
||||
unsigned int mclk, sclk;
|
||||
unsigned int format;
|
||||
bool deemph;
|
||||
/* Current sample rate for de-emphasis control */
|
||||
int rate;
|
||||
/* GPIO driving Reset pin, if any */
|
||||
int gpio_nreset;
|
||||
};
|
||||
|
||||
static int tas5086_deemph[] = { 0, 32000, 44100, 48000 };
|
||||
|
||||
static int tas5086_set_deemph(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int i, val = 0;
|
||||
|
||||
if (priv->deemph)
|
||||
for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++)
|
||||
if (tas5086_deemph[i] == priv->rate)
|
||||
val = i;
|
||||
|
||||
return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1,
|
||||
TAS5086_DEEMPH_MASK, val);
|
||||
}
|
||||
|
||||
static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = priv->deemph;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
priv->deemph = ucontrol->value.enumerated.item[0];
|
||||
|
||||
return tas5086_set_deemph(codec);
|
||||
}
|
||||
|
||||
|
||||
static int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (clk_id) {
|
||||
case TAS5086_CLK_IDX_MCLK:
|
||||
priv->mclk = freq;
|
||||
break;
|
||||
case TAS5086_CLK_IDX_SCLK:
|
||||
priv->sclk = freq;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* The TAS5086 can only be slave to all clocks */
|
||||
if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
|
||||
dev_err(codec->dev, "Invalid clocking mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* we need to refer to the data format from hw_params() */
|
||||
priv->format = format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const int tas5086_sample_rates[] = {
|
||||
32000, 38000, 44100, 48000, 88200, 96000, 176400, 192000
|
||||
};
|
||||
|
||||
static const int tas5086_ratios[] = {
|
||||
64, 128, 192, 256, 384, 512
|
||||
};
|
||||
|
||||
static int index_in_array(const int *array, int len, int needle)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (array[i] == needle)
|
||||
return i;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int tas5086_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 tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
priv->rate = params_rate(params);
|
||||
|
||||
/* Look up the sample rate and refer to the offset in the list */
|
||||
val = index_in_array(tas5086_sample_rates,
|
||||
ARRAY_SIZE(tas5086_sample_rates), priv->rate);
|
||||
|
||||
if (val < 0) {
|
||||
dev_err(codec->dev, "Invalid sample rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
|
||||
TAS5086_CLOCK_RATE_MASK,
|
||||
TAS5086_CLOCK_RATE(val));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* MCLK / Fs ratio */
|
||||
val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios),
|
||||
priv->mclk / priv->rate);
|
||||
if (val < 0) {
|
||||
dev_err(codec->dev, "Inavlid MCLK / Fs ratio\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
|
||||
TAS5086_CLOCK_RATIO_MASK,
|
||||
TAS5086_CLOCK_RATIO(val));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
||||
ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
|
||||
TAS5086_CLOCK_SCLK_RATIO_48,
|
||||
(priv->sclk == 48 * priv->rate) ?
|
||||
TAS5086_CLOCK_SCLK_RATIO_48 : 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The chip has a very unituitive register mapping and muxes information
|
||||
* about data format and sample depth into the same register, but not on
|
||||
* a logical bit-boundary. Hence, we have to refer to the format passed
|
||||
* in the set_dai_fmt() callback and set up everything from here.
|
||||
*
|
||||
* First, determine the 'base' value, using the format ...
|
||||
*/
|
||||
switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
val = 0x00;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val = 0x03;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
val = 0x06;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Invalid DAI format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* ... then add the offset for the sample bit depth. */
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
val += 0;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S20_3LE:
|
||||
val += 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_3LE:
|
||||
val += 2;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Invalid bit width\n");
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* clock is considered valid now */
|
||||
ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
|
||||
TAS5086_CLOCK_VALID, TAS5086_CLOCK_VALID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return tas5086_set_deemph(codec);
|
||||
}
|
||||
|
||||
static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val = 0;
|
||||
|
||||
if (mute)
|
||||
val = TAS5086_SOFT_MUTE_ALL;
|
||||
|
||||
return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
|
||||
}
|
||||
|
||||
/* TAS5086 controls */
|
||||
static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
|
||||
|
||||
static const struct snd_kcontrol_new tas5086_controls[] = {
|
||||
SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL,
|
||||
0, 0xff, 1, tas5086_dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
|
||||
TAS5086_CHANNEL_VOL(0), TAS5086_CHANNEL_VOL(1),
|
||||
0, 0xff, 1, tas5086_dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
|
||||
TAS5086_CHANNEL_VOL(2), TAS5086_CHANNEL_VOL(3),
|
||||
0, 0xff, 1, tas5086_dac_tlv),
|
||||
SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
|
||||
TAS5086_CHANNEL_VOL(4), TAS5086_CHANNEL_VOL(5),
|
||||
0, 0xff, 1, tas5086_dac_tlv),
|
||||
SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
|
||||
tas5086_get_deemph, tas5086_put_deemph),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops tas5086_dai_ops = {
|
||||
.hw_params = tas5086_hw_params,
|
||||
.set_sysclk = tas5086_set_dai_sysclk,
|
||||
.set_fmt = tas5086_set_dai_fmt,
|
||||
.mute_stream = tas5086_mute_stream,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver tas5086_dai = {
|
||||
.name = "tas5086-hifi",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 6,
|
||||
.rates = TAS5086_PCM_RATES,
|
||||
.formats = TAS5086_PCM_FORMATS,
|
||||
},
|
||||
.ops = &tas5086_dai_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tas5086_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Restore codec state */
|
||||
return regcache_sync(priv->regmap);
|
||||
}
|
||||
#else
|
||||
#define tas5086_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id tas5086_dt_ids[] = {
|
||||
{ .compatible = "ti,tas5086", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
|
||||
#endif
|
||||
|
||||
/* charge period values in microseconds */
|
||||
static const int tas5086_charge_period[] = {
|
||||
13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
|
||||
130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
|
||||
1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
|
||||
};
|
||||
|
||||
static int tas5086_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int charge_period = 1300000; /* hardware default is 1300 ms */
|
||||
int i, ret;
|
||||
|
||||
if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
|
||||
struct device_node *of_node = codec->dev->of_node;
|
||||
of_property_read_u32(of_node, "ti,charge-period", &charge_period);
|
||||
}
|
||||
|
||||
/* lookup and set split-capacitor charge period */
|
||||
if (charge_period == 0) {
|
||||
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
|
||||
} else {
|
||||
i = index_in_array(tas5086_charge_period,
|
||||
ARRAY_SIZE(tas5086_charge_period),
|
||||
charge_period);
|
||||
if (i >= 0)
|
||||
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
|
||||
i + 0x08);
|
||||
else
|
||||
dev_warn(codec->dev,
|
||||
"Invalid split-cap charge period of %d ns.\n",
|
||||
charge_period);
|
||||
}
|
||||
|
||||
/* enable factory trim */
|
||||
ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* start all channels */
|
||||
ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set master volume to 0 dB */
|
||||
ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* mute all channels for now */
|
||||
ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
|
||||
TAS5086_SOFT_MUTE_ALL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas5086_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (gpio_is_valid(priv->gpio_nreset))
|
||||
/* Set codec to the reset state */
|
||||
gpio_set_value(priv->gpio_nreset, 0);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
|
||||
.probe = tas5086_probe,
|
||||
.remove = tas5086_remove,
|
||||
.resume = tas5086_soc_resume,
|
||||
.controls = tas5086_controls,
|
||||
.num_controls = ARRAY_SIZE(tas5086_controls),
|
||||
};
|
||||
|
||||
static const struct i2c_device_id tas5086_i2c_id[] = {
|
||||
{ "tas5086", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
|
||||
|
||||
static const struct regmap_config tas5086_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = ARRAY_SIZE(tas5086_reg_defaults),
|
||||
.reg_defaults = tas5086_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(tas5086_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.volatile_reg = tas5086_volatile_reg,
|
||||
.writeable_reg = tas5086_writeable_reg,
|
||||
.readable_reg = tas5086_accessible_reg,
|
||||
};
|
||||
|
||||
static int tas5086_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tas5086_private *priv;
|
||||
struct device *dev = &i2c->dev;
|
||||
int gpio_nreset = -EINVAL;
|
||||
int i, ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
ret = PTR_ERR(priv->regmap);
|
||||
dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, priv);
|
||||
|
||||
if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) {
|
||||
struct device_node *of_node = dev->of_node;
|
||||
gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0);
|
||||
}
|
||||
|
||||
if (gpio_is_valid(gpio_nreset))
|
||||
if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
|
||||
gpio_nreset = -EINVAL;
|
||||
|
||||
if (gpio_is_valid(gpio_nreset)) {
|
||||
/* Reset codec - minimum assertion time is 400ns */
|
||||
gpio_direction_output(gpio_nreset, 0);
|
||||
udelay(1);
|
||||
gpio_set_value(gpio_nreset, 1);
|
||||
|
||||
/* Codec needs ~15ms to wake up */
|
||||
msleep(15);
|
||||
}
|
||||
|
||||
priv->gpio_nreset = gpio_nreset;
|
||||
|
||||
/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
|
||||
ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (i != 0x3) {
|
||||
dev_err(dev,
|
||||
"Failed to identify TAS5086 codec (got %02x)\n", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,
|
||||
&tas5086_dai, 1);
|
||||
}
|
||||
|
||||
static int tas5086_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver tas5086_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tas5086",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(tas5086_dt_ids),
|
||||
},
|
||||
.id_table = tas5086_i2c_id,
|
||||
.probe = tas5086_i2c_probe,
|
||||
.remove = tas5086_i2c_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(tas5086_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
|
||||
MODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -342,7 +342,7 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
|
||||
data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
|
||||
}
|
||||
|
||||
static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
|
||||
static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(codec->dev);
|
||||
struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
|
||||
@ -361,8 +361,8 @@ static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
|
||||
|
||||
ret = request_firmware(&fw, name, codec->dev);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to request application: %d\n",
|
||||
ret);
|
||||
dev_err(codec->dev, "Failed to request application(%s): %d\n",
|
||||
name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -761,6 +761,8 @@ static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
|
||||
case WM2000_REG_SYS_CTL2:
|
||||
case WM2000_REG_ANC_STAT:
|
||||
case WM2000_REG_IF_CTL:
|
||||
case WM2000_REG_ANA_MIC_CTL:
|
||||
case WM2000_REG_SPK_CTL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -771,7 +773,7 @@ static const struct regmap_config wm2000_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = WM2000_REG_IF_CTL,
|
||||
.max_register = WM2000_REG_SPK_CTL,
|
||||
.readable_reg = wm2000_readable_reg,
|
||||
};
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
#define WM2000_REG_SYS_CTL2 0xf004
|
||||
#define WM2000_REG_ANC_STAT 0xf005
|
||||
#define WM2000_REG_IF_CTL 0xf006
|
||||
#define WM2000_REG_ANA_MIC_CTL 0xf028
|
||||
#define WM2000_REG_SPK_CTL 0xf034
|
||||
|
||||
/* SPEECH_CLARITY */
|
||||
#define WM2000_SPEECH_CLARITY 0x01
|
||||
|
@ -1565,7 +1565,7 @@ static int wm2200_probe(struct snd_soc_codec *codec)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2);
|
||||
ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
|
@ -36,9 +36,6 @@
|
||||
struct wm5102_priv {
|
||||
struct arizona_priv core;
|
||||
struct arizona_fll fll[2];
|
||||
|
||||
unsigned int spk_ena:2;
|
||||
unsigned int spk_ena_pending:1;
|
||||
};
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
|
||||
@ -615,6 +612,26 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *wm5102_osr_text[] = {
|
||||
"Low power", "Normal", "High performance",
|
||||
};
|
||||
|
||||
static const unsigned int wm5102_osr_val[] = {
|
||||
0x0, 0x3, 0x5,
|
||||
};
|
||||
|
||||
static const struct soc_enum wm5102_hpout_osr[] = {
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
|
||||
ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
|
||||
wm5102_osr_text, wm5102_osr_val),
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
|
||||
ARIZONA_OUT2_OSR_SHIFT, 0x7, 3,
|
||||
wm5102_osr_text, wm5102_osr_val),
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
|
||||
ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
|
||||
wm5102_osr_text, wm5102_osr_val),
|
||||
};
|
||||
|
||||
#define WM5102_NG_SRC(name, base) \
|
||||
SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \
|
||||
SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \
|
||||
@ -745,6 +762,9 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
|
||||
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
|
||||
SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
|
||||
|
||||
SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
|
||||
SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
|
||||
|
||||
ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
|
||||
|
||||
@ -761,6 +781,8 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
|
||||
|
||||
SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
|
||||
ARIZONA_OUT4_OSR_SHIFT, 1, 0),
|
||||
SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
|
||||
ARIZONA_OUT5_OSR_SHIFT, 1, 0),
|
||||
|
||||
@ -790,6 +812,10 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
|
||||
ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
|
||||
0xbf, 0, digital_tlv),
|
||||
|
||||
SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
|
||||
SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
|
||||
SOC_VALUE_ENUM("HPOUT3 OSR", wm5102_hpout_osr[2]),
|
||||
|
||||
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
|
||||
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
|
||||
|
||||
@ -828,47 +854,6 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
|
||||
ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
|
||||
};
|
||||
|
||||
static int wm5102_spk_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
|
||||
struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (arizona->rev < 1)
|
||||
return 0;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
if (!wm5102->spk_ena) {
|
||||
snd_soc_write(codec, 0x4f5, 0x25a);
|
||||
wm5102->spk_ena_pending = true;
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
if (wm5102->spk_ena_pending) {
|
||||
msleep(75);
|
||||
snd_soc_write(codec, 0x4f5, 0xda);
|
||||
wm5102->spk_ena_pending = false;
|
||||
wm5102->spk_ena++;
|
||||
}
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
wm5102->spk_ena--;
|
||||
if (!wm5102->spk_ena)
|
||||
snd_soc_write(codec, 0x4f5, 0x25a);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
if (!wm5102->spk_ena)
|
||||
snd_soc_write(codec, 0x4f5, 0x0da);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
|
||||
ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
|
||||
@ -984,22 +969,28 @@ SND_SOC_DAPM_INPUT("IN3R"),
|
||||
|
||||
SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
|
||||
ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
|
||||
@ -1131,11 +1122,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
|
||||
SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
|
||||
ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux),
|
||||
|
||||
SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
|
||||
ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
|
||||
ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
@ -1146,12 +1137,6 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
|
||||
SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
@ -1494,6 +1479,12 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
|
||||
return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout);
|
||||
case WM5102_FLL2:
|
||||
return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout);
|
||||
case WM5102_FLL1_REFCLK:
|
||||
return arizona_set_fll_refclk(&wm5102->fll[0], source, Fref,
|
||||
Fout);
|
||||
case WM5102_FLL2_REFCLK:
|
||||
return arizona_set_fll_refclk(&wm5102->fll[1], source, Fref,
|
||||
Fout);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1581,10 +1572,12 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1);
|
||||
ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
arizona_init_spk(codec);
|
||||
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
|
||||
|
||||
priv->core.arizona->dapm = &codec->dapm;
|
||||
@ -1604,13 +1597,6 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec)
|
||||
#define WM5102_DIG_VU 0x0200
|
||||
|
||||
static unsigned int wm5102_digital_vu[] = {
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1R,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_2L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_2R,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_3L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_3R,
|
||||
|
||||
ARIZONA_DAC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_DAC_DIGITAL_VOLUME_1R,
|
||||
ARIZONA_DAC_DIGITAL_VOLUME_2L,
|
||||
@ -1653,6 +1639,7 @@ static int wm5102_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, wm5102);
|
||||
|
||||
wm5102->core.arizona = arizona;
|
||||
wm5102->core.num_inputs = 6;
|
||||
|
||||
wm5102->core.adsp[0].part = "wm5102";
|
||||
wm5102->core.adsp[0].num = 1;
|
||||
@ -1677,6 +1664,12 @@ static int wm5102_probe(struct platform_device *pdev)
|
||||
ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
|
||||
&wm5102->fll[1]);
|
||||
|
||||
/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
|
||||
ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
|
||||
ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++)
|
||||
arizona_init_dai(&wm5102->core, i);
|
||||
|
||||
|
@ -15,7 +15,9 @@
|
||||
|
||||
#include "arizona.h"
|
||||
|
||||
#define WM5102_FLL1 1
|
||||
#define WM5102_FLL2 2
|
||||
#define WM5102_FLL1 1
|
||||
#define WM5102_FLL2 2
|
||||
#define WM5102_FLL1_REFCLK 3
|
||||
#define WM5102_FLL2_REFCLK 4
|
||||
|
||||
#endif
|
||||
|
@ -416,28 +416,36 @@ SND_SOC_DAPM_INPUT("IN4R"),
|
||||
|
||||
SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT,
|
||||
0, NULL, 0, arizona_in_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
|
||||
ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
|
||||
@ -551,11 +559,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
|
||||
SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
|
||||
ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
|
||||
ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
|
||||
ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
@ -569,12 +577,6 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
|
||||
ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
|
||||
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
|
||||
@ -880,6 +882,12 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
|
||||
return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout);
|
||||
case WM5110_FLL2:
|
||||
return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout);
|
||||
case WM5110_FLL1_REFCLK:
|
||||
return arizona_set_fll_refclk(&wm5110->fll[0], source, Fref,
|
||||
Fout);
|
||||
case WM5110_FLL2_REFCLK:
|
||||
return arizona_set_fll_refclk(&wm5110->fll[1], source, Fref,
|
||||
Fout);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -987,15 +995,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
|
||||
#define WM5110_DIG_VU 0x0200
|
||||
|
||||
static unsigned int wm5110_digital_vu[] = {
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_1R,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_2L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_2R,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_3L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_3R,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_4L,
|
||||
ARIZONA_ADC_DIGITAL_VOLUME_4R,
|
||||
|
||||
ARIZONA_DAC_DIGITAL_VOLUME_1L,
|
||||
ARIZONA_DAC_DIGITAL_VOLUME_1R,
|
||||
ARIZONA_DAC_DIGITAL_VOLUME_2L,
|
||||
@ -1040,6 +1039,7 @@ static int wm5110_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, wm5110);
|
||||
|
||||
wm5110->core.arizona = arizona;
|
||||
wm5110->core.num_inputs = 8;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
|
||||
wm5110->fll[i].vco_mult = 3;
|
||||
|
@ -15,7 +15,9 @@
|
||||
|
||||
#include "arizona.h"
|
||||
|
||||
#define WM5110_FLL1 1
|
||||
#define WM5110_FLL2 2
|
||||
#define WM5110_FLL1 1
|
||||
#define WM5110_FLL2 2
|
||||
#define WM5110_FLL1_REFCLK 3
|
||||
#define WM5110_FLL2_REFCLK 4
|
||||
|
||||
#endif
|
||||
|
@ -478,6 +478,8 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
|
||||
/* ALSA can only do steps of .01dB */
|
||||
static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
|
||||
|
||||
@ -698,6 +700,8 @@ SOC_ENUM("DAC Mute Mode", mute_mode),
|
||||
SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
|
||||
SOC_ENUM("DAC Companding Mode", dac_companding),
|
||||
SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
|
||||
SOC_SINGLE_TLV("DAC Boost Volume", WM8903_AUDIO_INTERFACE_0, 9, 3, 0,
|
||||
dac_boost_tlv),
|
||||
SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
|
||||
wm8903_get_deemph, wm8903_put_deemph),
|
||||
|
||||
|
@ -204,6 +204,7 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
|
||||
|
||||
static const struct snd_kcontrol_new wm8960_snd_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
|
||||
@ -213,6 +214,15 @@ SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
|
||||
SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
|
||||
7, 1, 0),
|
||||
|
||||
SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
|
||||
WM8960_INBMIX1, 4, 7, 0, boost_tlv),
|
||||
SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
|
||||
WM8960_INBMIX1, 1, 7, 0, boost_tlv),
|
||||
SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
|
||||
WM8960_INBMIX2, 4, 7, 0, boost_tlv),
|
||||
SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
|
||||
WM8960_INBMIX2, 1, 7, 0, boost_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC,
|
||||
0, 255, 0, dac_tlv),
|
||||
|
||||
|
@ -2209,7 +2209,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
|
||||
vmid_reference(codec);
|
||||
break;
|
||||
case WM8958:
|
||||
if (wm8994->revision < 1)
|
||||
if (control->revision < 1)
|
||||
vmid_reference(codec);
|
||||
break;
|
||||
default:
|
||||
@ -2244,7 +2244,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
|
||||
vmid_dereference(codec);
|
||||
break;
|
||||
case WM8958:
|
||||
if (wm8994->revision < 1)
|
||||
if (control->revision < 1)
|
||||
vmid_dereference(codec);
|
||||
break;
|
||||
default:
|
||||
@ -2268,10 +2268,26 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
|
||||
*/
|
||||
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
|
||||
dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
|
||||
|
||||
wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK, 0x1);
|
||||
snd_soc_update_bits(codec, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK, 0x1);
|
||||
} else if (wm8994->aifdiv[0]) {
|
||||
snd_soc_update_bits(codec, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK,
|
||||
wm8994->aifdiv[0]);
|
||||
snd_soc_update_bits(codec, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK,
|
||||
wm8994->aifdiv[1]);
|
||||
|
||||
wm8994->aifdiv[0] = 0;
|
||||
wm8994->aifdiv[1] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2368,10 +2384,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
||||
*/
|
||||
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
|
||||
dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
|
||||
|
||||
wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK, 0x1);
|
||||
snd_soc_update_bits(codec, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK, 0x1);
|
||||
} else if (wm8994->aifdiv[0]) {
|
||||
snd_soc_update_bits(codec, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK,
|
||||
wm8994->aifdiv[0]);
|
||||
snd_soc_update_bits(codec, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK,
|
||||
wm8994->aifdiv[1]);
|
||||
|
||||
wm8994->aifdiv[0] = 0;
|
||||
wm8994->aifdiv[1] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2411,7 +2443,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
|
||||
switch (control->type) {
|
||||
case WM8958:
|
||||
if (wm8994->revision == 0) {
|
||||
if (control->revision == 0) {
|
||||
/* Optimise performance for rev A */
|
||||
snd_soc_update_bits(codec,
|
||||
WM8958_CHARGE_PUMP_2,
|
||||
@ -2656,6 +2688,8 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8994 *control = wm8994->wm8994;
|
||||
struct wm8994_pdata *pdata = &control->pdata;
|
||||
int aif1_reg;
|
||||
int aif2_reg;
|
||||
int bclk_reg;
|
||||
@ -2723,7 +2757,14 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
|
||||
wm8994->channels[id] = params_channels(params);
|
||||
switch (params_channels(params)) {
|
||||
if (pdata->max_channels_clocked[id] &&
|
||||
wm8994->channels[id] > pdata->max_channels_clocked[id]) {
|
||||
dev_dbg(dai->dev, "Constraining channels to %d from %d\n",
|
||||
pdata->max_channels_clocked[id], wm8994->channels[id]);
|
||||
wm8994->channels[id] = pdata->max_channels_clocked[id];
|
||||
}
|
||||
|
||||
switch (wm8994->channels[id]) {
|
||||
case 1:
|
||||
case 2:
|
||||
bclk_rate *= 2;
|
||||
@ -2745,7 +2786,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
|
||||
dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
|
||||
dai->id, wm8994->aifclk[id], bclk_rate);
|
||||
|
||||
if (params_channels(params) == 1 &&
|
||||
if (wm8994->channels[id] == 1 &&
|
||||
(snd_soc_read(codec, aif1_reg) & 0x18) == 0x18)
|
||||
aif2 |= WM8994_AIF1_MONO;
|
||||
|
||||
@ -3053,7 +3094,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
|
||||
int i, ret;
|
||||
unsigned int val, mask;
|
||||
|
||||
if (wm8994->revision < 4) {
|
||||
if (control->revision < 4) {
|
||||
/* force a HW read */
|
||||
ret = regmap_read(control->regmap,
|
||||
WM8994_POWER_MANAGEMENT_5, &val);
|
||||
@ -3870,7 +3911,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
codec->dapm.idle_bias_off = 1;
|
||||
|
||||
/* Set revision-specific configuration */
|
||||
wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION);
|
||||
switch (control->type) {
|
||||
case WM8994:
|
||||
/* Single ended line outputs should have VMID on. */
|
||||
@ -3878,7 +3918,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
!control->pdata.lineout2_diff)
|
||||
codec->dapm.idle_bias_off = 0;
|
||||
|
||||
switch (wm8994->revision) {
|
||||
switch (control->revision) {
|
||||
case 2:
|
||||
case 3:
|
||||
wm8994->hubs.dcs_codes_l = -5;
|
||||
@ -3897,7 +3937,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
wm8994->hubs.dcs_readback_mode = 1;
|
||||
wm8994->hubs.hp_startup_mode = 1;
|
||||
|
||||
switch (wm8994->revision) {
|
||||
switch (control->revision) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
@ -4000,7 +4040,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
|
||||
switch (control->type) {
|
||||
case WM1811:
|
||||
if (control->cust_id > 1 || wm8994->revision > 1) {
|
||||
if (control->cust_id > 1 || control->revision > 1) {
|
||||
ret = wm8994_request_irq(wm8994->wm8994,
|
||||
WM8994_IRQ_GPIO(6),
|
||||
wm1811_jackdet_irq, "JACKDET",
|
||||
@ -4114,7 +4154,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
case WM8994:
|
||||
snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
|
||||
ARRAY_SIZE(wm8994_specific_dapm_widgets));
|
||||
if (wm8994->revision < 4) {
|
||||
if (control->revision < 4) {
|
||||
snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
|
||||
ARRAY_SIZE(wm8994_lateclk_revd_widgets));
|
||||
snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
|
||||
@ -4135,7 +4175,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
ARRAY_SIZE(wm8958_snd_controls));
|
||||
snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
|
||||
ARRAY_SIZE(wm8958_dapm_widgets));
|
||||
if (wm8994->revision < 1) {
|
||||
if (control->revision < 1) {
|
||||
snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
|
||||
ARRAY_SIZE(wm8994_lateclk_revd_widgets));
|
||||
snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
|
||||
@ -4174,7 +4214,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
snd_soc_dapm_add_routes(dapm, wm8994_intercon,
|
||||
ARRAY_SIZE(wm8994_intercon));
|
||||
|
||||
if (wm8994->revision < 4) {
|
||||
if (control->revision < 4) {
|
||||
snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
|
||||
ARRAY_SIZE(wm8994_revd_intercon));
|
||||
snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
|
||||
@ -4185,7 +4225,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
||||
}
|
||||
break;
|
||||
case WM8958:
|
||||
if (wm8994->revision < 1) {
|
||||
if (control->revision < 1) {
|
||||
snd_soc_dapm_add_routes(dapm, wm8994_intercon,
|
||||
ARRAY_SIZE(wm8994_intercon));
|
||||
snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
|
||||
|
@ -79,6 +79,7 @@ struct wm8994_priv {
|
||||
int sysclk_rate[2];
|
||||
int mclk[2];
|
||||
int aifclk[2];
|
||||
int aifdiv[2];
|
||||
int channels[2];
|
||||
struct wm8994_fll_config fll[2], fll_suspend[2];
|
||||
struct completion fll_locked[2];
|
||||
@ -146,8 +147,6 @@ struct wm8994_priv {
|
||||
wm1811_mic_id_cb mic_id_cb;
|
||||
void *mic_id_cb_data;
|
||||
|
||||
int revision;
|
||||
|
||||
unsigned int aif1clk_enable:1;
|
||||
unsigned int aif2clk_enable:1;
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include <linux/mfd/arizona/registers.h>
|
||||
|
||||
#include "arizona.h"
|
||||
#include "wm_adsp.h"
|
||||
|
||||
#define adsp_crit(_dsp, fmt, ...) \
|
||||
@ -193,17 +194,25 @@ static void wm_adsp_buf_free(struct list_head *list)
|
||||
|
||||
#define WM_ADSP_NUM_FW 4
|
||||
|
||||
#define WM_ADSP_FW_MBC_VSS 0
|
||||
#define WM_ADSP_FW_TX 1
|
||||
#define WM_ADSP_FW_TX_SPK 2
|
||||
#define WM_ADSP_FW_RX_ANC 3
|
||||
|
||||
static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
|
||||
"MBC/VSS", "Tx", "Tx Speaker", "Rx ANC"
|
||||
[WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
|
||||
[WM_ADSP_FW_TX] = "Tx",
|
||||
[WM_ADSP_FW_TX_SPK] = "Tx Speaker",
|
||||
[WM_ADSP_FW_RX_ANC] = "Rx ANC",
|
||||
};
|
||||
|
||||
static struct {
|
||||
const char *file;
|
||||
} wm_adsp_fw[WM_ADSP_NUM_FW] = {
|
||||
{ .file = "mbc-vss" },
|
||||
{ .file = "tx" },
|
||||
{ .file = "tx-spk" },
|
||||
{ .file = "rx-anc" },
|
||||
[WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
|
||||
[WM_ADSP_FW_TX] = { .file = "tx" },
|
||||
[WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" },
|
||||
[WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" },
|
||||
};
|
||||
|
||||
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
|
||||
@ -246,17 +255,52 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
|
||||
SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
|
||||
};
|
||||
|
||||
const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
|
||||
const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
|
||||
SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
|
||||
static const struct soc_enum wm_adsp2_rate_enum[] = {
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
|
||||
ARIZONA_DSP1_RATE_SHIFT, 0xf,
|
||||
ARIZONA_RATE_ENUM_SIZE,
|
||||
arizona_rate_text, arizona_rate_val),
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
|
||||
ARIZONA_DSP1_RATE_SHIFT, 0xf,
|
||||
ARIZONA_RATE_ENUM_SIZE,
|
||||
arizona_rate_text, arizona_rate_val),
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
|
||||
ARIZONA_DSP1_RATE_SHIFT, 0xf,
|
||||
ARIZONA_RATE_ENUM_SIZE,
|
||||
arizona_rate_text, arizona_rate_val),
|
||||
SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
|
||||
ARIZONA_DSP1_RATE_SHIFT, 0xf,
|
||||
ARIZONA_RATE_ENUM_SIZE,
|
||||
arizona_rate_text, arizona_rate_val),
|
||||
};
|
||||
|
||||
const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
|
||||
SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
|
||||
SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
|
||||
SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
|
||||
SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
|
||||
wm_adsp_fw_get, wm_adsp_fw_put),
|
||||
SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
|
||||
EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
|
||||
#endif
|
||||
|
||||
static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
|
||||
int type)
|
||||
@ -549,13 +593,30 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
|
||||
buf_size = sizeof(adsp1_id);
|
||||
|
||||
algs = be32_to_cpu(adsp1_id.algs);
|
||||
dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
|
||||
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
|
||||
be32_to_cpu(adsp1_id.fw.id),
|
||||
dsp->fw_id,
|
||||
(be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
|
||||
(be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
|
||||
be32_to_cpu(adsp1_id.fw.ver) & 0xff,
|
||||
algs);
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP1_ZM;
|
||||
region->alg = be32_to_cpu(adsp1_id.fw.id);
|
||||
region->base = be32_to_cpu(adsp1_id.zm);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP1_DM;
|
||||
region->alg = be32_to_cpu(adsp1_id.fw.id);
|
||||
region->base = be32_to_cpu(adsp1_id.dm);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
|
||||
pos = sizeof(adsp1_id) / 2;
|
||||
term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
|
||||
break;
|
||||
@ -573,13 +634,38 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
|
||||
buf_size = sizeof(adsp2_id);
|
||||
|
||||
algs = be32_to_cpu(adsp2_id.algs);
|
||||
dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
|
||||
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
|
||||
be32_to_cpu(adsp2_id.fw.id),
|
||||
dsp->fw_id,
|
||||
(be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
|
||||
(be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
|
||||
be32_to_cpu(adsp2_id.fw.ver) & 0xff,
|
||||
algs);
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP2_XM;
|
||||
region->alg = be32_to_cpu(adsp2_id.fw.id);
|
||||
region->base = be32_to_cpu(adsp2_id.xm);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP2_YM;
|
||||
region->alg = be32_to_cpu(adsp2_id.fw.id);
|
||||
region->base = be32_to_cpu(adsp2_id.ym);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
|
||||
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
region->type = WMFW_ADSP2_ZM;
|
||||
region->alg = be32_to_cpu(adsp2_id.fw.id);
|
||||
region->base = be32_to_cpu(adsp2_id.zm);
|
||||
list_add_tail(®ion->list, &dsp->alg_regions);
|
||||
|
||||
pos = sizeof(adsp2_id) / 2;
|
||||
term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
|
||||
break;
|
||||
@ -781,8 +867,24 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
|
||||
case (WMFW_INFO_TEXT << 8):
|
||||
break;
|
||||
case (WMFW_ABSOLUTE << 8):
|
||||
region_name = "register";
|
||||
reg = offset;
|
||||
/*
|
||||
* Old files may use this for global
|
||||
* coefficients.
|
||||
*/
|
||||
if (le32_to_cpu(blk->id) == dsp->fw_id &&
|
||||
offset == 0) {
|
||||
region_name = "global coefficients";
|
||||
mem = wm_adsp_find_region(dsp, type);
|
||||
if (!mem) {
|
||||
adsp_err(dsp, "No ZM\n");
|
||||
break;
|
||||
}
|
||||
reg = wm_adsp_region_to_reg(mem, 0);
|
||||
|
||||
} else {
|
||||
region_name = "register";
|
||||
reg = offset;
|
||||
}
|
||||
break;
|
||||
|
||||
case WMFW_ADSP1_DM:
|
||||
|
@ -46,6 +46,8 @@ struct wm_adsp {
|
||||
|
||||
struct list_head alg_regions;
|
||||
|
||||
int fw_id;
|
||||
|
||||
const struct wm_adsp_region *mem;
|
||||
int num_mems;
|
||||
|
||||
@ -65,7 +67,8 @@ struct wm_adsp {
|
||||
.shift = num, .event = wm_adsp2_event, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
|
||||
|
||||
extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
|
||||
extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
|
||||
extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
|
||||
|
||||
int wm_adsp1_init(struct wm_adsp *adsp);
|
||||
int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
|
||||
|
@ -199,11 +199,12 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
|
||||
list_add_tail(&cache->list, &hubs->dcs_cache);
|
||||
}
|
||||
|
||||
static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
|
||||
static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
|
||||
u16 *reg_l, u16 *reg_r)
|
||||
{
|
||||
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
|
||||
u16 dcs_reg, reg;
|
||||
int ret = 0;
|
||||
|
||||
switch (hubs->dcs_readback_mode) {
|
||||
case 2:
|
||||
@ -236,8 +237,9 @@ static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Unknown DCS readback method\n");
|
||||
return;
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -286,7 +288,8 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
|
||||
WM8993_DCS_TRIG_STARTUP_1);
|
||||
}
|
||||
|
||||
wm_hubs_read_dc_servo(codec, ®_l, ®_r);
|
||||
if (wm_hubs_read_dc_servo(codec, ®_l, ®_r) < 0)
|
||||
return;
|
||||
|
||||
dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
|
||||
|
||||
|
@ -645,6 +645,10 @@ static struct snd_soc_dai_driver davinci_i2s_dai = {
|
||||
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver davinci_i2s_component = {
|
||||
.name = "davinci-i2s",
|
||||
};
|
||||
|
||||
static int davinci_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_platform_data *pdata = pdev->dev.platform_data;
|
||||
@ -727,20 +731,21 @@ static int davinci_i2s_probe(struct platform_device *pdev)
|
||||
|
||||
dev_set_drvdata(&pdev->dev, dev);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
|
||||
&davinci_i2s_dai, 1);
|
||||
if (ret != 0)
|
||||
goto err_release_clk;
|
||||
|
||||
ret = davinci_soc_platform_register(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
|
||||
goto err_unregister_dai;
|
||||
goto err_unregister_component;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_dai:
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
err_unregister_component:
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
err_release_clk:
|
||||
clk_disable(dev->clk);
|
||||
clk_put(dev->clk);
|
||||
@ -751,7 +756,7 @@ static int davinci_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
davinci_soc_platform_unregister(&pdev->dev);
|
||||
|
||||
clk_disable(dev->clk);
|
||||
|
@ -235,6 +235,8 @@
|
||||
#define DISMOD (val)(val<<2)
|
||||
#define TXSTATE BIT(4)
|
||||
#define RXSTATE BIT(5)
|
||||
#define SRMOD_MASK 3
|
||||
#define SRMOD_INACTIVE 0
|
||||
|
||||
/*
|
||||
* DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
|
||||
@ -634,35 +636,43 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
|
||||
* callback, take it into account here. That allows us to for example
|
||||
* send 32 bits per channel to the codec, while only 16 of them carry
|
||||
* audio payload.
|
||||
* The clock ratio is given for a full period of data (both left and
|
||||
* right channels), so it has to be divided by 2.
|
||||
* The clock ratio is given for a full period of data (for I2S format
|
||||
* both left and right channels), so it has to be divided by number of
|
||||
* tdm-slots (for I2S - divided by 2).
|
||||
*/
|
||||
if (dev->bclk_lrclk_ratio)
|
||||
word_length = dev->bclk_lrclk_ratio / 2;
|
||||
word_length = dev->bclk_lrclk_ratio / dev->tdm_slots;
|
||||
|
||||
/* mapping of the XSSZ bit-field as described in the datasheet */
|
||||
fmt = (word_length >> 1) - 1;
|
||||
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
|
||||
RXSSZ(fmt), RXSSZ(0x0F));
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
|
||||
TXSSZ(fmt), TXSSZ(0x0F));
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate),
|
||||
TXROT(7));
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate),
|
||||
RXROT(7));
|
||||
if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) {
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
|
||||
RXSSZ(fmt), RXSSZ(0x0F));
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
|
||||
TXSSZ(fmt), TXSSZ(0x0F));
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
|
||||
TXROT(rotate), TXROT(7));
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
|
||||
RXROT(rotate), RXROT(7));
|
||||
mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG,
|
||||
mask);
|
||||
}
|
||||
|
||||
mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask);
|
||||
mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
|
||||
static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
|
||||
int channels)
|
||||
{
|
||||
int i;
|
||||
u8 tx_ser = 0;
|
||||
u8 rx_ser = 0;
|
||||
|
||||
u8 ser;
|
||||
u8 slots = dev->tdm_slots;
|
||||
u8 max_active_serializers = (channels + slots - 1) / slots;
|
||||
/* Default configuration */
|
||||
mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
|
||||
|
||||
@ -682,17 +692,33 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
|
||||
for (i = 0; i < dev->num_serializer; i++) {
|
||||
mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
|
||||
dev->serial_dir[i]);
|
||||
if (dev->serial_dir[i] == TX_MODE) {
|
||||
if (dev->serial_dir[i] == TX_MODE &&
|
||||
tx_ser < max_active_serializers) {
|
||||
mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
|
||||
AXR(i));
|
||||
tx_ser++;
|
||||
} else if (dev->serial_dir[i] == RX_MODE) {
|
||||
} else if (dev->serial_dir[i] == RX_MODE &&
|
||||
rx_ser < max_active_serializers) {
|
||||
mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
|
||||
AXR(i));
|
||||
rx_ser++;
|
||||
} else {
|
||||
mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
|
||||
SRMOD_INACTIVE, SRMOD_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
ser = tx_ser;
|
||||
else
|
||||
ser = rx_ser;
|
||||
|
||||
if (ser < max_active_serializers) {
|
||||
dev_warn(dev->dev, "stream has more channels (%d) than are "
|
||||
"enabled in mcasp (%d)\n", channels, ser * slots);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
if (dev->txnumevt * tx_ser > 64)
|
||||
dev->txnumevt = 1;
|
||||
@ -729,6 +755,8 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
|
||||
((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
|
||||
@ -772,12 +800,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
|
||||
/* S/PDIF */
|
||||
static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
|
||||
{
|
||||
/* Set the PDIR for Serialiser as output */
|
||||
mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX);
|
||||
|
||||
/* TXMASK for 24 bits */
|
||||
mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF);
|
||||
|
||||
/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
|
||||
and LSB first */
|
||||
mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
|
||||
@ -812,12 +834,21 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
|
||||
&dev->dma_params[substream->stream];
|
||||
int word_length;
|
||||
u8 fifo_level;
|
||||
u8 slots = dev->tdm_slots;
|
||||
u8 active_serializers;
|
||||
int channels;
|
||||
struct snd_interval *pcm_channels = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||
channels = pcm_channels->min;
|
||||
|
||||
davinci_hw_common_param(dev, substream->stream);
|
||||
active_serializers = (channels + slots - 1) / slots;
|
||||
|
||||
if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL)
|
||||
return -EINVAL;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
fifo_level = dev->txnumevt;
|
||||
fifo_level = dev->txnumevt * active_serializers;
|
||||
else
|
||||
fifo_level = dev->rxnumevt;
|
||||
fifo_level = dev->rxnumevt * active_serializers;
|
||||
|
||||
if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
|
||||
davinci_hw_dit_param(dev);
|
||||
@ -936,13 +967,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
|
||||
.name = "davinci-mcasp.0",
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.channels_max = 32 * 16,
|
||||
.rates = DAVINCI_MCASP_RATES,
|
||||
.formats = DAVINCI_MCASP_PCM_FMTS,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.channels_max = 32 * 16,
|
||||
.rates = DAVINCI_MCASP_RATES,
|
||||
.formats = DAVINCI_MCASP_PCM_FMTS,
|
||||
},
|
||||
@ -962,6 +993,10 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
|
||||
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver davinci_mcasp_component = {
|
||||
.name = "davinci-mcasp",
|
||||
};
|
||||
|
||||
static const struct of_device_id mcasp_dt_ids[] = {
|
||||
{
|
||||
.compatible = "ti,dm646x-mcasp-audio",
|
||||
@ -1015,8 +1050,16 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
|
||||
pdata->op_mode = val;
|
||||
|
||||
ret = of_property_read_u32(np, "tdm-slots", &val);
|
||||
if (ret >= 0)
|
||||
if (ret >= 0) {
|
||||
if (val < 2 || val > 32) {
|
||||
dev_err(&pdev->dev,
|
||||
"tdm-slots must be in rage [2-32]\n");
|
||||
ret = -EINVAL;
|
||||
goto nodata;
|
||||
}
|
||||
|
||||
pdata->tdm_slots = val;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-serializer", &val);
|
||||
if (ret >= 0)
|
||||
@ -1170,7 +1213,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
|
||||
dma_data->channel = res->start;
|
||||
dev_set_drvdata(&pdev->dev, dev);
|
||||
ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
|
||||
ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
|
||||
&davinci_mcasp_dai[pdata->op_mode], 1);
|
||||
|
||||
if (ret != 0)
|
||||
goto err_release_clk;
|
||||
@ -1178,13 +1222,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
ret = davinci_soc_platform_register(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
|
||||
goto err_unregister_dai;
|
||||
goto err_unregister_component;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_dai:
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
err_unregister_component:
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
err_release_clk:
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
@ -1194,7 +1238,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
static int davinci_mcasp_remove(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
davinci_soc_platform_unregister(&pdev->dev);
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
@ -38,7 +38,7 @@ struct davinci_audio_dev {
|
||||
u8 num_serializer;
|
||||
u8 *serial_dir;
|
||||
u8 version;
|
||||
u8 bclk_lrclk_ratio;
|
||||
u16 bclk_lrclk_ratio;
|
||||
|
||||
/* McASP FIFO related */
|
||||
u8 txnumevt;
|
||||
|
@ -200,7 +200,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
|
||||
src = dma_pos;
|
||||
dst = prtd->params->dma_addr;
|
||||
src_bidx = data_type;
|
||||
dst_bidx = 0;
|
||||
dst_bidx = 4;
|
||||
src_cidx = data_type * fifo_level;
|
||||
dst_cidx = 0;
|
||||
} else {
|
||||
@ -223,9 +223,10 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
|
||||
edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0,
|
||||
ASYNC);
|
||||
else
|
||||
edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
|
||||
count, fifo_level,
|
||||
ABSYNC);
|
||||
edma_set_transfer_params(prtd->asp_link[0], acnt,
|
||||
fifo_level,
|
||||
count, fifo_level,
|
||||
ABSYNC);
|
||||
}
|
||||
|
||||
static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
|
||||
|
@ -204,6 +204,10 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
|
||||
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver davinci_vcif_component = {
|
||||
.name = "davinci-vcif",
|
||||
};
|
||||
|
||||
static int davinci_vcif_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = pdev->dev.platform_data;
|
||||
@ -234,7 +238,8 @@ static int davinci_vcif_probe(struct platform_device *pdev)
|
||||
|
||||
dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &davinci_vcif_component,
|
||||
&davinci_vcif_dai, 1);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "could not register dai\n");
|
||||
return ret;
|
||||
@ -243,7 +248,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
|
||||
ret = davinci_soc_platform_register(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -252,7 +257,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
|
||||
|
||||
static int davinci_vcif_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
davinci_soc_platform_unregister(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
@ -297,6 +297,10 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = {
|
||||
.trigger = dw_i2s_trigger,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver dw_i2s_component = {
|
||||
.name = "dw-i2s",
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int dw_i2s_suspend(struct snd_soc_dai *dai)
|
||||
@ -413,7 +417,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
|
||||
|
||||
dev->dev = &pdev->dev;
|
||||
dev_set_drvdata(&pdev->dev, dev);
|
||||
ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
|
||||
dw_i2s_dai, 1);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "not able to register dai\n");
|
||||
goto err_set_drvdata;
|
||||
@ -434,7 +439,7 @@ static int dw_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
|
||||
clk_put(dev->clk);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "fsl_ssi.h"
|
||||
#include "imx-pcm.h"
|
||||
@ -122,8 +123,10 @@ struct fsl_ssi_private {
|
||||
bool ssi_on_imx;
|
||||
struct clk *clk;
|
||||
struct platform_device *imx_pcm_pdev;
|
||||
struct imx_pcm_dma_params dma_params_tx;
|
||||
struct imx_pcm_dma_params dma_params_rx;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_rx;
|
||||
struct imx_dma_data filter_data_tx;
|
||||
struct imx_dma_data filter_data_rx;
|
||||
|
||||
struct {
|
||||
unsigned int rfrc;
|
||||
@ -574,6 +577,10 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = {
|
||||
.ops = &fsl_ssi_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver fsl_ssi_component = {
|
||||
.name = "fsl-ssi",
|
||||
};
|
||||
|
||||
/* Show the statistics of a flag only if its interrupt is enabled. The
|
||||
* compiler will optimze this code to a no-op if the interrupt is not
|
||||
* enabled.
|
||||
@ -649,6 +656,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||
const uint32_t *iprop;
|
||||
struct resource res;
|
||||
char name[64];
|
||||
bool shared;
|
||||
|
||||
/* SSIs that are not connected on the board should have a
|
||||
* status = "disabled"
|
||||
@ -737,14 +745,18 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||
* We have burstsize be "fifo_depth - 2" to match the SSI
|
||||
* watermark setting in fsl_ssi_startup().
|
||||
*/
|
||||
ssi_private->dma_params_tx.burstsize =
|
||||
ssi_private->dma_params_tx.maxburst =
|
||||
ssi_private->fifo_depth - 2;
|
||||
ssi_private->dma_params_rx.burstsize =
|
||||
ssi_private->dma_params_rx.maxburst =
|
||||
ssi_private->fifo_depth - 2;
|
||||
ssi_private->dma_params_tx.dma_addr =
|
||||
ssi_private->dma_params_tx.addr =
|
||||
ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
|
||||
ssi_private->dma_params_rx.dma_addr =
|
||||
ssi_private->dma_params_rx.addr =
|
||||
ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
|
||||
ssi_private->dma_params_tx.filter_data =
|
||||
&ssi_private->filter_data_tx;
|
||||
ssi_private->dma_params_rx.filter_data =
|
||||
&ssi_private->filter_data_rx;
|
||||
/*
|
||||
* TODO: This is a temporary solution and should be changed
|
||||
* to use generic DMA binding later when the helplers get in.
|
||||
@ -755,14 +767,14 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "could not get dma events\n");
|
||||
goto error_clk;
|
||||
}
|
||||
ssi_private->dma_params_tx.dma = dma_events[0];
|
||||
ssi_private->dma_params_rx.dma = dma_events[1];
|
||||
|
||||
ssi_private->dma_params_tx.shared_peripheral =
|
||||
of_device_is_compatible(of_get_parent(np),
|
||||
"fsl,spba-bus");
|
||||
ssi_private->dma_params_rx.shared_peripheral =
|
||||
ssi_private->dma_params_tx.shared_peripheral;
|
||||
shared = of_device_is_compatible(of_get_parent(np),
|
||||
"fsl,spba-bus");
|
||||
|
||||
imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
|
||||
dma_events[0], shared);
|
||||
imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
|
||||
dma_events[1], shared);
|
||||
}
|
||||
|
||||
/* Initialize the the device_attribute structure */
|
||||
@ -782,7 +794,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||
/* Register with ASoC */
|
||||
dev_set_drvdata(&pdev->dev, ssi_private);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
|
||||
ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
|
||||
&ssi_private->cpu_dai_drv, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
|
||||
goto error_dev;
|
||||
@ -835,7 +848,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||
error_dai:
|
||||
if (ssi_private->ssi_on_imx)
|
||||
platform_device_unregister(ssi_private->imx_pcm_pdev);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
error_dev:
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
@ -873,7 +886,7 @@ static int fsl_ssi_remove(struct platform_device *pdev)
|
||||
clk_disable_unprepare(ssi_private->clk);
|
||||
clk_put(ssi_private->clk);
|
||||
}
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
device_remove_file(&pdev->dev, &ssi_private->dev_attr);
|
||||
|
||||
free_irq(ssi_private->irq, ssi_private);
|
||||
|
@ -262,7 +262,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(pinctrl);
|
||||
}
|
||||
|
||||
audmux_clk = clk_get(&pdev->dev, "audmux");
|
||||
audmux_clk = devm_clk_get(&pdev->dev, "audmux");
|
||||
if (IS_ERR(audmux_clk)) {
|
||||
dev_dbg(&pdev->dev, "cannot get clock: %ld\n",
|
||||
PTR_ERR(audmux_clk));
|
||||
@ -282,7 +282,6 @@ static int imx_audmux_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (audmux_type == IMX31_AUDMUX)
|
||||
audmux_debugfs_remove();
|
||||
clk_put(audmux_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,16 +30,16 @@
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include <linux/platform_data/dma-imx.h>
|
||||
|
||||
#include "imx-pcm.h"
|
||||
|
||||
static bool filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct snd_dmaengine_dai_dma_data *dma_data = param;
|
||||
|
||||
if (!imx_dma_is_general_purpose(chan))
|
||||
return false;
|
||||
|
||||
chan->private = param;
|
||||
chan->private = dma_data->filter_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -49,25 +49,16 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
|
||||
struct imx_pcm_dma_params *dma_params;
|
||||
struct dma_slave_config slave_config;
|
||||
int ret;
|
||||
|
||||
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
slave_config.device_fc = false;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
slave_config.dst_addr = dma_params->dma_addr;
|
||||
slave_config.dst_maxburst = dma_params->burstsize;
|
||||
} else {
|
||||
slave_config.src_addr = dma_params->dma_addr;
|
||||
slave_config.src_maxburst = dma_params->burstsize;
|
||||
}
|
||||
snd_dmaengine_pcm_set_config_from_dai_data(substream,
|
||||
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
|
||||
&slave_config);
|
||||
|
||||
ret = dmaengine_slave_config(chan, &slave_config);
|
||||
if (ret)
|
||||
@ -100,47 +91,16 @@ static struct snd_pcm_hardware snd_imx_hardware = {
|
||||
static int snd_imx_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct imx_pcm_dma_params *dma_params;
|
||||
struct imx_dma_data *dma_data;
|
||||
int ret;
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
|
||||
|
||||
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
|
||||
if (!dma_data)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_data->peripheral_type = dma_params->shared_peripheral ?
|
||||
IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
|
||||
dma_data->priority = DMA_PRIO_HIGH;
|
||||
dma_data->dma_request = dma_params->dma;
|
||||
|
||||
ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
|
||||
if (ret) {
|
||||
kfree(dma_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_dmaengine_pcm_set_data(substream, dma_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_imx_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
|
||||
|
||||
snd_dmaengine_pcm_close(substream);
|
||||
kfree(dma_data);
|
||||
|
||||
return 0;
|
||||
return snd_dmaengine_pcm_open(substream, filter,
|
||||
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops imx_pcm_ops = {
|
||||
.open = snd_imx_open,
|
||||
.close = snd_imx_close,
|
||||
.close = snd_dmaengine_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_imx_pcm_hw_params,
|
||||
.trigger = snd_dmaengine_pcm_trigger,
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include "imx-ssi.h"
|
||||
|
||||
struct imx_pcm_runtime_data {
|
||||
int period;
|
||||
unsigned int period;
|
||||
int periods;
|
||||
unsigned long offset;
|
||||
unsigned long last_offset;
|
||||
@ -299,8 +299,8 @@ int imx_pcm_fiq_init(struct platform_device *pdev)
|
||||
|
||||
imx_ssi_fiq_base = (unsigned long)ssi->base;
|
||||
|
||||
ssi->dma_params_tx.burstsize = 4;
|
||||
ssi->dma_params_rx.burstsize = 6;
|
||||
ssi->dma_params_tx.maxburst = 4;
|
||||
ssi->dma_params_rx.maxburst = 6;
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
|
||||
if (ret)
|
||||
|
@ -13,17 +13,24 @@
|
||||
#ifndef _IMX_PCM_H
|
||||
#define _IMX_PCM_H
|
||||
|
||||
#include <linux/platform_data/dma-imx.h>
|
||||
|
||||
/*
|
||||
* Do not change this as the FIQ handler depends on this size
|
||||
*/
|
||||
#define IMX_SSI_DMABUF_SIZE (64 * 1024)
|
||||
|
||||
struct imx_pcm_dma_params {
|
||||
int dma;
|
||||
unsigned long dma_addr;
|
||||
int burstsize;
|
||||
bool shared_peripheral; /* The peripheral is on SPBA bus */
|
||||
};
|
||||
static inline void
|
||||
imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
|
||||
int dma, bool shared)
|
||||
{
|
||||
dma_data->dma_request = dma;
|
||||
dma_data->priority = DMA_PRIO_HIGH;
|
||||
if (shared)
|
||||
dma_data->peripheral_type = IMX_DMATYPE_SSI_SP;
|
||||
else
|
||||
dma_data->peripheral_type = IMX_DMATYPE_SSI;
|
||||
}
|
||||
|
||||
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma);
|
||||
|
@ -148,7 +148,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
|
||||
data->dai.stream_name = "HiFi";
|
||||
data->dai.codec_dai_name = "sgtl5000";
|
||||
data->dai.codec_of_node = codec_np;
|
||||
data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
|
||||
data->dai.cpu_of_node = ssi_np;
|
||||
data->dai.platform_name = "imx-pcm-audio";
|
||||
data->dai.init = &imx_sgtl5000_dai_init;
|
||||
data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
|
@ -236,7 +236,7 @@ static int imx_ssi_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct imx_pcm_dma_params *dma_data;
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
|
||||
/* Tx/Rx config */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
@ -369,8 +369,8 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
|
||||
|
||||
snd_soc_dai_set_drvdata(dai, ssi);
|
||||
|
||||
val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
|
||||
SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
|
||||
val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
|
||||
SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
|
||||
writel(val, ssi->base + SSI_SFCSR);
|
||||
|
||||
return 0;
|
||||
@ -400,7 +400,7 @@ static struct snd_soc_dai_driver imx_ac97_dai = {
|
||||
.stream_name = "AC97 Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
@ -413,6 +413,10 @@ static struct snd_soc_dai_driver imx_ac97_dai = {
|
||||
.ops = &imx_ssi_pcm_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver imx_component = {
|
||||
.name = DRV_NAME,
|
||||
};
|
||||
|
||||
static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
|
||||
{
|
||||
void __iomem *base = imx_ssi->base;
|
||||
@ -575,23 +579,31 @@ static int imx_ssi_probe(struct platform_device *pdev)
|
||||
|
||||
writel(0x0, ssi->base + SSI_SIER);
|
||||
|
||||
ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
|
||||
ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
|
||||
ssi->dma_params_rx.addr = res->start + SSI_SRX0;
|
||||
ssi->dma_params_tx.addr = res->start + SSI_STX0;
|
||||
|
||||
ssi->dma_params_tx.burstsize = 6;
|
||||
ssi->dma_params_rx.burstsize = 4;
|
||||
ssi->dma_params_tx.maxburst = 6;
|
||||
ssi->dma_params_rx.maxburst = 4;
|
||||
|
||||
ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
|
||||
ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
|
||||
if (res)
|
||||
ssi->dma_params_tx.dma = res->start;
|
||||
if (res) {
|
||||
imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
|
||||
false);
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
|
||||
if (res)
|
||||
ssi->dma_params_rx.dma = res->start;
|
||||
if (res) {
|
||||
imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
|
||||
false);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ssi);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &imx_component,
|
||||
dai, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register DAI failed\n");
|
||||
goto failed_register;
|
||||
@ -632,7 +644,7 @@ static int imx_ssi_probe(struct platform_device *pdev)
|
||||
failed_pdev_fiq_add:
|
||||
platform_device_put(ssi->soc_platform_pdev_fiq);
|
||||
failed_pdev_fiq_alloc:
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
failed_register:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
failed_get_resource:
|
||||
@ -650,7 +662,7 @@ static int imx_ssi_remove(struct platform_device *pdev)
|
||||
platform_device_unregister(ssi->soc_platform_pdev);
|
||||
platform_device_unregister(ssi->soc_platform_pdev_fiq);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
if (ssi->flags & IMX_SSI_USE_AC97)
|
||||
ac97_ssi = NULL;
|
||||
|
@ -187,6 +187,7 @@
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/platform_data/dma-imx.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include "imx-pcm.h"
|
||||
|
||||
struct imx_ssi {
|
||||
@ -204,8 +205,10 @@ struct imx_ssi {
|
||||
void (*ac97_reset) (struct snd_ac97 *ac97);
|
||||
void (*ac97_warm_reset)(struct snd_ac97 *ac97);
|
||||
|
||||
struct imx_pcm_dma_params dma_params_rx;
|
||||
struct imx_pcm_dma_params dma_params_tx;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_rx;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||
struct imx_dma_data filter_data_tx;
|
||||
struct imx_dma_data filter_data_rx;
|
||||
|
||||
int enabled;
|
||||
|
||||
|
@ -270,6 +270,9 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {
|
||||
.ops = &psc_ac97_digital_ops,
|
||||
} };
|
||||
|
||||
static const struct snd_soc_component_driver psc_ac97_component = {
|
||||
.name = DRV_NAME,
|
||||
};
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
@ -287,7 +290,8 @@ static int psc_ac97_of_probe(struct platform_device *op)
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
|
||||
rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
|
||||
psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
|
||||
if (rc != 0) {
|
||||
dev_err(&op->dev, "Failed to register DAI\n");
|
||||
return rc;
|
||||
@ -313,7 +317,7 @@ static int psc_ac97_of_probe(struct platform_device *op)
|
||||
static int psc_ac97_of_remove(struct platform_device *op)
|
||||
{
|
||||
mpc5200_audio_dma_destroy(op);
|
||||
snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
|
||||
snd_soc_unregister_component(&op->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -148,6 +148,10 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{
|
||||
.ops = &psc_i2s_dai_ops,
|
||||
} };
|
||||
|
||||
static const struct snd_soc_component_driver psc_i2s_component = {
|
||||
.name = "mpc5200-i2s",
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* OF platform bus binding code:
|
||||
* - Probe/remove operations
|
||||
@ -163,7 +167,8 @@ static int psc_i2s_of_probe(struct platform_device *op)
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
|
||||
rc = snd_soc_register_component(&op->dev, &psc_i2s_component,
|
||||
psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
|
||||
if (rc != 0) {
|
||||
pr_err("Failed to register DAI\n");
|
||||
return rc;
|
||||
@ -208,7 +213,7 @@ static int psc_i2s_of_probe(struct platform_device *op)
|
||||
static int psc_i2s_of_remove(struct platform_device *op)
|
||||
{
|
||||
mpc5200_audio_dma_destroy(op);
|
||||
snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
|
||||
snd_soc_unregister_component(&op->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -425,6 +425,10 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
|
||||
.resume = jz4740_i2s_resume,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver jz4740_i2s_component = {
|
||||
.name = "jz4740-i2s",
|
||||
};
|
||||
|
||||
static int jz4740_i2s_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct jz4740_i2s *i2s;
|
||||
@ -469,7 +473,8 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, i2s);
|
||||
ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &jz4740_i2s_component,
|
||||
&jz4740_i2s_dai, 1);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register DAI\n");
|
||||
@ -496,7 +501,7 @@ static int jz4740_i2s_dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
clk_put(i2s->clk_i2s);
|
||||
clk_put(i2s->clk_aic);
|
||||
|
@ -451,6 +451,10 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
|
||||
.ops = &kirkwood_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver kirkwood_i2s_component = {
|
||||
.name = DRV_NAME,
|
||||
};
|
||||
|
||||
static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
|
||||
@ -524,10 +528,11 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
||||
priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
|
||||
}
|
||||
|
||||
err = snd_soc_register_dai(&pdev->dev, soc_dai);
|
||||
err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
|
||||
soc_dai, 1);
|
||||
if (!err)
|
||||
return 0;
|
||||
dev_err(&pdev->dev, "snd_soc_register_dai failed\n");
|
||||
dev_err(&pdev->dev, "snd_soc_register_component failed\n");
|
||||
|
||||
if (!IS_ERR(priv->extclk)) {
|
||||
clk_disable_unprepare(priv->extclk);
|
||||
@ -542,7 +547,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
if (!IS_ERR(priv->extclk)) {
|
||||
clk_disable_unprepare(priv->extclk);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* sst_platform.c - Intel MID Platform driver
|
||||
*
|
||||
* Copyright (C) 2010-2012 Intel Corp
|
||||
* Copyright (C) 2010-2013 Intel Corp
|
||||
* Author: Vinod Koul <vinod.koul@intel.com>
|
||||
* Author: Harsha Priya <priya.harsha@intel.com>
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -165,6 +165,10 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver sst_component = {
|
||||
.name = "sst",
|
||||
};
|
||||
|
||||
/* helper functions */
|
||||
static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
|
||||
int state)
|
||||
@ -652,11 +656,21 @@ static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
|
||||
return stream->compr_ops->get_codec_caps(codec);
|
||||
}
|
||||
|
||||
static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
|
||||
struct snd_compr_metadata *metadata)
|
||||
{
|
||||
struct sst_runtime_stream *stream =
|
||||
cstream->runtime->private_data;
|
||||
|
||||
return stream->compr_ops->set_metadata(stream->id, metadata);
|
||||
}
|
||||
|
||||
static struct snd_compr_ops sst_platform_compr_ops = {
|
||||
|
||||
.open = sst_platform_compr_open,
|
||||
.free = sst_platform_compr_free,
|
||||
.set_params = sst_platform_compr_set_params,
|
||||
.set_metadata = sst_platform_compr_set_metadata,
|
||||
.trigger = sst_platform_compr_trigger,
|
||||
.pointer = sst_platform_compr_pointer,
|
||||
.ack = sst_platform_compr_ack,
|
||||
@ -683,7 +697,7 @@ static int sst_platform_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dais(&pdev->dev,
|
||||
ret = snd_soc_register_component(&pdev->dev, &sst_component,
|
||||
sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
|
||||
if (ret) {
|
||||
pr_err("registering cpu dais failed\n");
|
||||
@ -695,7 +709,7 @@ static int sst_platform_probe(struct platform_device *pdev)
|
||||
static int sst_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
pr_debug("sst_platform_remove success\n");
|
||||
return 0;
|
||||
|
@ -124,6 +124,8 @@ struct compress_sst_ops {
|
||||
int (*close) (unsigned int str_id);
|
||||
int (*get_caps) (struct snd_compr_caps *caps);
|
||||
int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
|
||||
int (*set_metadata) (unsigned int str_id,
|
||||
struct snd_compr_metadata *mdata);
|
||||
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/fsl/mxs-dma.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
@ -39,11 +38,6 @@
|
||||
|
||||
#include "mxs-pcm.h"
|
||||
|
||||
struct mxs_pcm_dma_data {
|
||||
struct mxs_dma_data dma_data;
|
||||
struct mxs_pcm_dma_params *dma_params;
|
||||
};
|
||||
|
||||
static struct snd_pcm_hardware snd_mxs_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
@ -66,8 +60,7 @@ static struct snd_pcm_hardware snd_mxs_hardware = {
|
||||
|
||||
static bool filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct mxs_pcm_dma_data *pcm_dma_data = param;
|
||||
struct mxs_pcm_dma_params *dma_params = pcm_dma_data->dma_params;
|
||||
struct mxs_pcm_dma_params *dma_params = param;
|
||||
|
||||
if (!mxs_dma_is_apbx(chan))
|
||||
return false;
|
||||
@ -75,7 +68,7 @@ static bool filter(struct dma_chan *chan, void *param)
|
||||
if (chan->chan_id != dma_params->chan_num)
|
||||
return false;
|
||||
|
||||
chan->private = &pcm_dma_data->dma_data;
|
||||
chan->private = &dma_params->dma_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -91,37 +84,11 @@ static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static int snd_mxs_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct mxs_pcm_dma_data *pcm_dma_data;
|
||||
int ret;
|
||||
|
||||
pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL);
|
||||
if (pcm_dma_data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
pcm_dma_data->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
pcm_dma_data->dma_data.chan_irq = pcm_dma_data->dma_params->chan_irq;
|
||||
|
||||
ret = snd_dmaengine_pcm_open(substream, filter, pcm_dma_data);
|
||||
if (ret) {
|
||||
kfree(pcm_dma_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
|
||||
|
||||
snd_dmaengine_pcm_set_data(substream, pcm_dma_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_mxs_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream);
|
||||
|
||||
snd_dmaengine_pcm_close(substream);
|
||||
kfree(pcm_dma_data);
|
||||
|
||||
return 0;
|
||||
return snd_dmaengine_pcm_open(substream, filter,
|
||||
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
|
||||
}
|
||||
|
||||
static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
@ -137,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
|
||||
static struct snd_pcm_ops mxs_pcm_ops = {
|
||||
.open = snd_mxs_open,
|
||||
.close = snd_mxs_close,
|
||||
.close = snd_dmaengine_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_mxs_pcm_hw_params,
|
||||
.trigger = snd_dmaengine_pcm_trigger,
|
||||
|
@ -19,8 +19,10 @@
|
||||
#ifndef _MXS_PCM_H
|
||||
#define _MXS_PCM_H
|
||||
|
||||
#include <linux/fsl/mxs-dma.h>
|
||||
|
||||
struct mxs_pcm_dma_params {
|
||||
int chan_irq;
|
||||
struct mxs_dma_data dma_data;
|
||||
int chan_num;
|
||||
};
|
||||
|
||||
|
@ -627,6 +627,10 @@ static struct snd_soc_dai_driver mxs_saif_dai = {
|
||||
.ops = &mxs_saif_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver mxs_saif_component = {
|
||||
.name = "mxs-saif",
|
||||
};
|
||||
|
||||
static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct mxs_saif *saif = dev_id;
|
||||
@ -753,9 +757,9 @@ static int mxs_saif_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
|
||||
if (saif->dma_param.chan_irq < 0) {
|
||||
ret = saif->dma_param.chan_irq;
|
||||
saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1);
|
||||
if (saif->dma_param.dma_data.chan_irq < 0) {
|
||||
ret = saif->dma_param.dma_data.chan_irq;
|
||||
dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
@ -763,7 +767,8 @@ static int mxs_saif_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, saif);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
|
||||
&mxs_saif_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register DAI failed\n");
|
||||
return ret;
|
||||
@ -778,7 +783,7 @@ static int mxs_saif_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
failed_pdev_alloc:
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -786,7 +791,7 @@ static int mxs_saif_probe(struct platform_device *pdev)
|
||||
static int mxs_saif_remove(struct platform_device *pdev)
|
||||
{
|
||||
mxs_pcm_platform_unregister(&pdev->dev);
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -314,6 +314,10 @@ static struct snd_soc_dai_driver nuc900_ac97_dai = {
|
||||
.ops = &nuc900_ac97_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver nuc900_ac97_component = {
|
||||
.name = "nuc900-ac97",
|
||||
};
|
||||
|
||||
static int nuc900_ac97_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
struct nuc900_audio *nuc900_audio;
|
||||
@ -361,7 +365,8 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
|
||||
|
||||
nuc900_ac97_data = nuc900_audio;
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
|
||||
&nuc900_ac97_dai, 1);
|
||||
if (ret)
|
||||
goto out3;
|
||||
|
||||
@ -384,7 +389,7 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
|
||||
|
||||
static int nuc900_ac97_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
clk_put(nuc900_ac97_data->clk);
|
||||
iounmap(nuc900_ac97_data->mmio);
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <linux/platform_data/asoc-ti-mcbsp.h>
|
||||
|
||||
#include "omap-mcbsp.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
#include "../codecs/tlv320aic23.h"
|
||||
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include <linux/platform_data/asoc-ti-mcbsp.h>
|
||||
|
||||
#include "omap-mcbsp.h"
|
||||
#include "omap-pcm.h"
|
||||
#include "../codecs/cx20442.h"
|
||||
|
||||
|
||||
|
@ -1018,9 +1018,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
/* RX DMA request number, and port address configuration */
|
||||
mcbsp->dma_data[1].name = "Audio Capture";
|
||||
mcbsp->dma_data[1].dma_req = res->start;
|
||||
mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
|
||||
mcbsp->dma_req[1] = res->start;
|
||||
mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
|
||||
mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
|
||||
mcbsp->dma_data[1].maxburst = 4;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
|
||||
if (!res) {
|
||||
@ -1028,9 +1029,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
/* TX DMA request number, and port address configuration */
|
||||
mcbsp->dma_data[0].name = "Audio Playback";
|
||||
mcbsp->dma_data[0].dma_req = res->start;
|
||||
mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
|
||||
mcbsp->dma_req[0] = res->start;
|
||||
mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
|
||||
mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
|
||||
mcbsp->dma_data[0].maxburst = 4;
|
||||
|
||||
mcbsp->fclk = clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(mcbsp->fclk)) {
|
||||
|
@ -24,14 +24,14 @@
|
||||
#ifndef __ASOC_MCBSP_H
|
||||
#define __ASOC_MCBSP_H
|
||||
|
||||
#include "omap-pcm.h"
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
#define mcbsp_omap1() 1
|
||||
#else
|
||||
#define mcbsp_omap1() 0
|
||||
#endif
|
||||
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
/* McBSP register numbers. Register address offset = num * reg_step */
|
||||
enum {
|
||||
/* Common registers */
|
||||
@ -312,7 +312,8 @@ struct omap_mcbsp {
|
||||
struct omap_mcbsp_platform_data *pdata;
|
||||
struct omap_mcbsp_st_data *st_data;
|
||||
struct omap_mcbsp_reg_cfg cfg_regs;
|
||||
struct omap_pcm_dma_data dma_data[2];
|
||||
struct snd_dmaengine_dai_dma_data dma_data[2];
|
||||
unsigned int dma_req[2];
|
||||
int dma_op_mode;
|
||||
u16 max_tx_thres;
|
||||
u16 max_rx_thres;
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <linux/platform_data/asoc-ti-mcbsp.h>
|
||||
|
||||
#include "omap-mcbsp.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
#define N810_HEADSET_AMP_GPIO 10
|
||||
#define N810_SPEAKER_AMP_GPIO 101
|
||||
|
@ -34,7 +34,6 @@
|
||||
|
||||
#include "omap-dmic.h"
|
||||
#include "omap-mcpdm.h"
|
||||
#include "omap-pcm.h"
|
||||
#include "../codecs/twl6040.h"
|
||||
|
||||
struct abe_twl6040 {
|
||||
|
@ -39,8 +39,8 @@
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "omap-pcm.h"
|
||||
#include "omap-dmic.h"
|
||||
|
||||
struct omap_dmic {
|
||||
@ -55,13 +55,9 @@ struct omap_dmic {
|
||||
u32 ch_enabled;
|
||||
bool active;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
/*
|
||||
* Stream DMA parameters
|
||||
*/
|
||||
static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
|
||||
.name = "DMIC capture",
|
||||
struct snd_dmaengine_dai_dma_data dma_data;
|
||||
unsigned int dma_req;
|
||||
};
|
||||
|
||||
static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
|
||||
@ -118,7 +114,7 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
|
||||
|
||||
mutex_unlock(&dmic->mutex);
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
|
||||
snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -203,7 +199,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
|
||||
struct omap_pcm_dma_data *dma_data;
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
int channels;
|
||||
|
||||
dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
|
||||
@ -230,7 +226,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
/* packet size is threshold * channels */
|
||||
dma_data = snd_soc_dai_get_dma_data(dai, substream);
|
||||
dma_data->packet_size = dmic->threshold * channels;
|
||||
dma_data->maxburst = dmic->threshold * channels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -448,6 +444,10 @@ static struct snd_soc_dai_driver omap_dmic_dai = {
|
||||
.ops = &omap_dmic_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver omap_dmic_component = {
|
||||
.name = "omap-dmic",
|
||||
};
|
||||
|
||||
static int asoc_dmic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dmic *dmic;
|
||||
@ -476,7 +476,7 @@ static int asoc_dmic_probe(struct platform_device *pdev)
|
||||
ret = -ENODEV;
|
||||
goto err_put_clk;
|
||||
}
|
||||
omap_dmic_dai_dma_params.port_addr = res->start + OMAP_DMIC_DATA_REG;
|
||||
dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!res) {
|
||||
@ -484,7 +484,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
|
||||
ret = -ENODEV;
|
||||
goto err_put_clk;
|
||||
}
|
||||
omap_dmic_dai_dma_params.dma_req = res->start;
|
||||
|
||||
dmic->dma_req = res->start;
|
||||
dmic->dma_data.filter_data = &dmic->dma_req;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
|
||||
if (!res) {
|
||||
@ -493,21 +495,12 @@ static int asoc_dmic_probe(struct platform_device *pdev)
|
||||
goto err_put_clk;
|
||||
}
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, res->start,
|
||||
resource_size(res), pdev->name)) {
|
||||
dev_err(dmic->dev, "memory region already claimed\n");
|
||||
ret = -ENODEV;
|
||||
goto err_put_clk;
|
||||
}
|
||||
dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(dmic->io_base))
|
||||
return PTR_ERR(dmic->io_base);
|
||||
|
||||
dmic->io_base = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!dmic->io_base) {
|
||||
ret = -ENOMEM;
|
||||
goto err_put_clk;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component,
|
||||
&omap_dmic_dai, 1);
|
||||
if (ret)
|
||||
goto err_put_clk;
|
||||
|
||||
@ -522,7 +515,7 @@ static int asoc_dmic_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dmic *dmic = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
clk_put(dmic->fclk);
|
||||
|
||||
return 0;
|
||||
|
@ -32,15 +32,16 @@
|
||||
#include <sound/soc.h>
|
||||
#include <sound/asound.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "omap-pcm.h"
|
||||
#include "omap-hdmi.h"
|
||||
|
||||
#define DRV_NAME "omap-hdmi-audio-dai"
|
||||
|
||||
struct hdmi_priv {
|
||||
struct omap_pcm_dma_data dma_params;
|
||||
struct snd_dmaengine_dai_dma_data dma_data;
|
||||
unsigned int dma_req;
|
||||
struct omap_dss_audio dss_audio;
|
||||
struct snd_aes_iec958 iec;
|
||||
struct snd_cea_861_aud_if cea;
|
||||
@ -68,7 +69,7 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, &priv->dma_params);
|
||||
snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -88,25 +89,20 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
struct snd_aes_iec958 *iec = &priv->iec;
|
||||
struct snd_cea_861_aud_if *cea = &priv->cea;
|
||||
struct omap_pcm_dma_data *dma_data;
|
||||
int err = 0;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(dai, substream);
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
dma_data->packet_size = 16;
|
||||
priv->dma_data.maxburst = 16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
dma_data->packet_size = 32;
|
||||
priv->dma_data.maxburst = 32;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "format not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dma_data->data_type = 32;
|
||||
|
||||
/*
|
||||
* fill the IEC-60958 channel status word
|
||||
*/
|
||||
@ -264,6 +260,10 @@ static struct snd_soc_dai_driver omap_hdmi_dai = {
|
||||
.ops = &omap_hdmi_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver omap_hdmi_component = {
|
||||
.name = DRV_NAME,
|
||||
};
|
||||
|
||||
static int omap_hdmi_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
@ -283,8 +283,7 @@ static int omap_hdmi_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdmi_data->dma_params.port_addr = hdmi_rsrc->start
|
||||
+ OMAP_HDMI_AUDIO_DMA_PORT;
|
||||
hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
|
||||
|
||||
hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!hdmi_rsrc) {
|
||||
@ -292,8 +291,9 @@ static int omap_hdmi_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdmi_data->dma_params.dma_req = hdmi_rsrc->start;
|
||||
hdmi_data->dma_params.name = "HDMI playback";
|
||||
hdmi_data->dma_req = hdmi_rsrc->start;
|
||||
hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
|
||||
hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
|
||||
/*
|
||||
* TODO: We assume that there is only one DSS HDMI device. Future
|
||||
@ -321,7 +321,8 @@ static int omap_hdmi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, hdmi_data);
|
||||
ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
|
||||
ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
|
||||
&omap_hdmi_dai, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -330,7 +331,7 @@ static int omap_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
if (hdmi_data == NULL) {
|
||||
dev_err(&pdev->dev, "cannot obtain HDMi data\n");
|
||||
|
@ -33,11 +33,11 @@
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_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)
|
||||
|
||||
@ -62,24 +62,22 @@ enum {
|
||||
* Stream DMA parameters. DMA request line and port address are set runtime
|
||||
* since they are different between OMAP1 and later OMAPs
|
||||
*/
|
||||
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
|
||||
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
|
||||
unsigned int packet_size)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct omap_pcm_dma_data *dma_data;
|
||||
int words;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
/*
|
||||
* Configure McBSP threshold based on either:
|
||||
* packet_size, when the sDMA is in packet mode, or based on the
|
||||
* period size in THRESHOLD mode, otherwise use McBSP threshold = 1
|
||||
* for mono streams.
|
||||
*/
|
||||
if (dma_data->packet_size)
|
||||
words = dma_data->packet_size;
|
||||
if (packet_size)
|
||||
words = packet_size;
|
||||
else
|
||||
words = 1;
|
||||
|
||||
@ -226,7 +224,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
|
||||
struct omap_pcm_dma_data *dma_data;
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
int wlen, channels, wpf;
|
||||
int pkt_size = 0;
|
||||
unsigned int format, div, framesize, master;
|
||||
@ -245,7 +243,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
if (mcbsp->pdata->buffer_size) {
|
||||
dma_data->set_threshold = omap_mcbsp_set_threshold;
|
||||
if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
|
||||
int period_words, max_thrsh;
|
||||
int divider = 0;
|
||||
@ -276,9 +273,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
/* Use packet mode for non mono streams */
|
||||
pkt_size = channels;
|
||||
}
|
||||
omap_mcbsp_set_threshold(substream, pkt_size);
|
||||
}
|
||||
|
||||
dma_data->packet_size = pkt_size;
|
||||
dma_data->maxburst = pkt_size;
|
||||
|
||||
if (mcbsp->configured) {
|
||||
/* McBSP already configured by another stream */
|
||||
@ -586,6 +584,10 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = {
|
||||
.ops = &mcbsp_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver omap_mcbsp_component = {
|
||||
.name = "omap-mcbsp",
|
||||
};
|
||||
|
||||
static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
@ -793,7 +795,8 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
|
||||
|
||||
ret = omap_mcbsp_init(pdev);
|
||||
if (!ret)
|
||||
return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
|
||||
return snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
|
||||
&omap_mcbsp_dai, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -802,7 +805,7 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
|
||||
mcbsp->pdata->ops->free(mcbsp->id);
|
||||
|
@ -39,11 +39,14 @@
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "omap-mcpdm.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
#define OMAP44XX_MCPDM_L3_BASE 0x49032000
|
||||
struct mcpdm_link_config {
|
||||
u32 link_mask; /* channel mask for the direction */
|
||||
u32 threshold; /* FIFO threshold */
|
||||
};
|
||||
|
||||
struct omap_mcpdm {
|
||||
struct device *dev;
|
||||
@ -53,29 +56,22 @@ struct omap_mcpdm {
|
||||
|
||||
struct mutex mutex;
|
||||
|
||||
/* channel data */
|
||||
u32 dn_channels;
|
||||
u32 up_channels;
|
||||
|
||||
/* McPDM FIFO thresholds */
|
||||
u32 dn_threshold;
|
||||
u32 up_threshold;
|
||||
/* Playback/Capture configuration */
|
||||
struct mcpdm_link_config config[2];
|
||||
|
||||
/* McPDM dn offsets for rx1, and 2 channels */
|
||||
u32 dn_rx_offset;
|
||||
|
||||
/* McPDM needs to be restarted due to runtime reconfiguration */
|
||||
bool restart;
|
||||
|
||||
struct snd_dmaengine_dai_dma_data dma_data[2];
|
||||
unsigned int dma_req[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* Stream DMA parameters
|
||||
*/
|
||||
static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
|
||||
{
|
||||
.name = "Audio playback",
|
||||
},
|
||||
{
|
||||
.name = "Audio capture",
|
||||
},
|
||||
};
|
||||
|
||||
static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
|
||||
{
|
||||
@ -130,11 +126,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
|
||||
static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
|
||||
{
|
||||
u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
|
||||
u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
|
||||
|
||||
ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
|
||||
|
||||
ctrl |= mcpdm->dn_channels | mcpdm->up_channels;
|
||||
ctrl |= link_mask;
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
|
||||
|
||||
ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
|
||||
@ -148,11 +145,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
|
||||
static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
|
||||
{
|
||||
u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
|
||||
u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
|
||||
|
||||
ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
|
||||
|
||||
ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels);
|
||||
ctrl &= ~(link_mask);
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
|
||||
|
||||
ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
|
||||
@ -188,8 +186,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
|
||||
}
|
||||
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold);
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold);
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
|
||||
mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
|
||||
mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
|
||||
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
|
||||
MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
|
||||
@ -267,7 +267,7 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
|
||||
mutex_unlock(&mcpdm->mutex);
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream,
|
||||
&omap_mcpdm_dai_dma_params[substream->stream]);
|
||||
&mcpdm->dma_data[substream->stream]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -283,6 +283,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
if (omap_mcpdm_active(mcpdm)) {
|
||||
omap_mcpdm_stop(mcpdm);
|
||||
omap_mcpdm_close_streams(mcpdm);
|
||||
mcpdm->config[0].link_mask = 0;
|
||||
mcpdm->config[1].link_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,7 +297,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
|
||||
int stream = substream->stream;
|
||||
struct omap_pcm_dma_data *dma_data;
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
u32 threshold;
|
||||
int channels;
|
||||
int link_mask = 0;
|
||||
|
||||
@ -325,16 +328,32 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(dai, substream);
|
||||
|
||||
threshold = mcpdm->config[stream].threshold;
|
||||
/* Configure McPDM channels, and DMA packet size */
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
mcpdm->dn_channels = link_mask << 3;
|
||||
dma_data->packet_size =
|
||||
(MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
|
||||
link_mask <<= 3;
|
||||
|
||||
/* If capture is not running assume a stereo stream to come */
|
||||
if (!mcpdm->config[!stream].link_mask)
|
||||
mcpdm->config[!stream].link_mask = 0x3;
|
||||
|
||||
dma_data->maxburst =
|
||||
(MCPDM_DN_THRES_MAX - threshold) * channels;
|
||||
} else {
|
||||
mcpdm->up_channels = link_mask << 0;
|
||||
dma_data->packet_size = mcpdm->up_threshold * channels;
|
||||
/* If playback is not running assume a stereo stream to come */
|
||||
if (!mcpdm->config[!stream].link_mask)
|
||||
mcpdm->config[!stream].link_mask = (0x3 << 3);
|
||||
|
||||
dma_data->maxburst = threshold * channels;
|
||||
}
|
||||
|
||||
/* Check if we need to restart McPDM with this stream */
|
||||
if (mcpdm->config[stream].link_mask &&
|
||||
mcpdm->config[stream].link_mask != link_mask)
|
||||
mcpdm->restart = true;
|
||||
|
||||
mcpdm->config[stream].link_mask = link_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -346,6 +365,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
|
||||
if (!omap_mcpdm_active(mcpdm)) {
|
||||
omap_mcpdm_start(mcpdm);
|
||||
omap_mcpdm_reg_dump(mcpdm);
|
||||
} else if (mcpdm->restart) {
|
||||
omap_mcpdm_stop(mcpdm);
|
||||
omap_mcpdm_start(mcpdm);
|
||||
mcpdm->restart = false;
|
||||
omap_mcpdm_reg_dump(mcpdm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -369,7 +393,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
|
||||
pm_runtime_get_sync(mcpdm->dev);
|
||||
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
|
||||
|
||||
ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
|
||||
ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
|
||||
0, "McPDM", (void *)mcpdm);
|
||||
|
||||
pm_runtime_put_sync(mcpdm->dev);
|
||||
@ -380,8 +404,9 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
|
||||
}
|
||||
|
||||
/* Configure McPDM threshold values */
|
||||
mcpdm->dn_threshold = 2;
|
||||
mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3;
|
||||
mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
|
||||
mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
|
||||
MCPDM_UP_THRES_MAX - 3;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -389,7 +414,6 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
free_irq(mcpdm->irq, (void *)mcpdm);
|
||||
pm_runtime_disable(mcpdm->dev);
|
||||
|
||||
return 0;
|
||||
@ -420,6 +444,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
|
||||
.ops = &omap_mcpdm_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver omap_mcpdm_component = {
|
||||
.name = "omap-mcpdm",
|
||||
};
|
||||
|
||||
void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
|
||||
u8 rx1, u8 rx2)
|
||||
{
|
||||
@ -446,33 +474,30 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
|
||||
if (res == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA;
|
||||
omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA;
|
||||
mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
|
||||
mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
omap_mcpdm_dai_dma_params[0].dma_req = res->start;
|
||||
mcpdm->dma_req[0] = res->start;
|
||||
mcpdm->dma_data[0].filter_data = &mcpdm->dma_req[0];
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
omap_mcpdm_dai_dma_params[1].dma_req = res->start;
|
||||
mcpdm->dma_req[1] = res->start;
|
||||
mcpdm->dma_data[1].filter_data = &mcpdm->dma_req[1];
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
|
||||
if (res == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, res->start,
|
||||
resource_size(res), "McPDM"))
|
||||
return -EBUSY;
|
||||
|
||||
mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!mcpdm->io_base)
|
||||
return -ENOMEM;
|
||||
mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(mcpdm->io_base))
|
||||
return PTR_ERR(mcpdm->io_base);
|
||||
|
||||
mcpdm->irq = platform_get_irq(pdev, 0);
|
||||
if (mcpdm->irq < 0)
|
||||
@ -480,12 +505,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
|
||||
|
||||
mcpdm->dev = &pdev->dev;
|
||||
|
||||
return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
|
||||
return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component,
|
||||
&omap_mcpdm_dai, 1);
|
||||
}
|
||||
|
||||
static int asoc_mcpdm_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,6 @@
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "omap-pcm.h"
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
#define pcm_omap1510() cpu_is_omap1510()
|
||||
#else
|
||||
@ -56,25 +54,6 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
};
|
||||
|
||||
static int omap_pcm_get_dma_buswidth(int num_bits)
|
||||
{
|
||||
int buswidth;
|
||||
|
||||
switch (num_bits) {
|
||||
case 16:
|
||||
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
break;
|
||||
case 32:
|
||||
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
break;
|
||||
default:
|
||||
buswidth = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return buswidth;
|
||||
}
|
||||
|
||||
|
||||
/* this may get called several times by oss emulation */
|
||||
static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
@ -105,20 +84,9 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Override the *_dma addr_width if requested by the DAI driver */
|
||||
if (dma_data->data_type) {
|
||||
int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
config.dst_addr_width = buswidth;
|
||||
else
|
||||
config.src_addr_width = buswidth;
|
||||
}
|
||||
|
||||
config.src_addr = dma_data->port_addr;
|
||||
config.dst_addr = dma_data->port_addr;
|
||||
config.src_maxburst = dma_data->packet_size;
|
||||
config.dst_maxburst = dma_data->packet_size;
|
||||
snd_dmaengine_pcm_set_config_from_dai_data(substream,
|
||||
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
|
||||
&config);
|
||||
|
||||
return dmaengine_slave_config(chan, &config);
|
||||
}
|
||||
@ -129,37 +97,6 @@ static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct omap_pcm_dma_data *dma_data;
|
||||
int ret = 0;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
/* Configure McBSP internal buffer usage */
|
||||
if (dma_data->set_threshold)
|
||||
dma_data->set_threshold(substream);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
ret = snd_dmaengine_pcm_trigger(substream, cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_uframes_t offset;
|
||||
@ -175,20 +112,14 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
static int omap_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct omap_pcm_dma_data *dma_data;
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
|
||||
&dma_data->dma_req);
|
||||
}
|
||||
|
||||
static int omap_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_dmaengine_pcm_close(substream);
|
||||
return 0;
|
||||
dma_data->filter_data);
|
||||
}
|
||||
|
||||
static int omap_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
@ -204,11 +135,11 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
|
||||
|
||||
static struct snd_pcm_ops omap_pcm_ops = {
|
||||
.open = omap_pcm_open,
|
||||
.close = omap_pcm_close,
|
||||
.close = snd_dmaengine_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = omap_pcm_hw_params,
|
||||
.hw_free = omap_pcm_hw_free,
|
||||
.trigger = omap_pcm_trigger,
|
||||
.trigger = snd_dmaengine_pcm_trigger,
|
||||
.pointer = omap_pcm_pointer,
|
||||
.mmap = omap_pcm_mmap,
|
||||
};
|
||||
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* omap-pcm.h
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
*
|
||||
* Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
|
||||
* Peter Ujfalusi <peter.ujfalusi@ti.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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OMAP_PCM_H__
|
||||
#define __OMAP_PCM_H__
|
||||
|
||||
struct snd_pcm_substream;
|
||||
|
||||
struct omap_pcm_dma_data {
|
||||
char *name; /* stream identifier */
|
||||
int dma_req; /* DMA request line */
|
||||
unsigned long port_addr; /* transmit/receive register */
|
||||
void (*set_threshold)(struct snd_pcm_substream *substream);
|
||||
int data_type; /* 8, 16, 32 (bits) or 0 to let omap-pcm
|
||||
* to decide the sDMA data type */
|
||||
int packet_size; /* packet size only in PACKET mode */
|
||||
};
|
||||
|
||||
#endif
|
@ -43,7 +43,6 @@
|
||||
#include <sound/jack.h>
|
||||
|
||||
#include "omap-mcbsp.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
struct omap_twl4030 {
|
||||
int jack_detect; /* board can detect jack events */
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <linux/platform_data/asoc-ti-mcbsp.h>
|
||||
|
||||
#include "omap-mcbsp.h"
|
||||
#include "omap-pcm.h"
|
||||
|
||||
#define OMAP3_PANDORA_DAC_POWER_GPIO 118
|
||||
#define OMAP3_PANDORA_AMP_POWER_GPIO 14
|
||||
@ -80,12 +79,18 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
|
||||
static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The PCM1773 DAC datasheet requires 1ms delay between switching
|
||||
* VCC power on/off and /PD pin high/low
|
||||
*/
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
regulator_enable(omap3pandora_dac_reg);
|
||||
ret = regulator_enable(omap3pandora_dac_reg);
|
||||
if (ret) {
|
||||
dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
mdelay(1);
|
||||
gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
|
||||
} else {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user