Commit 7ddb870b authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/fsl-esai' into asoc-next

parents 64fdf13c 5ea55705
Device-Tree binding for regmap
The endianness mode of CPU & Device scenarios:
Index Device Endianness properties
---------------------------------------------------
1 BE 'big-endian'
2 LE 'little-endian'
For one device driver, which will run in different scenarios above
on different SoCs using the devicetree, we need one way to simplify
this.
Required properties:
- {big,little}-endian: these are boolean properties, if absent
meaning that the CPU and the Device are in the same endianness mode,
these properties are for register values and all the buffers only.
Examples:
Scenario 1 : CPU in LE mode & device in LE mode.
dev: dev@40031000 {
compatible = "name";
reg = <0x40031000 0x1000>;
...
};
Scenario 2 : CPU in LE mode & device in BE mode.
dev: dev@40031000 {
compatible = "name";
reg = <0x40031000 0x1000>;
...
big-endian;
};
Scenario 3 : CPU in BE mode & device in BE mode.
dev: dev@40031000 {
compatible = "name";
reg = <0x40031000 0x1000>;
...
};
Scenario 4 : CPU in BE mode & device in LE mode.
dev: dev@40031000 {
compatible = "name";
reg = <0x40031000 0x1000>;
...
little-endian;
};
Everest ES8328 audio CODEC
This device supports both I2C and SPI.
Required properties:
- compatible : "everest,es8328"
- DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V
- AVDD-supply : Regulator providing analog supply voltage 3.3V
- PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V
- IPVDD-supply : Regulator providing analog output voltage 3.3V
- clocks : A 22.5792 or 11.2896 MHz clock
- reg : the I2C address of the device for I2C, the chip select number for SPI
Pins on the device (for linking into audio routes):
* LOUT1
* LOUT2
* ROUT1
* ROUT2
* LINPUT1
* RINPUT1
* LINPUT2
* RINPUT2
* Mic Bias
Example:
codec: es8328@11 {
compatible = "everest,es8328";
DVDD-supply = <&reg_3p3v>;
AVDD-supply = <&reg_3p3v>;
PVDD-supply = <&reg_3p3v>;
HPVDD-supply = <&reg_3p3v>;
clocks = <&clks 169>;
reg = <0x11>;
};
......@@ -7,7 +7,8 @@ other DSPs. It has up to six transmitters and four receivers.
Required properties:
- compatible : Compatible list, must contain "fsl,imx35-esai".
- compatible : Compatible list, must contain "fsl,imx35-esai" or
"fsl,vf610-esai"
- reg : Offset and length of the register set for the device.
......
Freescale Generic ASoC Sound Card with ASRC support
The Freescale Generic ASoC Sound Card can be used, ideally, for all Freescale
SoCs connecting with external CODECs.
The idea of this generic sound card is a bit like ASoC Simple Card. However,
for Freescale SoCs (especially those released in recent years), most of them
have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And
this is a specific feature that might be painstakingly controlled and merged
into the Simple Card.
So having this generic sound card allows all Freescale SoC users to benefit
from the simplification of a new card support and the capability of the wide
sample rates support through ASRC.
Note: The card is initially designed for those sound cards who use I2S and
PCM DAI formats. However, it'll be also possible to support those non
I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as long
as the driver has been properly upgraded.
The compatible list for this generic sound card currently:
"fsl,imx-audio-cs42888"
"fsl,imx-audio-wm8962"
(compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt)
"fsl,imx-audio-sgtl5000"
(compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt)
Required properties:
- compatible : Contains one of entries in the compatible list.
- model : The user-visible name of this sound complex
- audio-cpu : The phandle of an CPU DAI controller
- audio-codec : The phandle of an audio codec
- audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source. There're a few pre-designed board connectors:
* Line Out Jack
* Line In Jack
* Headphone Jack
* Mic Jack
* Ext Spk
* AMIC (stands for Analog Microphone Jack)
* DMIC (stands for Digital Microphone Jack)
Note: The "Mic Jack" and "AMIC" are redundant while
coexsiting in order to support the old bindings
of wm8962 and sgtl5000.
Optional properties:
- audio-asrc : The phandle of ASRC. It can be absent if there's no
need to add ASRC support via DPCM.
Example:
sound-cs42888 {
compatible = "fsl,imx-audio-cs42888";
model = "cs42888-audio";
audio-cpu = <&esai>;
audio-asrc = <&asrc>;
audio-codec = <&cs42888>;
audio-routing =
"Line Out Jack", "AOUT1L",
"Line Out Jack", "AOUT1R",
"Line Out Jack", "AOUT2L",
"Line Out Jack", "AOUT2R",
"Line Out Jack", "AOUT3L",
"Line Out Jack", "AOUT3R",
"Line Out Jack", "AOUT4L",
"Line Out Jack", "AOUT4R",
"AIN1L", "Line In Jack",
"AIN1R", "Line In Jack",
"AIN2L", "Line In Jack",
"AIN2R", "Line In Jack";
};
......@@ -18,9 +18,8 @@ Required properties:
- pinctrl-names: Must contain a "default" entry.
- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
See ../pinctrl/pinctrl-bindings.txt for details of the property values.
- big-endian-regs: If this property is absent, the little endian mode will
be in use as default, or the big endian mode will be in use for all the
device registers.
- big-endian: Boolean property, required if all the FTM_PWM registers
are big-endian rather than little-endian.
- big-endian-data: If this property is absent, the little endian mode will
be in use as default, or the big endian mode will be in use for all the
fifo data.
......@@ -38,6 +37,6 @@ sai2: sai@40031000 {
dma-names = "tx", "rx";
dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
<&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
big-endian-regs;
big-endian;
big-endian-data;
};
Freescale i.MX audio complex with ES8328 codec
Required properties:
- compatible : "fsl,imx-audio-es8328"
- model : The user-visible name of this sound complex
- ssi-controller : The phandle of the i.MX SSI controller
- jack-gpio : Optional GPIO for headphone jack
- audio-amp-supply : Power regulator for speaker amps
- audio-codec : The phandle of the ES8328 audio codec
- audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source. Valid names could be power supplies, ES8328
pins, and the jacks on the board:
Power supplies:
* audio-amp
ES8328 pins:
* LOUT1
* LOUT2
* ROUT1
* ROUT2
* LINPUT1
* LINPUT2
* RINPUT1
* RINPUT2
* Mic PGA
Board connectors:
* Headphone
* Speaker
* Mic Jack
- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
- mux-ext-port : The external port of the i.MX audio muxer (AUDMIX)
Note: The AUDMUX port numbering should start at 1, which is consistent with
hardware manual.
Example:
sound {
compatible = "fsl,imx-audio-es8328";
model = "imx-audio-es8328";
ssi-controller = <&ssi1>;
audio-codec = <&codec>;
jack-gpio = <&gpio5 15 0>;
audio-amp-supply = <&reg_audio_amp>;
audio-routing =
"Speaker", "LOUT2",
"Speaker", "ROUT2",
"Speaker", "audio-amp",
"Headphone", "ROUT1",
"Headphone", "LOUT1",
"LINPUT1", "Mic Jack",
"RINPUT1", "Mic Jack",
"Mic Jack", "Mic Bias";
mux-int-port = <1>;
mux-ext-port = <3>;
};
......@@ -48,6 +48,7 @@ epfl Ecole Polytechnique Fédérale de Lausanne
epson Seiko Epson Corp.
est ESTeem Wireless Modems
eukrea Eukréa Electromatique
everest Everest Semiconductor Co. Ltd.
excito Excito
fsl Freescale Semiconductor
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
......
......@@ -168,6 +168,8 @@ static struct regmap_bus regmap_i2c = {
.write = regmap_i2c_write,
.gather_write = regmap_i2c_gather_write,
.read = regmap_i2c_read,
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
};
static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
......
......@@ -109,6 +109,8 @@ static struct regmap_bus regmap_spi = {
.async_alloc = regmap_spi_async_alloc,
.read = regmap_spi_read,
.read_flag_mask = 0x80,
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
};
/**
......
......@@ -15,6 +15,7 @@
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/rbtree.h>
#include <linux/sched.h>
......@@ -448,6 +449,66 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
}
EXPORT_SYMBOL_GPL(regmap_attach_dev);
static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus,
const struct regmap_config *config)
{
enum regmap_endian endian;
/* Retrieve the endianness specification from the regmap config */
endian = config->reg_format_endian;
/* If the regmap config specified a non-default value, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;
/* Retrieve the endianness specification from the bus config */
if (bus && bus->reg_format_endian_default)
endian = bus->reg_format_endian_default;
/* If the bus specified a non-default value, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;
/* Use this if no other value was found */
return REGMAP_ENDIAN_BIG;
}
static enum regmap_endian regmap_get_val_endian(struct device *dev,
const struct regmap_bus *bus,
const struct regmap_config *config)
{
struct device_node *np = dev->of_node;
enum regmap_endian endian;
/* Retrieve the endianness specification from the regmap config */
endian = config->val_format_endian;
/* If the regmap config specified a non-default value, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;
/* Parse the device's DT node for an endianness specification */
if (of_property_read_bool(np, "big-endian"))
endian = REGMAP_ENDIAN_BIG;
else if (of_property_read_bool(np, "little-endian"))
endian = REGMAP_ENDIAN_LITTLE;
/* If the endianness was specified in DT, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;
/* Retrieve the endianness specification from the bus config */
if (bus && bus->val_format_endian_default)
endian = bus->val_format_endian_default;
/* If the bus specified a non-default value, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;
/* Use this if no other value was found */
return REGMAP_ENDIAN_BIG;
}
/**
* regmap_init(): Initialise register map
*
......@@ -551,17 +612,8 @@ struct regmap *regmap_init(struct device *dev,
map->reg_read = _regmap_bus_read;
}
reg_endian = config->reg_format_endian;
if (reg_endian == REGMAP_ENDIAN_DEFAULT)
reg_endian = bus->reg_format_endian_default;
if (reg_endian == REGMAP_ENDIAN_DEFAULT)
reg_endian = REGMAP_ENDIAN_BIG;
val_endian = config->val_format_endian;
if (val_endian == REGMAP_ENDIAN_DEFAULT)
val_endian = bus->val_format_endian_default;
if (val_endian == REGMAP_ENDIAN_DEFAULT)
val_endian = REGMAP_ENDIAN_BIG;
reg_endian = regmap_get_reg_endian(bus, config);
val_endian = regmap_get_val_endian(dev, bus, config);
switch (config->reg_bits + map->reg_shift) {
case 2:
......
......@@ -57,6 +57,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
select SND_SOC_BT_SCO
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C
......@@ -405,6 +407,17 @@ config SND_SOC_DMIC
config SND_SOC_HDMI_CODEC
tristate "HDMI stub CODEC"
config SND_SOC_ES8328
tristate "Everest Semi ES8328 CODEC"
config SND_SOC_ES8328_I2C
tristate
select SND_SOC_ES8328
config SND_SOC_ES8328_SPI
tristate
select SND_SOC_ES8328
config SND_SOC_ISABELLE
tristate
......
......@@ -49,6 +49,9 @@ snd-soc-da732x-objs := da732x.o
snd-soc-da9055-objs := da9055.o
snd-soc-bt-sco-objs := bt-sco.o
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-isabelle-objs := isabelle.o
snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-l3-objs := l3.o
......@@ -220,6 +223,9 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
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_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
......
/*
* es8328-i2c.c -- ES8328 ALSA SoC I2C Audio driver
*
* Copyright 2014 Sutajio Ko-Usagi PTE LTD
*
* Author: Sean Cross <xobs@kosagi.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/i2c.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "es8328.h"
static const struct i2c_device_id es8328_id[] = {
{ "everest,es8328", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, es8328_id);
static const struct of_device_id es8328_of_match[] = {
{ .compatible = "everest,es8328", },
{ }
};
MODULE_DEVICE_TABLE(of, es8328_of_match);
static int es8328_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
return es8328_probe(&i2c->dev,
devm_regmap_init_i2c(i2c, &es8328_regmap_config));
}
static int es8328_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
return 0;
}
static struct i2c_driver es8328_i2c_driver = {
.driver = {
.name = "es8328",
.of_match_table = es8328_of_match,
},
.probe = es8328_i2c_probe,
.remove = es8328_i2c_remove,
.id_table = es8328_id,
};
module_i2c_driver(es8328_i2c_driver);
MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver");
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
MODULE_LICENSE("GPL");
/*
* es8328.c -- ES8328 ALSA SoC SPI Audio driver
*
* Copyright 2014 Sutajio Ko-Usagi PTE LTD
*
* Author: Sean Cross <xobs@kosagi.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/regmap.h>
#include <linux/spi/spi.h>
#include <sound/soc.h>
#include "es8328.h"
static const struct of_device_id es8328_of_match[] = {
{ .compatible = "everest,es8328", },
{ }
};
MODULE_DEVICE_TABLE(of, es8328_of_match);
static int es8328_spi_probe(struct spi_device *spi)
{
return es8328_probe(&spi->dev,
devm_regmap_init_spi(spi, &es8328_regmap_config));
}
static int es8328_spi_remove(struct spi_device *spi)
{
snd_soc_unregister_codec(&spi->dev);
return 0;
}
static struct spi_driver es8328_spi_driver = {
.driver = {
.name = "es8328",
.of_match_table = es8328_of_match,
},
.probe = es8328_spi_probe,
.remove = es8328_spi_remove,
};
module_spi_driver(es8328_spi_driver);
MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver");
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
MODULE_LICENSE("GPL");
This diff is collapsed.
This diff is collapsed.
......@@ -240,6 +240,18 @@ config SND_SOC_IMX_WM8962
Say Y if you want to add support for SoC audio on an i.MX board with
a wm8962 codec.
config SND_SOC_IMX_ES8328
tristate "SoC Audio support for i.MX boards with the ES8328 codec"
depends on OF && (I2C || SPI)
select SND_SOC_ES8328_I2C if I2C
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_IMX_PCM_DMA
select SND_SOC_IMX_AUDMUX
select SND_SOC_FSL_SSI
help
Say Y if you want to add support for the ES8328 audio codec connected
via SSI/I2S over either SPI or I2C.
config SND_SOC_IMX_SGTL5000
tristate "SoC Audio support for i.MX boards with sgtl5000"
depends on OF && I2C
......@@ -268,6 +280,23 @@ config SND_SOC_IMX_MC13783
select SND_SOC_MC13783
select SND_SOC_IMX_PCM_DMA
config SND_SOC_FSL_ASOC_CARD
tristate "Generic ASoC Sound Card with ASRC support"
depends on OF && I2C
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_PCM_DMA
select SND_SOC_FSL_ESAI
select SND_SOC_FSL_SAI
select SND_SOC_FSL_SSI
select SND_SOC_CS42XX8_I2C
select SND_SOC_SGTL5000
select SND_SOC_WM8962
help
ALSA SoC Audio support with ASRC feature for Freescale SoCs that have
ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888
and SGTL5000.
Say Y if you want to add support for Freescale Generic ASoC Sound Card.
endif # SND_IMX_SOC
endmenu
......@@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o
obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
# Freescale SSI/DMA/SAI/SPDIF Support
snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o
snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o
snd-soc-fsl-sai-objs := fsl_sai.o
snd-soc-fsl-ssi-y := fsl_ssi.o
......@@ -19,6 +20,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o
snd-soc-fsl-esai-objs := fsl_esai.o
snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
......@@ -50,6 +52,7 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
snd-soc-phycore-ac97-objs := phycore-ac97.o
snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
snd-soc-wm1133-ev1-objs := wm1133-ev1.o
snd-soc-imx-es8328-objs := imx-es8328.o
snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
snd-soc-imx-wm8962-objs := imx-wm8962.o
snd-soc-imx-spdif-objs := imx-spdif.o
......@@ -59,6 +62,7 @@ obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
......
This diff is collapsed.
......@@ -684,7 +684,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg)
}
}
static struct regmap_config fsl_asrc_regmap_config = {
static const struct regmap_config fsl_asrc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
......@@ -802,10 +802,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
asrc_priv->paddr = res->start;
/* Register regmap and let it prepare core clock */
if (of_property_read_bool(np, "big-endian"))
fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs,
&fsl_asrc_regmap_config);
if (IS_ERR(asrc_priv->regmap)) {
......
......@@ -37,6 +37,7 @@
* @fsysclk: system clock source to derive HCK, SCK and FS
* @fifo_depth: depth of tx/rx FIFO
* @slot_width: width of each DAI slot
* @slots: number of slots
* @hck_rate: clock rate of desired HCKx clock
* @sck_rate: clock rate of desired SCKx clock
* @hck_dir: the direction of HCKx pads
......@@ -55,6 +56,7 @@ struct fsl_esai {
struct clk *fsysclk;
u32 fifo_depth;
u32 slot_width;
u32 slots;
u32 hck_rate[2];
u32 sck_rate[2];
bool hck_dir[2];
......@@ -362,6 +364,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
esai_priv->slot_width = slot_width;
esai_priv->slots = slots;
return 0;
}
......@@ -509,10 +512,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 width = snd_pcm_format_width(params_format(params));
u32 channels = params_channels(params);
u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
u32 bclk, mask, val;
int ret;
bclk = params_rate(params) * esai_priv->slot_width * 2;
bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots;
ret = fsl_esai_set_bclk(dai, tx, bclk);
if (ret)
......@@ -529,7 +533,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
(tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |
(tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
(tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins));
regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
......@@ -564,6 +568,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u8 i, channels = substream->runtime->channels;
u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
......@@ -578,7 +583,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins));
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
......@@ -705,7 +710,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
}
}
static struct regmap_config fsl_esai_regmap_config = {
static const struct regmap_config fsl_esai_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
......@@ -731,9 +736,6 @@ static int fsl_esai_probe(struct platform_device *pdev)
esai_priv->pdev = pdev;
strcpy(esai_priv->name, np->name);
if (of_property_read_bool(np, "big-endian"))
fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
......@@ -781,6 +783,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
/* Set a default slot size */
esai_priv->slot_width = 32;
/* Set a default slot number */
esai_priv->slots = 2;
/* Set a default master/slave state */
esai_priv->slave_mode = true;
......
......@@ -130,8 +130,8 @@
#define ESAI_xFCR_RE_WIDTH 4
#define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
#define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK)
#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK)
#define ESAI_xFCR_xFR_SHIFT 1
#define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT)
#define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT)
......@@ -272,8 +272,8 @@
#define ESAI_xCR_RE_WIDTH 4
#define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
#define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK)
#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK)
/*
* Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
......
......@@ -539,7 +539,7 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
}
}
static struct regmap_config fsl_sai_regmap_config = {
static const struct regmap_config fsl_sai_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
......@@ -568,10 +568,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
sai->sai_on_imx = true;
sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
if (sai->big_endian_regs)
fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......
......@@ -131,7 +131,6 @@ struct fsl_sai {
struct clk *bus_clk;
struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
bool big_endian_regs;
bool big_endian_data;
bool is_dsp_mode;
bool sai_on_imx;
......
......@@ -1040,7 +1040,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
}
}
static struct regmap_config fsl_spdif_regmap_config = {
static const struct regmap_config fsl_spdif_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
......@@ -1184,9 +1184,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
spdif_priv->cpu_dai_drv.name = spdif_priv->name;
if (of_property_read_bool(np, "big-endian"))
fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
......
/*
* Copyright 2012 Freescale Semiconductor, Inc.
* Copyright 2012 Linaro Ltd.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/i2c.h>
#include <linux/of_gpio.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "imx-audmux.h"
#define DAI_NAME_SIZE 32
#define MUX_PORT_MAX 7
struct imx_es8328_data {
struct device *dev;
struct snd_soc_dai_link dai;
struct snd_soc_card card;
char codec_dai_name[DAI_NAME_SIZE];
char platform_name[DAI_NAME_SIZE];
int jack_gpio;
};
static struct snd_soc_jack_gpio headset_jack_gpios[] = {
{
.gpio = -1,
.name = "headset-gpio",
.report = SND_JACK_HEADSET,
.invert = 0,
.debounce_time = 200,
},
};
static struct snd_soc_jack headset_jack;
static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct imx_es8328_data *data = container_of(rtd->card,
struct imx_es8328_data, card);
int ret = 0;
/* Headphone jack detection */
if (gpio_is_valid(data->jack_gpio)) {
ret = snd_soc_jack_new(rtd->codec, "Headphone",
SND_JACK_HEADPHONE | SND_JACK_BTN_0,
&headset_jack);
if (ret)
return ret;
headset_jack_gpios[0].gpio = data->jack_gpio;
ret = snd_soc_jack_add_gpios(&headset_jack,
ARRAY_SIZE(headset_jack_gpios),
headset_jack_gpios);
}
return ret;
}
static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
};
static int imx_es8328_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *ssi_np, *codec_np;
struct platform_device *ssi_pdev;
struct imx_es8328_data *data;
u32 int_port, ext_port;
int ret;
struct device *dev = &pdev->dev;
ret = of_property_read_u32(np, "mux-int-port", &int_port);
if (ret) {
dev_err(dev, "mux-int-port missing or invalid\n");
goto fail;
}
if (int_port > MUX_PORT_MAX || int_port == 0) {
dev_err(dev, "mux-int-port: hardware only has %d mux ports\n",
MUX_PORT_MAX);
goto fail;
}
ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
if (ret) {
dev_err(dev, "mux-ext-port missing or invalid\n");
goto fail;
}
if (ext_port > MUX_PORT_MAX || ext_port == 0) {
dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n",
MUX_PORT_MAX);
goto fail;
}
/*
* The port numbering in the hardware manual starts at 1, while
* the audmux API expects it starts at 0.
*/
int_port--;
ext_port--;
ret = imx_audmux_v2_configure_port(int_port,
IMX_AUDMUX_V2_PTCR_SYN |
IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
IMX_AUDMUX_V2_PTCR_TFSDIR |
IMX_AUDMUX_V2_PTCR_TCLKDIR,
IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
if (ret) {
dev_err(dev, "audmux internal port setup failed\n");
return ret;
}
ret = imx_audmux_v2_configure_port(ext_port,
IMX_AUDMUX_V2_PTCR_SYN,
IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
if (ret) {
dev_err(dev, "audmux external port setup failed\n");
return ret;
}
ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
if (!ssi_np || !codec_np) {
dev_err(dev, "phandle missing or invalid\n");
ret = -EINVAL;
goto fail;
}
ssi_pdev = of_find_device_by_node(ssi_np);
if (!ssi_pdev) {
dev_err(dev, "failed to find SSI platform device\n");
ret = -EINVAL;
goto fail;
}
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto fail;
}
data->dev = dev;
data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0);
data->dai.name = "hifi";
data->dai.stream_name = "hifi";
data->dai.codec_dai_name = "es8328-hifi-analog";
data->dai.codec_of_node = codec_np;
data->dai.cpu_of_node = ssi_np;
data->dai.platform_of_node = ssi_np;
data->dai.init = &imx_es8328_dai_init;
data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM;
data->card.dev = dev;
data->card.dapm_widgets = imx_es8328_dapm_widgets;
data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
ret = snd_soc_of_parse_card_name(&data->card, "model");
if (ret) {
dev_err(dev, "Unable to parse card name\n");
goto fail;
}
ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
if (ret) {
dev_err(dev, "Unable to parse routing: %d\n", ret);
goto fail;
}
data->card.num_links = 1;
data->card.owner = THIS_MODULE;
data->card.dai_link = &data->dai;
ret = snd_soc_register_card(&data->card);
if (ret) {
dev_err(dev, "Unable to register: %d\n", ret);
goto fail;
}
platform_set_drvdata(pdev, data);
fail:
of_node_put(ssi_np);
of_node_put(codec_np);
return ret;
}
static int imx_es8328_remove(struct platform_device *pdev)
{
struct imx_es8328_data *data = platform_get_drvdata(pdev);
snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios),
headset_jack_gpios);
snd_soc_unregister_card(&data->card);
return 0;
}
static const struct of_device_id imx_es8328_dt_ids[] = {
{ .compatible = "fsl,imx-audio-es8328", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids);
static struct platform_driver imx_es8328_driver = {
.driver = {
.name = "imx-es8328",
.of_match_table = imx_es8328_dt_ids,
},
.probe = imx_es8328_probe,
.remove = imx_es8328_remove,
};
module_platform_driver(imx_es8328_driver);
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:imx-audio-es8328");
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