Merge remote-tracking branches 'asoc/topic/fsl-spdif', 'asoc/topic/fsl-ssi', 'asoc/topic/gtm601', 'asoc/topic/ics43432' and 'asoc/topic/ids' into asoc-next

This commit is contained in:
Mark Brown 2015-08-30 15:54:15 +01:00
12 changed files with 265 additions and 6 deletions

View File

@ -0,0 +1,17 @@
Invensense ICS-43432 MEMS microphone with I2S output.
There are no software configuration options for this device, indeed, the only
host connection is the I2S interface. Apart from requirements on clock
frequency (460 kHz to 3.379 MHz according to the data sheet) there must be
64 clock cycles in each stereo output frame; 24 of the 32 available bits
contain audio data. A hardware pin determines if the device outputs data
on the left or right channel of the I2S frame.
Required properties:
- compatible : Must be "invensense,ics43432"
Example:
ics43432: ics43432 {
compatible = "invensense,ics43432";
};

View File

@ -110,6 +110,7 @@ ingenic Ingenic Semiconductor
innolux Innolux Corporation
intel Intel Corporation
intercontrol Inter Control Group
invensense InvenSense Inc.
isee ISEE 2007 S.L.
isil Intersil
karo Ka-Ro electronics GmbH
@ -150,6 +151,7 @@ nvidia NVIDIA
nxp NXP Semiconductors
onnn ON Semiconductor Corp.
opencores OpenCores.org
option Option NV
ortustech Ortus Technology Co., Ltd.
ovti OmniVision Technologies
panasonic Panasonic Corporation

View File

@ -63,6 +63,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_BT_SCO
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
select SND_SOC_GTM601
select SND_SOC_ICS43432
select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C
@ -453,6 +455,12 @@ config SND_SOC_ES8328_SPI
tristate
select SND_SOC_ES8328
config SND_SOC_GTM601
tristate 'GTM601 UMTS modem audio codec'
config SND_SOC_ICS43432
tristate
config SND_SOC_ISABELLE
tristate

View File

@ -56,6 +56,8 @@ snd-soc-dmic-objs := dmic.o
snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o
snd-soc-gtm601-objs := gtm601.o
snd-soc-ics43432-objs := ics43432.o
snd-soc-isabelle-objs := isabelle.o
snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-l3-objs := l3.o
@ -245,6 +247,8 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o
obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o

View File

@ -1533,6 +1533,7 @@ static const struct of_device_id da9055_of_match[] = {
{ .compatible = "dlg,da9055-codec", },
{ }
};
MODULE_DEVICE_TABLE(of, da9055_of_match);
/* I2C codec control layer */
static struct i2c_driver da9055_i2c_driver = {

95
sound/soc/codecs/gtm601.c Normal file
View File

@ -0,0 +1,95 @@
/*
* This is a simple driver for the GTM601 Voice PCM interface
*
* Copyright (C) 2015 Goldelico GmbH
*
* Author: Marek Belisko <marek@goldelico.com>
*
* Based on wm8727.c driver
*
* 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/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
static const struct snd_soc_dapm_widget gtm601_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("AOUT"),
SND_SOC_DAPM_INPUT("AIN"),
};
static const struct snd_soc_dapm_route gtm601_dapm_routes[] = {
{ "AOUT", NULL, "Playback" },
{ "Capture", NULL, "AIN" },
};
static struct snd_soc_dai_driver gtm601_dai = {
.name = "gtm601",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 1,
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 1,
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
};
static const struct snd_soc_codec_driver soc_codec_dev_gtm601 = {
.dapm_widgets = gtm601_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets),
.dapm_routes = gtm601_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(gtm601_dapm_routes),
};
static int gtm601_platform_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev,
&soc_codec_dev_gtm601, &gtm601_dai, 1);
}
static int gtm601_platform_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
#if defined(CONFIG_OF)
static const struct of_device_id gtm601_codec_of_match[] = {
{ .compatible = "option,gtm601", },
{},
};
MODULE_DEVICE_TABLE(of, gtm601_codec_of_match);
#endif
static struct platform_driver gtm601_codec_driver = {
.driver = {
.name = "gtm601",
.of_match_table = of_match_ptr(gtm601_codec_of_match),
},
.probe = gtm601_platform_probe,
.remove = gtm601_platform_remove,
};
module_platform_driver(gtm601_codec_driver);
MODULE_DESCRIPTION("ASoC gtm601 driver");
MODULE_AUTHOR("Marek Belisko <marek@goldelico.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:gtm601");

View File

@ -0,0 +1,76 @@
/*
* I2S MEMS microphone driver for InvenSense ICS-43432
*
* - Non configurable.
* - I2S interface, 64 BCLs per frame, 32 bits per channel, 24 bit data
*
* Copyright (c) 2015 Axis Communications AB
*
* Licensed under GPL v2.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#define ICS43432_RATE_MIN 7190 /* Hz, from data sheet */
#define ICS43432_RATE_MAX 52800 /* Hz, from data sheet */
#define ICS43432_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32)
static struct snd_soc_dai_driver ics43432_dai = {
.name = "ics43432-hifi",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rate_min = ICS43432_RATE_MIN,
.rate_max = ICS43432_RATE_MAX,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = ICS43432_FORMATS,
},
};
static struct snd_soc_codec_driver ics43432_codec_driver = {
};
static int ics43432_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev, &ics43432_codec_driver,
&ics43432_dai, 1);
}
static int ics43432_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id ics43432_ids[] = {
{ .compatible = "invensense,ics43432", },
{ }
};
MODULE_DEVICE_TABLE(of, ics43432_ids);
#endif
static struct platform_driver ics43432_driver = {
.driver = {
.name = "ics43432",
.of_match_table = of_match_ptr(ics43432_ids),
},
.probe = ics43432_probe,
.remove = ics43432_remove,
};
module_platform_driver(ics43432_driver);
MODULE_DESCRIPTION("ASoC ICS43432 driver");
MODULE_AUTHOR("Ricard Wanderlof <ricardw@axis.com>");
MODULE_LICENSE("GPL v2");

View File

@ -598,6 +598,7 @@ static const struct of_device_id wm8510_of_match[] = {
{ .compatible = "wlf,wm8510" },
{ },
};
MODULE_DEVICE_TABLE(of, wm8510_of_match);
static const struct regmap_config wm8510_regmap = {
.reg_bits = 7,

View File

@ -430,6 +430,7 @@ static const struct of_device_id wm8523_of_match[] = {
{ .compatible = "wlf,wm8523" },
{ },
};
MODULE_DEVICE_TABLE(of, wm8523_of_match);
static const struct regmap_config wm8523_regmap = {
.reg_bits = 8,

View File

@ -916,6 +916,7 @@ static const struct of_device_id wm8580_of_match[] = {
{ .compatible = "wlf,wm8580" },
{ },
};
MODULE_DEVICE_TABLE(of, wm8580_of_match);
static const struct regmap_config wm8580_regmap = {
.reg_bits = 7,

View File

@ -454,7 +454,8 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct platform_device *pdev = spdif_priv->pdev;
struct regmap *regmap = spdif_priv->regmap;
u32 scr, mask, i;
u32 scr, mask;
int i;
int ret;
/* Reset module and interrupts only for first initialization */

View File

@ -900,14 +900,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
break;
default:
return -EINVAL;
if (!fsl_ssi_is_ac97(ssi_private))
return -EINVAL;
}
stcr |= strcr;
srcr |= strcr;
if (ssi_private->cpu_dai_drv.symmetric_rates) {
/* Need to clear RXDIR when using SYNC mode */
if (ssi_private->cpu_dai_drv.symmetric_rates
|| fsl_ssi_is_ac97(ssi_private)) {
/* Need to clear RXDIR when using SYNC or AC97 mode */
srcr &= ~CCSR_SSI_SRCR_RXDIR;
scr |= CCSR_SSI_SCR_SYN;
}
@ -1101,6 +1103,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.bus_control = true,
.probe = fsl_ssi_dai_probe,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
@ -1127,10 +1130,17 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
struct regmap *regs = fsl_ac97_data->regs;
unsigned int lreg;
unsigned int lval;
int ret;
if (reg > 0x7f)
return;
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 write clk_prepare_enable failed: %d\n",
ret);
return;
}
lreg = reg << 12;
regmap_write(regs, CCSR_SSI_SACADD, lreg);
@ -1141,6 +1151,8 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK,
CCSR_SSI_SACNT_WR);
udelay(100);
clk_disable_unprepare(fsl_ac97_data->clk);
}
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
@ -1151,6 +1163,14 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
unsigned short val = -1;
u32 reg_val;
unsigned int lreg;
int ret;
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 read clk_prepare_enable failed: %d\n",
ret);
return -1;
}
lreg = (reg & 0x7f) << 12;
regmap_write(regs, CCSR_SSI_SACADD, lreg);
@ -1162,6 +1182,8 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
regmap_read(regs, CCSR_SSI_SACDAT, &reg_val);
val = (reg_val >> 4) & 0xffff;
clk_disable_unprepare(fsl_ac97_data->clk);
return val;
}
@ -1320,7 +1342,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
fsl_ac97_data = ssi_private;
snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
if (ret) {
dev_err(&pdev->dev, "could not set AC'97 ops\n");
return ret;
}
} else {
/* Initialize this copy of the CPU DAI driver structure */
memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
@ -1357,7 +1383,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
/* Are the RX and the TX clocks locked? */
if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) {
ssi_private->cpu_dai_drv.symmetric_rates = 1;
if (!fsl_ssi_is_ac97(ssi_private))
ssi_private->cpu_dai_drv.symmetric_rates = 1;
ssi_private->cpu_dai_drv.symmetric_channels = 1;
ssi_private->cpu_dai_drv.symmetric_samplebits = 1;
}
@ -1434,6 +1462,27 @@ static int fsl_ssi_probe(struct platform_device *pdev)
_fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private,
ssi_private->dai_fmt);
if (fsl_ssi_is_ac97(ssi_private)) {
u32 ssi_idx;
ret = of_property_read_u32(np, "cell-index", &ssi_idx);
if (ret) {
dev_err(&pdev->dev, "cannot get SSI index property\n");
goto error_sound_card;
}
ssi_private->pdev =
platform_device_register_data(NULL,
"ac97-codec", ssi_idx, NULL, 0);
if (IS_ERR(ssi_private->pdev)) {
ret = PTR_ERR(ssi_private->pdev);
dev_err(&pdev->dev,
"failed to register AC97 codec platform: %d\n",
ret);
goto error_sound_card;
}
}
return 0;
error_sound_card:
@ -1458,6 +1507,9 @@ static int fsl_ssi_remove(struct platform_device *pdev)
if (ssi_private->soc->imx)
fsl_ssi_imx_clean(pdev, ssi_private);
if (fsl_ssi_is_ac97(ssi_private))
snd_soc_set_ac97_ops(NULL);
return 0;
}