Skip to contentSkip to conversation

sound/soc/codecs: add LAPIS Semiconductor ML26124

PATCH Superseded Tomoya MORINAGA 2 participants 17 messages Dec 20, 2011 – Dec 27, 2011

Subsystems (2)

v5 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

PATCH v5 1/3 sound/soc/codecs: add LAPIS Semiconductor ML26124

ML26124-01HB/ML26124-02GD is 16bit monaural audio CODEC which has high resistance to voltage noise. On chip regulator realizes power supply rejection ratio be over 90dB so more than 50dB is improved than ever. ML26124-01HB/ ML26124-02GD can deliver stable audio performance without being affected by noise from the power supply circuit and peripheral components. The chip also includes a composite video signal output, which can be applied to various portable device
requirements. The ML26124 is realized these functions into very small package
the size is only 2.56mm x 2.46mm therefore can be construct high quality sound system easily.
ML26124-01HB is 25pin WCSP package; ML26124-02GD is 32pin WQFN package.

---
V5: Add clock setting processing

---
 sound/soc/codecs/Kconfig   |    4 +
 sound/soc/codecs/Makefile  |    1 +
 sound/soc/codecs/ml26124.c |  594 ++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/ml26124.h |  129 ++++++++++
 4 files changed, 728 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/ml26124.c
 create mode 100644 sound/soc/codecs/ml26124.h
sound/soc/codecs/Kconfig +4 -0
index 7c205e7..2b4435f 100644
@@ -41,6 +41,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX9850 if I2C
 	select SND_SOC_MAX9877 if I2C
+	select SND_SOC_ML26124 if I2C
 	select SND_SOC_PCM3008
 	select SND_SOC_RT5631 if I2C
 	select SND_SOC_SGTL5000 if I2C
@@ -224,6 +225,9 @@ config SND_SOC_MAX98095
 config SND_SOC_MAX9850
 	tristate
 
+config SND_SOC_ML26124
+	tristate
+
 config SND_SOC_PCM3008
        tristate
 
sound/soc/codecs/Makefile +1 -0
index 9aa6e66..22adcbd 100644
@@ -28,6 +28,7 @@ snd-soc-lm4857-objs := lm4857.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
+snd-soc-ml26124-objs := ml26124.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-sgtl5000-objs := sgtl5000.o
sound/soc/codecs/ml26124.c new file +594 -0

594 lines not on this page · raw message

sound/soc/codecs/ml26124.h new file +129 -0

129 lines not on this page · raw message

Signature · 1 line
1.7.4.4
#1 lore raw

PATCH v4 2/3 sound/soc/lapis: add machine driver for ML7213 Carrier Board

This driver is for LAPIS Semiconductor ML7213 Carrier Board. This driver controls ML26124 CODEC and ML7213 IOH I2S.

---
V4
- Add MCLKFS / BCLKFS processing
- Delete ml7213_ioh_init

---
 sound/soc/Kconfig                   |    1 +
 sound/soc/Makefile                  |    1 +
 sound/soc/lapis/Kconfig             |    5 +
 sound/soc/lapis/Makefile            |    4 +
 sound/soc/lapis/ml7213ioh-machine.c |  214 +++++++++++++++++++++++++++++++++++
 5 files changed, 225 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/lapis/Kconfig
 create mode 100644 sound/soc/lapis/Makefile
 create mode 100644 sound/soc/lapis/ml7213ioh-machine.c
sound/soc/Kconfig +1 -0
index 35e662d..63f8582 100644
@@ -34,6 +34,7 @@ source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/imx/Kconfig"
 source "sound/soc/jz4740/Kconfig"
+source "sound/soc/lapis/Kconfig"
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/kirkwood/Kconfig"
sound/soc/Makefile +1 -0
index 9ea8ac8..002951f 100644
@@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC)	+= ep93xx/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)	+= jz4740/
+obj-$(CONFIG_SND_SOC)   += lapis/
 obj-$(CONFIG_SND_SOC)	+= mid-x86/
 obj-$(CONFIG_SND_SOC)	+= mxs/
 obj-$(CONFIG_SND_SOC)	+= nuc900/
sound/soc/lapis/Kconfig new file +5 -0
new file mode 100644
index 0000000..f6c2fe5
@@ -0,0 +1,5 @@
+config SND_SOC_ML7213_MACHINE
+	tristate "ML7213 IOH ASoC machine driver"
+	select SND_SOC_ML7213_PLATFORM
+	help
+	  This is ASoC machine driver for ML7213 IOH
sound/soc/lapis/Makefile new file +4 -0
new file mode 100644
index 0000000..cdb196a
@@ -0,0 +1,4 @@
+# Platform
+snd-soc-ml7213-machine-objs := ml7213ioh-machine.o
+
+obj-$(CONFIG_SND_SOC_ML7213_MACHINE) += snd-soc-ml7213-machine.o
sound/soc/lapis/ml7213ioh-machine.c new file +214 -0

214 lines not on this page · raw message

Signature · 1 line
1.7.4.4
#2 lore raw

Re: [PATCH 2/3 v4] sound/soc/lapis: add machine driver for ML7213 Carrier Board

sound/soc/lapis/ml7213ioh-machine.c line 56

Quoted 10 lines · Tomoya MORINAGA
sound/soc/lapis/ml7213ioh-machine.c new file +10 -0
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	unsigned int clk = 0;
+	int ret = 0;
+	int bclkfs;
+	int mclkfs;
+	int rate = params_rate(hw_params);

The coding style here is really odd, looks like you're mixing declarations and code.

sound/soc/lapis/ml7213ioh-machine.c line 81

Quoted 4 lines
sound/soc/lapis/ml7213ioh-machine.c new file +4 -0
+	default:
+		pr_err("%s: Failed not support format\n", __func__);
+		return -1;
+		break;

Return sensible error codes and there's no reason for the break after the return.

Quoted 37 lines
sound/soc/lapis/ml7213ioh-machine.c new file +37 -0
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_BCLKFS0, bclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_BCLKFS1, bclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_BCLKFS2, bclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_BCLKFS3, bclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_BCLKFS4, bclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_BCLKFS5, bclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_MCLKFS0, mclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_MCLKFS1, mclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_MCLKFS2, mclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_MCLKFS3, mclkfs);

sound/soc/lapis/ml7213ioh-machine.c line 136

Quoted 10 lines
sound/soc/lapis/ml7213ioh-machine.c new file +10 -0
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_MCLKFS4, mclkfs);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ML7213IOH_MCLKFS5, mclkfs);
+	if (ret < 0)
+		return ret;

This looks like the CODEC driver ought to be working these things out for itself rather than having every machine using the device know about these dividers.

You're also still missing the drivers for the CPU...

#3 lore raw

PATCH v2 3/3 sound/soc/lapis: add platform driver for ML7213 IOH I2S

In reply to Tomoya MORINAGA

---
V2
- Delete unused module_param "index"
- Re-desing data structure. So, some internal functions interface are changed
- Add dai interface functions (Includes format, sysclk, clkdiv)
- Delete snd_device_new, snd_card_create snd_card_register

---
 sound/soc/lapis/Kconfig          |    5 +
 sound/soc/lapis/Makefile         |    2 +
 sound/soc/lapis/ioh_i2s.h        |   39 +
 sound/soc/lapis/ml7213ioh-plat.c | 2033 ++++++++++++++++++++++++++++++++++++++
 sound/soc/lapis/ml7213ioh-plat.h |  583 +++++++++++
 5 files changed, 2662 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/lapis/ioh_i2s.h
 create mode 100644 sound/soc/lapis/ml7213ioh-plat.c
 create mode 100644 sound/soc/lapis/ml7213ioh-plat.h
sound/soc/lapis/Kconfig +5 -0
index f6c2fe5..e10e729 100644
@@ -1,3 +1,8 @@
+config SND_SOC_ML7213_PLATFORM
+	tristate "ML7213 IOH ASoC platform driver"
+	help
+	  This option enables support for the AC Link Controllers in ML7213 IOH SoC.
+
 config SND_SOC_ML7213_MACHINE
 	tristate "ML7213 IOH ASoC machine driver"
 	select SND_SOC_ML7213_PLATFORM
sound/soc/lapis/Makefile +2 -0
index cdb196a..812290b 100644
@@ -1,4 +1,6 @@
 # Platform
 snd-soc-ml7213-machine-objs := ml7213ioh-machine.o
+snd-soc-ml7213-plat-objs := ml7213ioh-plat.o
 
 obj-$(CONFIG_SND_SOC_ML7213_MACHINE) += snd-soc-ml7213-machine.o
+obj-$(CONFIG_SND_SOC_ML7213_PLATFORM) += snd-soc-ml7213-plat.o
sound/soc/lapis/ioh_i2s.h new file +39 -0
new file mode 100644
index 0000000..9f19f70
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef ML7213_IOH_I2S
+#define ML7213_IOH_I2S
+
+enum ioh_bclkfs {
+	ML7213IOH_BCLKFS0 = 0,
+	ML7213IOH_BCLKFS1,
+	ML7213IOH_BCLKFS2,
+	ML7213IOH_BCLKFS3,
+	ML7213IOH_BCLKFS4,
+	ML7213IOH_BCLKFS5,
+};
+
+enum ioh_mclkfs {
+	ML7213IOH_MCLKFS0 = 6,
+	ML7213IOH_MCLKFS1,
+	ML7213IOH_MCLKFS2,
+	ML7213IOH_MCLKFS3,
+	ML7213IOH_MCLKFS4,
+	ML7213IOH_MCLKFS5,
+};
+
+#endif
sound/soc/lapis/ml7213ioh-plat.c new file +2033 -0

2,033 lines not on this page · raw message

sound/soc/lapis/ml7213ioh-plat.h new file +583 -0

583 lines not on this page · raw message

Signature · 1 line
1.7.4.4
#4 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

sound/soc/lapis/ml7213ioh-plat.c line 40

Quoted 3 lines · Tomoya MORINAGA
sound/soc/lapis/ml7213ioh-plat.c new file +3 -0
+static int ignore_overrun = 1;
+module_param(ignore_overrun, int, 0444);
+MODULE_PARM_DESC(ignore_overrun, "ignore RX overruns (default=0)");

This shouldn't be a driver specific thing, and if we were to have such a feature a module parameter doesn't seem like a great way of doing it.

Quoted 3 lines

+/*****************************************************************************
+ * I2S HAL (Hardware Abstruction Layer)
+ *****************************************************************************/

Please follow the kernel coding style in terms of comments.

sound/soc/lapis/ml7213ioh-plat.c line 59

Quoted 9 lines
sound/soc/lapis/ml7213ioh-plat.c new file +9 -0
+static void ioh_i2s_enable_interrupts(int ch, enum dma_data_direction dir)
+{
+	unsigned int intr_lines;
+
+	if (dir)
+		intr_lines = 1 << (I2S_IMASK_RX_BIT_START + ch);
+
+	else
+		intr_lines = 1 << (I2S_IMASK_TX_BIT_START + ch);

I'd expect a switch statement corresponding to the enum, not an if statement.

sound/soc/lapis/ml7213ioh-plat.c line 70

Quoted 6 lines
sound/soc/lapis/ml7213ioh-plat.c new file +6 -0
+static void ioh_i2s_disable_interrupts(int ch, enum dma_data_direction dir)
+{
+	unsigned int intr_lines;
+
+	/*intr_lines&=I2S_ALL_INTERRUPT_BITS; */
+	intr_lines = ioread32(i2s_data->iobase + I2SIMASK_OFFSET);

What's this commented out code for? Also as a coding style thing you should have a space between /* and the text in the comment (this applies throughout the driver).

sound/soc/lapis/ml7213ioh-plat.c line 79

Quoted 8 lines
sound/soc/lapis/ml7213ioh-plat.c new file +8 -0
+	/*disable interrupts for specified channel */
+	if (dir)
+		intr_lines |= 1 << (I2S_IMASK_RX_BIT_START + ch);
+	else
+		intr_lines |= 1 << (I2S_IMASK_TX_BIT_START + ch);
+
+	/*Mask the specific interrupt bits */
+	iowrite32(intr_lines, i2s_data->iobase + I2SIMASK_OFFSET);

What ensures that this read/modify/write cycle can't race with another caller?

sound/soc/lapis/ml7213ioh-plat.c line 113

Quoted 8 lines
sound/soc/lapis/ml7213ioh-plat.c new file +8 -0
+/* Clear interrupt status */
+static void ioh_i2s_clear_tx_sts_ir(int ch)
+{
+	int offset = ch * 0x800;
+
+	iowrite32(I2S_TX_FINT | I2S_TX_AFINT | I2S_TX_EINT | I2S_TX_AEINT,
+		i2s_data->iobase + I2SISTTX_OFFSET + offset);
+}

This appears to unconditionally acknowledge all interrupts, generally you should only acknowledge interrupts that have been handled. Otherwise it's possible that interrupts may be dropped if they're flagged between the status read and acknowledgement write.

Quoted 3 lines

+/*****************************************************************************
+ * I2S Middle ware
+ *****************************************************************************/

I'm really not convinced of the value of these layers, reading the code it really feels incredibly verbose in comparison with what I'd expect from such a driver and I can't help that think that a lot of this verbosity is down to muddling through these abstraction layers.

Quoted 1 line

+static bool filter(struct dma_chan *chan, void *slave)

This needs a better name. It's not namespaced and it's not clear what it's filtering.

sound/soc/lapis/ml7213ioh-plat.c line 247

Quoted 13 lines
sound/soc/lapis/ml7213ioh-plat.c new file +13 -0
+static struct dma_chan *ioh_request_dma_channel(
+		   int ch, struct ioh_i2s_dma *dma, enum dma_data_direction dir)
+{
+	dma_cap_mask_t mask;
+	struct dma_chan *chan;
+	struct pci_dev *dma_dev;
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0, 1)); /* Get DMA's dev
+								information */
+
+	if (dir == DMA_FROM_DEVICE) { /* Rx */

switch statement to select between multiple options in the enum. This applies throughout the code.

sound/soc/lapis/ml7213ioh-plat.c line 293

Quoted 5 lines
sound/soc/lapis/ml7213ioh-plat.c new file +5 -0
+static void
+ioh_i2s_write(struct snd_pcm_substream *substream, const void *data, int len)
+{
+	int rem1;
+	int rem2;

What is this supposed to do? There's an awful lot of it, and it looks like it's supposed to be rewriting the data format for some reason which isn't something that a driver ought to be doing (apart from anything else it does rather defeat the point of DMA).

sound/soc/lapis/ml7213ioh-plat.c line 429

Quoted 3 lines
sound/soc/lapis/ml7213ioh-plat.c new file +3 -0
+static void ioh_i2s_configure_i2s_regs(int ch, enum ioh_direction dir)
+{
+	int offset = ch * 0x800;

You should have a function to map the channel into a number.

sound/soc/lapis/ml7213ioh-plat.c line 437

Quoted 8 lines
sound/soc/lapis/ml7213ioh-plat.c new file +8 -0
+
+	if (dir) {
+		/* Rx register */
+		iowrite32(I2S_AFULL_THRESH / 2,
+			  i2s_data->iobase + I2SAFRX_OFFSET + offset);
+		iowrite32(0x1F, i2s_data->iobase + I2SAERX_OFFSET + offset);
+		iowrite32(0x1F, i2s_data->iobase + I2SMSKRX_OFFSET + offset);
+		iowrite32(0xC, i2s_data->iobase + I2SISTRX_OFFSET + offset);

Lots of magic numbers here and given that the function is called just "configure" it's not clear what the intended purpose is. This needs to be clarified.

Quoted 3 lines
sound/soc/lapis/ml7213ioh-plat.c new file +3 -0
+		/* Rx configuration */
+		if (atomic_read(&dma->rx_busy)) {
+			dev_err(i2s_data->dev, "rx i2s%dalready opened\n", ch);

...

sound/soc/lapis/ml7213ioh-plat.c line 663

Quoted 3 lines
sound/soc/lapis/ml7213ioh-plat.c new file +3 -0
+	} else {
+		/* Tx configuration */
+		if (atomic_read(&dma->tx_busy)) {

There's a *lot* of duplicate code in the driver for TX and RX, it should be possible to abstract out much more common code.

sound/soc/lapis/ml7213ioh-plat.c line 924

Quoted 13 lines
sound/soc/lapis/ml7213ioh-plat.c new file +13 -0
+static void i2s_tx_almost_empty_ir(int ch)
+{
+	struct dma_async_tx_descriptor *desc;
+	int num;
+	int tx_comp_index;
+	struct ioh_i2s_dma *dma = &dmadata[ch];
+	struct scatterlist *sg = dma->sg_tx_p;
+	void *cb_ch;
+
+	dev_dbg(i2s_data->dev, "%s: data_head=%p data_complete=%p\n", __func__,
+		dma->tx_data_head, dma->tx_complete);
+
+	num = ((int)dma->tx_avail) / (I2S_AEMPTY_THRESH * 4);

That case looks *very* suspect.

sound/soc/lapis/ml7213ioh-plat.c line 927

Quoted 2 lines
sound/soc/lapis/ml7213ioh-plat.c new file +2 -0
+	tx_comp_index = (((int)(dma->tx_complete - dma->tx_head))) /\
+			(I2S_AEMPTY_THRESH * 4);

There is very rarely any need for line continuations outside of macros.

sound/soc/lapis/ml7213ioh-plat.c line 992

Quoted 10 lines
sound/soc/lapis/ml7213ioh-plat.c new file +10 -0
+static inline void ioh_i2s_interrupt_sub_tx(int ch)
+{
+	unsigned int status;
+	int offset = ch * 0x800;
+
+	status = ioread32(i2s_data->iobase + I2SISTTX_OFFSET + offset);
+	if (status & I2S_TX_EINT)
+		i2s_tx_empty_ir(ch);
+	if (status & I2S_TX_AEINT)
+		i2s_tx_almost_empty_ir(ch);

Given that all you're doing is logging just open code the log message.

Review

Quoted 2 lines
(quoted diff) +2 -0
+	default:
+		return -1;

Return error codes, you EPERM almost certainly isn't the error you meant to report.

sound/soc/lapis/ml7213ioh-plat.c line 1937

Quoted 5 lines
sound/soc/lapis/ml7213ioh-plat.c new file +5 -0
+static int ioh_i2s_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	int ret;
+
+	ioh_i2s_save_reg_conf(pdev);

You should be doing this in ASoC suspend/resume callbacks, not in PCI ones.

#5 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

2011/12/20 Mark Brown <[email protected]>:

Quoted 8 lines · Tomoya MORINAGA

sound/soc/lapis/ml7213ioh-plat.c line 40

Quoted 4 lines
sound/soc/lapis/ml7213ioh-plat.c new file +3 -0
+static int ignore_overrun = 1;
+module_param(ignore_overrun, int, 0444);
+MODULE_PARM_DESC(ignore_overrun, "ignore RX overruns (default=0)");

This shouldn't be a driver specific thing, and if we were to have such a feature a module parameter doesn't seem like a great way of doing it.

I'll delete this parameter.

Quoted 6 lines
Quoted 4 lines

+/*****************************************************************************
+ *   I2S HAL (Hardware Abstruction Layer)
+ *****************************************************************************/

Please follow the kernel coding style in terms of comments.

I' ll modify this.

Quoted 13 lines

sound/soc/lapis/ml7213ioh-plat.c line 59

Quoted 10 lines
sound/soc/lapis/ml7213ioh-plat.c new file +9 -0
+static void ioh_i2s_enable_interrupts(int ch, enum dma_data_direction dir)
+{
+     unsigned int intr_lines;
+
+     if (dir)
+             intr_lines = 1 << (I2S_IMASK_RX_BIT_START + ch);
+
+     else
+             intr_lines = 1 << (I2S_IMASK_TX_BIT_START + ch);

I'd expect a switch statement corresponding to the enum, not an if statement.

"if" will replace "switch".

Quoted 11 lines

sound/soc/lapis/ml7213ioh-plat.c line 70

Quoted 7 lines
sound/soc/lapis/ml7213ioh-plat.c new file +6 -0
+static void ioh_i2s_disable_interrupts(int ch, enum dma_data_direction dir)
+{
+     unsigned int intr_lines;
+
+     /*intr_lines&=I2S_ALL_INTERRUPT_BITS; */
+     intr_lines = ioread32(i2s_data->iobase + I2SIMASK_OFFSET);

What's this commented out code for?  Also as a coding style thing you should have a space between /* and the text in the comment (this applies throughout the driver).

I'll delete.

Quoted 10 lines
Quoted 9 lines

+     /*disable interrupts for specified channel */
+     if (dir)
+             intr_lines |= 1 << (I2S_IMASK_RX_BIT_START + ch);
+     else
+             intr_lines |= 1 << (I2S_IMASK_TX_BIT_START + ch); +
+     /*Mask the specific interrupt bits */
+     iowrite32(intr_lines, i2s_data->iobase + I2SIMASK_OFFSET);

Quoted 2 lines

What ensures that this read/modify/write cycle can't race with another caller?

I'll add exclusive processing like spin-lock.

Quoted 14 lines

sound/soc/lapis/ml7213ioh-plat.c line 113

Quoted 9 lines
sound/soc/lapis/ml7213ioh-plat.c new file +8 -0
+/* Clear interrupt status */
+static void ioh_i2s_clear_tx_sts_ir(int ch)
+{
+     int offset = ch * 0x800;
+
+     iowrite32(I2S_TX_FINT | I2S_TX_AFINT | I2S_TX_EINT | I2S_TX_AEINT,
+             i2s_data->iobase + I2SISTTX_OFFSET + offset);
+}

This appears to unconditionally acknowledge all interrupts, generally you should only acknowledge interrupts that have been handled. Otherwise it's possible that interrupts may be dropped if they're flagged between the status read and acknowledgement write.

I can understand your saying.
If following your saying, only called by i2s_dma_tx_complete is enough.

However I think adding clearing interrupt status at both before and after i2s communicating start/finish is better.

Quoted 10 lines
Quoted 4 lines

+/*****************************************************************************
+ *   I2S Middle ware
+ *****************************************************************************/

I'm really not convinced of the value of these layers, reading the code it really feels incredibly verbose in comparison with what I'd expect from such a driver and I can't help that think that a lot of this verbosity is down to muddling through these abstraction layers.

Quoted 4 lines
Quoted 1 line

+static bool filter(struct dma_chan *chan, void *slave)

This needs a better name.  It's not namespaced and it's not clear what it's filtering.

In case of using Linux standard DMA API, function "filter" is the most popular name.
Almost drivers which use standard use "filter".

Quoted 17 lines
Quoted 4 lines
sound/soc/lapis/ml7213ioh-plat.c new file +3 -0
+static struct dma_chan *ioh_request_dma_channel(
+                int ch, struct ioh_i2s_dma *dma, enum dma_data_direction dir)
+{

sound/soc/lapis/ml7213ioh-plat.c line 247

Quoted 10 lines
sound/soc/lapis/ml7213ioh-plat.c new file +10 -0
+     dma_cap_mask_t mask;
+     struct dma_chan *chan;
+     struct pci_dev *dma_dev;
+     dma_cap_zero(mask);
+     dma_cap_set(DMA_SLAVE, mask);
+
+     dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0, 1)); /* Get DMA's dev
+                                                             information */
+
+     if (dir == DMA_FROM_DEVICE) { /* Rx */

switch statement to select between multiple options in the enum.  This applies throughout the code.

"if" will replace "switch".

Quoted 11 lines

sound/soc/lapis/ml7213ioh-plat.c line 293

Quoted 6 lines
sound/soc/lapis/ml7213ioh-plat.c new file +5 -0
+static void
+ioh_i2s_write(struct snd_pcm_substream *substream, const void *data, int len)
+{
+     int rem1;
+     int rem2;

What is this supposed to do?  There's an awful lot of it, and it looks like it's supposed to be rewriting the data format for some reason which isn't something that a driver ought to be doing (apart from anything else it does rather defeat the point of DMA).

This driver has buffer which is for preventing noisy sound by jitter So, this buffer is variable.

Quoted 6 lines

sound/soc/lapis/ml7213ioh-plat.c line 429

Quoted 4 lines
sound/soc/lapis/ml7213ioh-plat.c new file +3 -0
+static void ioh_i2s_configure_i2s_regs(int ch, enum ioh_direction dir)
+{
+     int offset = ch * 0x800;

You should have a function to map the channel into a number.

understand.

Quoted 10 lines
Quoted 9 lines

+
+     if (dir) {
+             /* Rx register */
+             iowrite32(I2S_AFULL_THRESH / 2,
+                       i2s_data->iobase + I2SAFRX_OFFSET + offset);
+             iowrite32(0x1F, i2s_data->iobase + I2SAERX_OFFSET + offset);
+             iowrite32(0x1F, i2s_data->iobase + I2SMSKRX_OFFSET + offset);
+             iowrite32(0xC, i2s_data->iobase + I2SISTRX_OFFSET + offset);

Quoted 3 lines

Lots of magic numbers here and given that the function is called just "configure" it's not clear what the intended purpose is.  This needs to be clarified.

understand.

Quoted 5 lines
Quoted 4 lines

+             /* Rx configuration */
+             if (atomic_read(&dma->rx_busy)) {
+                     dev_err(i2s_data->dev, "rx i2s%dalready opened\n", ch);

Quoted 8 lines

...

Quoted 3 lines

+     } else {
+             /* Tx configuration */
+             if (atomic_read(&dma->tx_busy)) {

There's a *lot* of duplicate code in the driver for TX and RX, it should be possible to abstract out much more common code.

I'll study.

Quoted 16 lines
Quoted 4 lines
sound/soc/lapis/ml7213ioh-plat.c new file +3 -0
+static void i2s_tx_almost_empty_ir(int ch)
+{
+     struct dma_async_tx_descriptor *desc;

sound/soc/lapis/ml7213ioh-plat.c line 924

Quoted 10 lines
sound/soc/lapis/ml7213ioh-plat.c new file +10 -0
+     int num;
+     int tx_comp_index;
+     struct ioh_i2s_dma *dma = &dmadata[ch];
+     struct scatterlist *sg = dma->sg_tx_p;
+     void *cb_ch;
+
+     dev_dbg(i2s_data->dev, "%s: data_head=%p data_complete=%p\n", __func__,
+             dma->tx_data_head, dma->tx_complete);
+
+     num = ((int)dma->tx_avail) / (I2S_AEMPTY_THRESH * 4);

That case looks *very* suspect.

This is correct.
Why do you think so ?

Quoted 6 lines
Quoted 3 lines

+     tx_comp_index = (((int)(dma->tx_complete - dma->tx_head))) /\
+                     (I2S_AEMPTY_THRESH * 4);

There is very rarely any need for line continuations outside of macros.

Quoted 12 lines

sound/soc/lapis/ml7213ioh-plat.c line 992

Quoted 10 lines
sound/soc/lapis/ml7213ioh-plat.c new file +10 -0
+static inline void ioh_i2s_interrupt_sub_tx(int ch)
+{
+     unsigned int status;
+     int offset = ch * 0x800;
+
+     status = ioread32(i2s_data->iobase + I2SISTTX_OFFSET + offset);
+     if (status & I2S_TX_EINT)
+             i2s_tx_empty_ir(ch);
+     if (status & I2S_TX_AEINT)
+             i2s_tx_almost_empty_ir(ch);

Given that all you're doing is logging just open code the log message.

Understand.

Quoted 6 lines
Quoted 3 lines

+     default:
+             return -1;

Return error codes, you EPERM almost certainly isn't the error you meant to report.

I'll modify.

Quoted 9 lines

sound/soc/lapis/ml7213ioh-plat.c line 1937

Quoted 6 lines
sound/soc/lapis/ml7213ioh-plat.c new file +5 -0
+static int ioh_i2s_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+     int ret;
+
+     ioh_i2s_save_reg_conf(pdev);

You should be doing this in ASoC suspend/resume callbacks, not in PCI ones.

Understand.

thanks,
tomoya

#6 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

Quoted 11 lines · Tomoya MORINAGA

2011/12/20 Mark Brown <[email protected]>:

Quoted 9 lines · Tomoya MORINAGA
Quoted 3 lines

+     iowrite32(I2S_TX_FINT | I2S_TX_AFINT | I2S_TX_EINT | I2S_TX_AEINT,
+             i2s_data->iobase + I2SISTTX_OFFSET + offset);

This appears to unconditionally acknowledge all interrupts, generally you should only acknowledge interrupts that have been handled. Otherwise it's possible that interrupts may be dropped if they're flagged between the status read and acknowledgement write.

Quoted 5 lines

I can understand your saying.
If following your saying, only called by i2s_dma_tx_complete is enough.

However I think adding clearing interrupt status at both before and after i2s communicating start/finish is better.

No, the issue is that you're acknowleding a hard coded set of interrupts, not the interrupts that were actually handled. The ordering isn't really the issue, the issue is that you could acknowledge things that weren't handled. For example:

1. ISR runs, reads status A
2. Condition B happens
3. ISR handles condition A.
4. ISR acknowledges both A and B.

would mean that B would just get ignored.

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

+static bool filter(struct dma_chan *chan, void *slave)

This needs a better name.  It's not namespaced and it's not clear what it's filtering.

In case of using Linux standard DMA API, function "filter" is the most popular name.
Almost drivers which use standard use "filter".

I suspect they may have the filter immediately next to the code that uses it, which certainly isn't the case here.

Quoted 10 lines
Quoted 9 lines

sound/soc/lapis/ml7213ioh-plat.c line 293

Quoted 4 lines
sound/soc/lapis/ml7213ioh-plat.c new file +4 -0
+ioh_i2s_write(struct snd_pcm_substream *substream, const void *data, int len)
+{
+     int rem1;
+     int rem2;

What is this supposed to do?  There's an awful lot of it, and it looks like it's supposed to be rewriting the data format for some reason which isn't something that a driver ought to be doing (apart from anything else it does rather defeat the point of DMA).

Quoted 2 lines

This driver has buffer which is for preventing noisy sound by jitter So, this buffer is variable.

You're implementing some sort of custom buffering in your driver? That sounds terribly unidiomatic - pretty much all DMA drivers are very thin and manage to work well, I'd expect this is masking some problems in the code rather than anything else. Can you provide more detail on what this is working around?

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

+     num = ((int)dma->tx_avail) / (I2S_AEMPTY_THRESH * 4);

That case looks *very* suspect.

This is correct.
Why do you think so ?

I can't tell what it's supposed to do, and casting that isn't super clear especially casting to integer types tends to be a big red flag.

#7 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

2011/12/22 Mark Brown <[email protected]>:

Quoted 23 lines · Tomoya MORINAGA
Quoted 11 lines

2011/12/20 Mark Brown <[email protected]>:

Quoted 9 lines · Tomoya MORINAGA
Quoted 3 lines

+     iowrite32(I2S_TX_FINT | I2S_TX_AFINT | I2S_TX_EINT | I2S_TX_AEINT,
+             i2s_data->iobase + I2SISTTX_OFFSET + offset);

This appears to unconditionally acknowledge all interrupts, generally you should only acknowledge interrupts that have been handled. Otherwise it's possible that interrupts may be dropped if they're flagged between the status read and acknowledgement write.

Quoted 5 lines

I can understand your saying.
If following your saying, only called by i2s_dma_tx_complete is enough.

However I think adding clearing interrupt status at both before and after i2s communicating start/finish is better.

No, the issue is that you're acknowleding a hard coded set of interrupts, not the interrupts that were actually handled.  The ordering isn't really the issue, the issue is that you could acknowledge things that weren't handled.  For example:

Quoted 6 lines

  1. ISR runs, reads status A
  2. Condition B happens
  3. ISR handles condition A.
  4. ISR acknowledges both A and B.

would mean that B would just get ignored.

I can understand your saying.
However, in case of Tx interrupt, only ALMOST-EMPTY occurs. in case of Rx, only Rx ALMOST-FULL occurs.
So as long as a user uses ML7213 I2S, your mentioned behavior is never happened.

Quoted 6 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines

+static bool filter(struct dma_chan *chan, void *slave)

This needs a better name.  It's not namespaced and it's not clear what it's filtering.

Quoted 6 lines
Quoted 3 lines

In case of using Linux standard DMA API, function "filter" is the most popular name.
Almost drivers which use standard use "filter".

I suspect they may have the filter immediately next to the code that uses it, which certainly isn't the case here.

They have the "filter" function immediately next to the code uses "dma_request_channel".
Anyway, if you want me to change the name, I can change the name. Please decide it.

Quoted 11 lines
Quoted 10 lines
Quoted 10 lines

sound/soc/lapis/ml7213ioh-plat.c line 293

Quoted 5 lines
sound/soc/lapis/ml7213ioh-plat.c new file +4 -0
+ioh_i2s_write(struct snd_pcm_substream *substream, const void *data, int len)
+{
+     int rem1;
+     int rem2;

What is this supposed to do?  There's an awful lot of it, and it looks like it's supposed to be rewriting the data format for some reason which isn't something that a driver ought to be doing (apart from anything else it does rather defeat the point of DMA).

Quoted 8 lines
Quoted 2 lines

This driver has buffer which is for preventing noisy sound  by jitter So, this buffer is variable.

You're implementing some sort of custom buffering in your driver?  That sounds terribly unidiomatic - pretty much all DMA drivers are very thin and manage to work well, I'd expect this is masking some problems in the code rather than anything else.  Can you provide more detail on what this is working around?

Not sorted but queuing only.
In sound/voice control system, queuing is not rare, I think. If necessary, though this method is very common, I can send the method of the queue.

Quoted 10 lines
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

+     num = ((int)dma->tx_avail) / (I2S_AEMPTY_THRESH * 4);

That case looks *very* suspect.

This is correct.
Why do you think so ?

I can't tell what it's supposed to do, and casting that isn't super clear especially casting to integer types tends to be a big red flag.

Currently, "tx_avail" is "int" type. So, "(int)" is redundant. Maybe, once type of "tx_avail" is not "int" but something pointer type. I'll modify like below.
num = dma->tx_avail / (I2S_AEMPTY_THRESH * 4);

thanks,
tomoya

#8 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

Quoted 4 lines · Tomoya MORINAGA

I can understand your saying.
However, in case of Tx interrupt, only ALMOST-EMPTY occurs. in case of Rx, only Rx ALMOST-FULL occurs.
So as long as a user uses ML7213 I2S, your mentioned behavior is never happened.

That's not what your code says... it may be that the other interrupts are very rare but that's not the same thing.

Quoted 2 lines

They have the "filter" function immediately next to the code uses "dma_request_channel".

That's a rather large function...

Quoted 2 lines

Anyway, if you want me to change the name, I can change the name. Please decide it.

Rename.

Quoted 10 lines
Quoted 5 lines

You're implementing some sort of custom buffering in your driver?  That sounds terribly unidiomatic - pretty much all DMA drivers are very thin and manage to work well, I'd expect this is masking some problems in the code rather than anything else.  Can you provide more detail on what this is working around?

Not sorted but queuing only.
In sound/voice control system, queuing is not rare, I think. If necessary, though this method is very common, I can send the method of the queue.

No, please describe the problem you're trying to fix. If nothing else think about what you're saying here - if this is a common need then it's something that's going to be handled in generic code, not open coded in individual drivers. Like I say I would expect that you have problems elsewhere in your code which you are masking with this.

#9 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

2011/12/22 Mark Brown <[email protected]>:

Quoted 9 lines · Tomoya MORINAGA
Quoted 5 lines

I can understand your saying.
However, in case of Tx interrupt, only ALMOST-EMPTY occurs. in case of Rx, only Rx ALMOST-FULL occurs.
So as long as a user uses ML7213 I2S, your mentioned behavior is never happened.

That's not what your code says...  it may be that the other interrupts are very rare but that's not the same thing.

I'll delete these except initialize() and transfer_complete().

Quoted 10 lines
Quoted 3 lines

They have the "filter" function immediately next to the code uses "dma_request_channel".

That's a rather large function...

Quoted 2 lines

Anyway, if you want me to change the name, I can change the name. Please decide it.

Rename.

I'll obey your opinion.

Quoted 7 lines
Quoted 6 lines
Quoted 6 lines

You're implementing some sort of custom buffering in your driver?  That sounds terribly unidiomatic - pretty much all DMA drivers are very thin and manage to work well, I'd expect this is masking some problems in the code rather than anything else.  Can you provide more detail on what this is working around?

Quoted 6 lines
Quoted 4 lines

Not sorted but queuing only.
In sound/voice control system, queuing is not rare, I think. If necessary, though this method is very common, I can send the method of the queue.

No, please describe the problem you're trying to fix.

When CPU is heavy load, this buffer is useful. The heavy load causes delaying receiving processing. If there is no buffer, stream sound/voice can be broken. If there is the buffer, it can prevent the broken sound.

thanks,
tomoya

#10 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

Quoted 7 lines · Tomoya MORINAGA

2011/12/22 Mark Brown <[email protected]>:

Quoted 4 lines
Quoted 4 lines

Not sorted but queuing only.
In sound/voice control system, queuing is not rare, I think. If necessary, though this method is very common, I can send the method of the queue.

Quoted 6 lines
Quoted 1 line

No, please describe the problem you're trying to fix.

When CPU is heavy load, this buffer is useful. The heavy load causes delaying receiving processing. If there is no buffer, stream sound/voice can be broken. If there is the buffer, it can prevent the broken sound.

So you're just talking about standard underflows if the application can't keep up? There's *no* reason for your driver to do anything about this, it's a really basic thing that affects all audio hardware. Just write a driver for the hardware.

#11 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

2011/12/26 Mark Brown <[email protected]>:

Quoted 10 lines · Tomoya MORINAGA
Quoted 8 lines

2011/12/22 Mark Brown <[email protected]>:

Quoted 6 lines
Quoted 4 lines

Not sorted but queuing only.
In sound/voice control system, queuing is not rare, I think. If necessary, though this method is very common, I can send the method of the queue.

No, please describe the problem you're trying to fix.

Quoted 7 lines
Quoted 4 lines

When CPU is heavy load, this buffer is useful. The heavy load causes delaying receiving processing. If there is no buffer, stream sound/voice can be broken. If there is the buffer, it can prevent the broken sound.

So you're just talking about standard underflows if the application can't keep up?

No. not only underflow but overflow.

Quoted 3 lines

There's *no* reason for your driver to do anything about this, it's a really basic thing that affects all audio hardware.  Just write a driver for the hardware.

In case driver layer doesn't have the function,
which part works for the under/overflow ? Application ? or nothing ?

tomoya

#12 lore raw

Re: [PATCH 3/3 v2] sound/soc/lapis: add platform driver for ML7213 IOH I2S

Quoted 6 lines · Tomoya MORINAGA

2011/12/26 Mark Brown <[email protected]>:

Quoted 2 lines

So you're just talking about standard underflows if the application can't keep up?

No. not only underflow but overflow.

Same difference.

Quoted 6 lines
Quoted 3 lines

There's *no* reason for your driver to do anything about this, it's a really basic thing that affects all audio hardware.  Just write a driver for the hardware.

In case driver layer doesn't have the function,
which part works for the under/overflow ? Application ? or nothing ?

Your driver has to accurately describe what the hardware supports and then the application layer is responsible for making sure it keeps up with things.

#13 lore raw
In reply to Tomoya MORINAGA

sound/soc/codecs/ml26124.c line 417

Quoted 7 lines · Tomoya MORINAGA
sound/soc/codecs/ml26124.c new file +7 -0
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* VMID ON */
+		snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+				    ML26124_VMID, ML26124_VMID);
+		msleep(500);
+	case SND_SOC_BIAS_PREPARE:

You're missing a break here.

sound/soc/codecs/ml26124.c line 441

Quoted 10 lines
sound/soc/codecs/ml26124.c new file +10 -0
+static int ml26124_pcm_trigger(struct snd_pcm_substream *substream,
+			      int cmd, struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+		snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, 0x3, 0);
+		return 0;
+	} else if (cmd == SNDRV_PCM_TRIGGER_START) {
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)

Use switch statements, though frankly I'd be astonished if this code actually runs as the trigger() callback is called in atomic context and the register I/O functionality needs interrupts. How have you tested this code?

sound/soc/codecs/ml26124.c line 528

Quoted 3 lines
sound/soc/codecs/ml26124.c new file +3 -0
+	.reg_cache_size = ML26134_CACHESIZE,
+	.reg_word_size = sizeof(u8),
+	.reg_cache_default = ml26124_reg,

New drivers really should use regmap rather than the ASoC cache code.

#14 lore raw

2011/12/20 Mark Brown <[email protected]>:

Quoted 1 line

How have you tested this code?

No, I haven't tested at all. (Of course, I tested before ASoC.) I'll test the new these drivers after you say "Roughly, how to use ASoC framework is OK"

thanks,
tomoya

#15 lore raw
Quoted 7 lines · Tomoya MORINAGA

2011/12/20 Mark Brown <[email protected]>:

Quoted 1 line

How have you tested this code?

No, I haven't tested at all. (Of course, I tested before ASoC.) I'll test the new these drivers after you say "Roughly, how to use ASoC framework is OK"

Don't do this unless you really have to, and if for some reason it's needed or useful then indicate that this is what you're doing. People shouldn't be finding issues on review that mean that the code will never run. If the testing is very light that's fine but you need to make some effort to verify that things will work.

#16 lore raw
In reply to Tomoya MORINAGA

sound/soc/codecs/ml26124.c line 122

Quoted 1 line · Tomoya MORINAGA
sound/soc/codecs/ml26124.c new file +1 -0
+	SND_SOC_DAPM_MICBIAS("MICBIAS", ML26124_PW_REF_PW_MNG, 0, 0),

You should use a supply widget for MICBIAS, the specific widget type is legacy.