Commit 246647ee authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/fsl-spdif', 'asoc/topic/fsl-ssi',...

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
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";
};
...@@ -110,6 +110,7 @@ ingenic Ingenic Semiconductor ...@@ -110,6 +110,7 @@ ingenic Ingenic Semiconductor
innolux Innolux Corporation innolux Innolux Corporation
intel Intel Corporation intel Intel Corporation
intercontrol Inter Control Group intercontrol Inter Control Group
invensense InvenSense Inc.
isee ISEE 2007 S.L. isee ISEE 2007 S.L.
isil Intersil isil Intersil
karo Ka-Ro electronics GmbH karo Ka-Ro electronics GmbH
...@@ -150,6 +151,7 @@ nvidia NVIDIA ...@@ -150,6 +151,7 @@ nvidia NVIDIA
nxp NXP Semiconductors nxp NXP Semiconductors
onnn ON Semiconductor Corp. onnn ON Semiconductor Corp.
opencores OpenCores.org opencores OpenCores.org
option Option NV
ortustech Ortus Technology Co., Ltd. ortustech Ortus Technology Co., Ltd.
ovti OmniVision Technologies ovti OmniVision Technologies
panasonic Panasonic Corporation panasonic Panasonic Corporation
......
...@@ -63,6 +63,8 @@ config SND_SOC_ALL_CODECS ...@@ -63,6 +63,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_BT_SCO select SND_SOC_BT_SCO
select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C select SND_SOC_ES8328_I2C if I2C
select SND_SOC_GTM601
select SND_SOC_ICS43432
select SND_SOC_ISABELLE if I2C select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C select SND_SOC_LM4857 if I2C
...@@ -453,6 +455,12 @@ config SND_SOC_ES8328_SPI ...@@ -453,6 +455,12 @@ config SND_SOC_ES8328_SPI
tristate tristate
select SND_SOC_ES8328 select SND_SOC_ES8328
config SND_SOC_GTM601
tristate 'GTM601 UMTS modem audio codec'
config SND_SOC_ICS43432
tristate
config SND_SOC_ISABELLE config SND_SOC_ISABELLE
tristate tristate
......
...@@ -56,6 +56,8 @@ snd-soc-dmic-objs := dmic.o ...@@ -56,6 +56,8 @@ snd-soc-dmic-objs := dmic.o
snd-soc-es8328-objs := es8328.o snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.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-isabelle-objs := isabelle.o
snd-soc-jz4740-codec-objs := jz4740.o snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-l3-objs := l3.o snd-soc-l3-objs := l3.o
...@@ -245,6 +247,8 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.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) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.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_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_ISABELLE) += snd-soc-isabelle.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
......
...@@ -1533,6 +1533,7 @@ static const struct of_device_id da9055_of_match[] = { ...@@ -1533,6 +1533,7 @@ static const struct of_device_id da9055_of_match[] = {
{ .compatible = "dlg,da9055-codec", }, { .compatible = "dlg,da9055-codec", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, da9055_of_match);
/* I2C codec control layer */ /* I2C codec control layer */
static struct i2c_driver da9055_i2c_driver = { static struct i2c_driver da9055_i2c_driver = {
......
/*
* 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");
/*
* 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");
...@@ -598,6 +598,7 @@ static const struct of_device_id wm8510_of_match[] = { ...@@ -598,6 +598,7 @@ static const struct of_device_id wm8510_of_match[] = {
{ .compatible = "wlf,wm8510" }, { .compatible = "wlf,wm8510" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, wm8510_of_match);
static const struct regmap_config wm8510_regmap = { static const struct regmap_config wm8510_regmap = {
.reg_bits = 7, .reg_bits = 7,
......
...@@ -430,6 +430,7 @@ static const struct of_device_id wm8523_of_match[] = { ...@@ -430,6 +430,7 @@ static const struct of_device_id wm8523_of_match[] = {
{ .compatible = "wlf,wm8523" }, { .compatible = "wlf,wm8523" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, wm8523_of_match);
static const struct regmap_config wm8523_regmap = { static const struct regmap_config wm8523_regmap = {
.reg_bits = 8, .reg_bits = 8,
......
...@@ -916,6 +916,7 @@ static const struct of_device_id wm8580_of_match[] = { ...@@ -916,6 +916,7 @@ static const struct of_device_id wm8580_of_match[] = {
{ .compatible = "wlf,wm8580" }, { .compatible = "wlf,wm8580" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, wm8580_of_match);
static const struct regmap_config wm8580_regmap = { static const struct regmap_config wm8580_regmap = {
.reg_bits = 7, .reg_bits = 7,
......
...@@ -454,7 +454,8 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, ...@@ -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 fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct platform_device *pdev = spdif_priv->pdev; struct platform_device *pdev = spdif_priv->pdev;
struct regmap *regmap = spdif_priv->regmap; struct regmap *regmap = spdif_priv->regmap;
u32 scr, mask, i; u32 scr, mask;
int i;
int ret; int ret;
/* Reset module and interrupts only for first initialization */ /* Reset module and interrupts only for first initialization */
......
...@@ -900,14 +900,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, ...@@ -900,14 +900,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
break; break;
default: default:
return -EINVAL; if (!fsl_ssi_is_ac97(ssi_private))
return -EINVAL;
} }
stcr |= strcr; stcr |= strcr;
srcr |= strcr; srcr |= strcr;
if (ssi_private->cpu_dai_drv.symmetric_rates) { if (ssi_private->cpu_dai_drv.symmetric_rates
/* Need to clear RXDIR when using SYNC mode */ || fsl_ssi_is_ac97(ssi_private)) {
/* Need to clear RXDIR when using SYNC or AC97 mode */
srcr &= ~CCSR_SSI_SRCR_RXDIR; srcr &= ~CCSR_SSI_SRCR_RXDIR;
scr |= CCSR_SSI_SCR_SYN; scr |= CCSR_SSI_SCR_SYN;
} }
...@@ -1101,6 +1103,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = { ...@@ -1101,6 +1103,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.bus_control = true, .bus_control = true,
.probe = fsl_ssi_dai_probe,
.playback = { .playback = {
.stream_name = "AC97 Playback", .stream_name = "AC97 Playback",
.channels_min = 2, .channels_min = 2,
...@@ -1127,10 +1130,17 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, ...@@ -1127,10 +1130,17 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
struct regmap *regs = fsl_ac97_data->regs; struct regmap *regs = fsl_ac97_data->regs;
unsigned int lreg; unsigned int lreg;
unsigned int lval; unsigned int lval;
int ret;
if (reg > 0x7f) if (reg > 0x7f)
return; 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; lreg = reg << 12;
regmap_write(regs, CCSR_SSI_SACADD, lreg); regmap_write(regs, CCSR_SSI_SACADD, lreg);
...@@ -1141,6 +1151,8 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, ...@@ -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, regmap_update_bits(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_RDWR_MASK,
CCSR_SSI_SACNT_WR); CCSR_SSI_SACNT_WR);
udelay(100); udelay(100);
clk_disable_unprepare(fsl_ac97_data->clk);
} }
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, 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, ...@@ -1151,6 +1163,14 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
unsigned short val = -1; unsigned short val = -1;
u32 reg_val; u32 reg_val;
unsigned int lreg; 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; lreg = (reg & 0x7f) << 12;
regmap_write(regs, CCSR_SSI_SACADD, lreg); regmap_write(regs, CCSR_SSI_SACADD, lreg);
...@@ -1162,6 +1182,8 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, ...@@ -1162,6 +1182,8 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
regmap_read(regs, CCSR_SSI_SACDAT, &reg_val); regmap_read(regs, CCSR_SSI_SACDAT, &reg_val);
val = (reg_val >> 4) & 0xffff; val = (reg_val >> 4) & 0xffff;
clk_disable_unprepare(fsl_ac97_data->clk);
return val; return val;
} }
...@@ -1320,7 +1342,11 @@ static int fsl_ssi_probe(struct platform_device *pdev) ...@@ -1320,7 +1342,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
fsl_ac97_data = ssi_private; 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 { } else {
/* Initialize this copy of the CPU DAI driver structure */ /* Initialize this copy of the CPU DAI driver structure */
memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template, memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
...@@ -1357,7 +1383,9 @@ static int fsl_ssi_probe(struct platform_device *pdev) ...@@ -1357,7 +1383,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
/* Are the RX and the TX clocks locked? */ /* Are the RX and the TX clocks locked? */
if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { 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_channels = 1;
ssi_private->cpu_dai_drv.symmetric_samplebits = 1; ssi_private->cpu_dai_drv.symmetric_samplebits = 1;
} }
...@@ -1434,6 +1462,27 @@ static int fsl_ssi_probe(struct platform_device *pdev) ...@@ -1434,6 +1462,27 @@ static int fsl_ssi_probe(struct platform_device *pdev)
_fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private, _fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private,
ssi_private->dai_fmt); 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; return 0;
error_sound_card: error_sound_card:
...@@ -1458,6 +1507,9 @@ static int fsl_ssi_remove(struct platform_device *pdev) ...@@ -1458,6 +1507,9 @@ static int fsl_ssi_remove(struct platform_device *pdev)
if (ssi_private->soc->imx) if (ssi_private->soc->imx)
fsl_ssi_imx_clean(pdev, ssi_private); fsl_ssi_imx_clean(pdev, ssi_private);
if (fsl_ssi_is_ac97(ssi_private))
snd_soc_set_ac97_ops(NULL);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment