RE: [PATCH 2/2] omap: zoom: Move new code introduced by ASoC m-c to board-zoom-peripherals

2010-10-01 Thread Lopez Cruz, Misael
 Liam Girdwood wrote:
  On Fri, 2010-09-24 at 11:31 -0500, Lopez Cruz, Misael wrote:
   Hi Jarkko,
  
ASoC Multi-Component Support moves some code from
sound/soc/omap/zoom2.c
into
arch/arm/mach-omap2/board-zoom2.c. However, that code should go to
board-zoom-peripherals.c instead as there is common code and
registration
for zoom boards.
   
Signed-off-by: Jarkko Nikula jhnik...@gmail.com
Cc: Vikram Pandita vikram.pand...@ti.com
Cc: Lopez Cruz, Misael x0052...@ti.com
Cc: Jorge Eduardo Candelaria jorge.candela...@ti.com
Cc: Tony Lindgren t...@atomide.com
---
I don't have this HW so not tested.
   Tested on zoom2 using the 2 patches of your series, compilation break
 is
   gone and audio works fine.
  
   Thanks,
   -Misael
 
  Applied, and manually added your Tested-by:
 
  Thanks
 
  Liam
 
 Misael, Liam,
 
 Sorry I noticed this patch only now. I have a minor comment on the patch:
 
 Specifically, the part below
 
 + if (machine_is_omap_zoom2()) {
 + zoom_audio_data.ramp_delay_value = 3;   /* 161 ms */
 + zoom_audio_data.hs_extmute = 1;
 + zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
 + }
 
 Isn't the audio on a zoom2/zoom3/3630 SDP the same? (Or at least the
 same on a zoom2 and zoom3)?
Yes, at least zoom2 and zoom3 are the same for audio. 

 If so, we could probably get rid of the
 machine_is_omap_zoom2() check, right?
I think it'd better to add checks for the machines supported by the
driver, so it fails nicely with unsupported ones. I'll go thru the
differences between our boards and send a patch soon.

 - Anand

Thanks,
-Misa
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 2/2] omap: zoom: Move new code introduced by ASoC m-c to board-zoom-peripherals

2010-09-24 Thread Lopez Cruz, Misael
Hi Jarkko,

 ASoC Multi-Component Support moves some code from sound/soc/omap/zoom2.c
 into
 arch/arm/mach-omap2/board-zoom2.c. However, that code should go to
 board-zoom-peripherals.c instead as there is common code and registration
 for zoom boards.
 
 Signed-off-by: Jarkko Nikula jhnik...@gmail.com
 Cc: Vikram Pandita vikram.pand...@ti.com
 Cc: Lopez Cruz, Misael x0052...@ti.com
 Cc: Jorge Eduardo Candelaria jorge.candela...@ti.com
 Cc: Tony Lindgren t...@atomide.com
 ---
 I don't have this HW so not tested.
Tested on zoom2 using the 2 patches of your series, compilation break is
gone and audio works fine.

Thanks,
-Misael
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [alsa-devel] [PATCHv3 1/7] OMAP4: PMIC: Add support for twl6030 codec

2009-10-07 Thread Lopez Cruz, Misael
Krishnamoorthy, Balaji T wrote:

 CONFIG_TWL6030_CORE and CONFIG_TWL4030_CORE is merged to
 CONFIG_TWL_CORE As two different build config was not encouraged. 
 Now switch twl_class_is_6030() will be used to decide at runtime time
 to support for 6030 related drivers, Similarly twl_class_is_4030()
 for 4030 drivers 

In patch [PATCH v3 01/04] OMAP4: PMIC: Add support for twl6030 irq
framework [1], TWL4030_CORE is redefined as TWL_CORE as you mentioned.
Then I guess that audio drivers should depend on TWL_CORE as well, if so
then we have to update all its dependencies:

1. TWL4030 codec driver: SND_SOC_TWL4030
2. All machine drivers using twl4030 codec driver: overo, omap2evm,
   omap3evm, sdp3430, omap3_pandora, omap3_beagle and zoom2

And I should do the same for twl6030 codec driver.

Regards,
-Misa

[1] http://www.mail-archive.com/linux-omap@vger.kernel.org/msg17066.html--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 0/7] TWL6030 audio codec initial support

2009-10-06 Thread Lopez Cruz, Misael
Following patch series adds initial support for TWL6030 codec
driver.

Changes from v2:
- CODEC now handles scenarios where no platform data is passed
- Removed GPIOLIB dependency of codec driver
- Removed magic values, register reads instead
- Added runtime constraints depending on sysclk
- Added more constraints for switching to low-power mode
- Use request_threaded_irq instead (oneshot support required)
- wait_for_completion with timeout
- Changelog now gives a better explanation of features and
  corresponding changes

Thanks,
-Misa

---

Misael Lopez Cruz (7):
  OMAP4: PMIC: Add support for twl6030 codec
  ASoC: TWL6030: Add twl6030 codec driver
  ASoC: TWL6030: Manual power-up/down sequences
  ASoC: TWL6030: Add support for low-power PLL
  ASoC: TWL6030: Add restrictions for low-power playback mode
  ASoC: TWL6030: Enable audio interrupt
  ASoC: TWL6030: Detect power-up sequence completion

 drivers/mfd/twl-core.c |   15 +
 include/linux/i2c/twl.h|7 +
 sound/soc/codecs/Kconfig   |4 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/twl6030.c | 1242 
 sound/soc/codecs/twl6030.h |  141 +
 6 files changed, 1411 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/twl6030.c
 create mode 100644 sound/soc/codecs/twl6030.h--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 1/7] OMAP4: PMIC: Add support for twl6030 codec

2009-10-06 Thread Lopez Cruz, Misael
In order to have TWL6030 CODEC driver as a platform driver, codec data
should be passed through twl_platform_data structure.

For twl6030 audio codec, the following data may be passed:

- audpwron_gpio: gpio line used to power-up/down the codec. A low-to-high
  transition powers codec up. Setting audpwron_gpio to a negative value
  means that codec will use manual power sequence instead of automatic
  sequence
- naudint_irq: irq line for audio interrupt. twl6030 drives NAUDINT line
  to low when an interrupt (codec ready, plug insertion/removal, etc) is
  detected

However, codec driver can operate if any or none of them are passed.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 drivers/mfd/twl-core.c  |   15 +++
 include/linux/i2c/twl.h |7 +++
 2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index af4cf47..6432af1 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -108,6 +108,12 @@
 #define twl_has_mmc()   false
 #endif
 
+#if defined(CONFIG_SND_SOC_TWL6030) || defined(CONFIG_SND_SOC_TWL6030_MODULE)
+#define twl_has_codec()true
+#else
+#define twl_has_codec()false
+#endif
+
 #if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
 #define twl_has_usb()  true
 #else
@@ -190,6 +196,7 @@
 #define BCI_SUB_CHIP_IDSUB_CHIP_ID1
 #define GPIO_SUB_CHIP_ID   0 /* NOT SUPPORTED IN TWL6030 */
 #define KEYPAD_SUB_CHIP_ID 0 /* ADDED FOR COMPILATION ONLY */
+#define CODEC_SUB_CHIP_ID  SUB_CHIP_ID3
 
 /* subchip/slave 0 0x48 - POWER */
 #define TWL6030_BASEADD_RTC0x
@@ -632,6 +639,14 @@ add_children(struct twl_platform_data *pdata, unsigned 
long features)
if (IS_ERR(child))
return PTR_ERR(child);
}
+
+   if (twl_has_codec()) {
+   child = add_child(CODEC_SUB_CHIP_ID, twl6030_codec,
+   pdata-codec, sizeof(*pdata-codec), false,
+   0, 0);
+   if (IS_ERR(child))
+   return PTR_ERR(child);
+   }
 #endif
 
if (twl_has_usb()  pdata-usb) {
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index b687a8b..e76ca9b 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -472,6 +472,12 @@ struct twl_usb_data {
enum twl_usb_mode   usb_mode;
 };
 
+struct twl_codec_data {
+   /* twl6030 */
+   int audpwron_gpio;  /* audio power-on gpio */
+   int naudint_irq;/* audio interrupt */
+};
+
 struct twl_platform_data {
unsignedirq_base, irq_end;
struct twl_bci_platform_data*bci;
@@ -479,6 +485,7 @@ struct twl_platform_data {
struct twl_madc_platform_data   *madc;
struct twl_keypad_data  *keypad;
struct twl_usb_data *usb;
+   struct twl_codec_data   *codec;
 
/* LDO regulators common to TWL4030/TWL6030 */
struct regulator_init_data  *vdac;
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv3 2/7] ASoC: TWL6030: Add twl6030 codec driver

2009-10-06 Thread Lopez Cruz, Misael
Initial version of TWL6030 codec driver.

The TWL6030 codec uses a propietary PDM-based digital audio interface.
Audio paths supported are:

- Input: Main Mic, Sub Mic, Headset Mic, Auxiliary-FM Left/Right
- Output: Headset Left/Right, Handsfree Left/Right

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/Kconfig   |4 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/twl6030.c |  824 
 sound/soc/codecs/twl6030.h |   94 +
 4 files changed, 924 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/twl6030.c
 create mode 100644 sound/soc/codecs/twl6030.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index bbc97fd..0effb52 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -25,6 +25,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TWL4030 if TWL4030_CORE
+   select SND_SOC_TWL6030 if TWL6030_CORE
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
select SND_SOC_WM8350 if MFD_WM8350
@@ -114,6 +115,9 @@ config SND_SOC_TLV320AIC3X
 config SND_SOC_TWL4030
tristate

+config SND_SOC_TWL6030
+   tristate
+
 config SND_SOC_UDA134X
tristate

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8b75305..b70c8a1 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -13,6 +13,7 @@ snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-twl4030-objs := twl4030.o
+snd-soc-twl6030-objs := twl6030.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wm8350-objs := wm8350.o
@@ -50,6 +51,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)  += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)  += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
+obj-$(CONFIG_SND_SOC_TWL6030)  += snd-soc-twl6030.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WM8350)   += snd-soc-wm8350.o
diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
new file mode 100644
index 000..3c6c540
--- /dev/null
+++ b/sound/soc/codecs/twl6030.c
@@ -0,0 +1,824 @@
+/*
+ * ALSA SoC TWL6030 codec driver
+ *
+ * Author:  Misael Lopez Cruz x0052...@ti.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include linux/module.h
+#include linux/moduleparam.h
+#include linux/init.h
+#include linux/delay.h
+#include linux/pm.h
+#include linux/i2c.h
+#include linux/gpio.h
+#include linux/platform_device.h
+#include linux/i2c/twl.h
+
+#include sound/core.h
+#include sound/pcm.h
+#include sound/pcm_params.h
+#include sound/soc.h
+#include sound/soc-dapm.h
+#include sound/initval.h
+#include sound/tlv.h
+
+#include twl6030.h
+
+#define TWL6030_RATES   (SNDRV_PCM_RATE_48000)
+#define TWL6030_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct twl6030_data {
+   struct snd_soc_codec codec;
+   int audpwron;
+   int codec_powered;
+};
+
+/*
+ * twl6030 register cache  default register settings
+ */
+static const u8 twl6030_reg[TWL6030_CACHEREGNUM] = {
+   0x00, /* not used   0x00*/
+   0x4B, /* TWL6030_ASICID (ro)0x01*/
+   0x00, /* TWL6030_ASICREV (ro)   0x02*/
+   0x00, /* TWL6030_INTID  0x03*/
+   0x7B, /* TWL6030_INTMR  0x04*/
+   0x00, /* TWL6030_NCPCTRL0x05*/
+   0x00, /* TWL6030_LDOCTL 0x06*/
+   0x00, /* TWL6030_HPPLLCTL   0x07*/
+   0x00, /* TWL6030_LPPLLCTL   0x08*/
+   0x00, /* TWL6030_LPPLLDIV   0x09*/
+   0x00, /* TWL6030_AMICBCTL   0x0A*/
+   0x00, /* TWL6030_DMICBCTL   0x0B*/
+   0x18, /* TWL6030_MICLCTL0x0C*/
+   0x18, /* TWL6030_MICRCTL0x0D*/
+   0x00, /* TWL6030_MICGAIN0x0E*/
+   0x1B, /* TWL6030_LINEGAIN   0x0F*/
+   0x00, /* TWL6030_HSLCTL 0x10*/
+   0x00, /* TWL6030_HSRCTL 0x11*/
+   0x00, /* TWL6030_HSGAIN 0x12*/
+   

[PATCHv3 3/7] ASoC: TWL6030: Manual power-up/down sequences

2009-10-06 Thread Lopez Cruz, Misael
TWL6030 codec device can be powered-up/down through a specific register
writes sequence. These sequences can be used when no gpio line is
provided for AUDPWRON.

When the codec is powered-up in this way, automatic power-down sequence
(triggered by thermal shutdown) is not possible.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |  112 ++-
 sound/soc/codecs/twl6030.h |   16 ++
 2 files changed, 115 insertions(+), 13 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 3c6c540..f97dec2 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -244,6 +244,88 @@ static void twl6030_init_vdd_regs(struct snd_soc_codec 
*codec)
}
 }
 
+/* twl6030 codec manual power-up sequence */
+static void twl6030_power_up(struct snd_soc_codec *codec)
+{
+   u8 ncpctl, ldoctl, lppllctl, accctl;
+
+   ncpctl = twl6030_read_reg_cache(codec, TWL6030_REG_NCPCTL);
+   ldoctl = twl6030_read_reg_cache(codec, TWL6030_REG_LDOCTL);
+   lppllctl = twl6030_read_reg_cache(codec, TWL6030_REG_LPPLLCTL);
+   accctl = twl6030_read_reg_cache(codec, TWL6030_REG_ACCCTL);
+
+   /* enable reference system */
+   ldoctl |= TWL6030_REFENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   mdelay(10);
+   /* enable internal oscillator */
+   ldoctl |= TWL6030_OSCENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(10);
+   /* enable high-side ldo */
+   ldoctl |= TWL6030_HSLDOENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(244);
+   /* enable negative charge pump */
+   ncpctl |= TWL6030_NCPENA | TWL6030_NCPOPEN;
+   twl6030_write(codec, TWL6030_REG_NCPCTL, ncpctl);
+   udelay(488);
+   /* enable low-side ldo */
+   ldoctl |= TWL6030_LSLDOENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(244);
+   /* enable low-power pll */
+   lppllctl |= TWL6030_LPLLENA;
+   twl6030_write(codec, TWL6030_REG_LPPLLCTL, lppllctl);
+   /* reset state machine */
+   accctl |= TWL6030_RESETSPLIT;
+   twl6030_write(codec, TWL6030_REG_ACCCTL, accctl);
+   mdelay(5);
+   accctl = ~TWL6030_RESETSPLIT;
+   twl6030_write(codec, TWL6030_REG_ACCCTL, accctl);
+   /* disable internal oscillator */
+   ldoctl = ~TWL6030_OSCENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+}
+
+/* twl6030 codec manual power-down sequence */
+static void twl6030_power_down(struct snd_soc_codec *codec)
+{
+   u8 ncpctl, ldoctl, lppllctl, accctl;
+
+   ncpctl = twl6030_read_reg_cache(codec, TWL6030_REG_NCPCTL);
+   ldoctl = twl6030_read_reg_cache(codec, TWL6030_REG_LDOCTL);
+   lppllctl = twl6030_read_reg_cache(codec, TWL6030_REG_LPPLLCTL);
+   accctl = twl6030_read_reg_cache(codec, TWL6030_REG_ACCCTL);
+
+   /* enable internal oscillator */
+   ldoctl |= TWL6030_OSCENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(10);
+   /* disable low-power pll */
+   lppllctl = ~TWL6030_LPLLENA;
+   twl6030_write(codec, TWL6030_REG_LPPLLCTL, lppllctl);
+   /* disable low-side ldo */
+   ldoctl = ~TWL6030_LSLDOENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(244);
+   /* disable negative charge pump */
+   ncpctl = ~(TWL6030_NCPENA | TWL6030_NCPOPEN);
+   twl6030_write(codec, TWL6030_REG_NCPCTL, ncpctl);
+   udelay(488);
+   /* disable high-side ldo */
+   ldoctl = ~TWL6030_HSLDOENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(244);
+   /* disable internal oscillator */
+   ldoctl = ~TWL6030_OSCENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   /* disable reference system */
+   ldoctl = ~TWL6030_REFENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   mdelay(10);
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -480,12 +562,15 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
 
/* power-up sequence latency */
mdelay(16);
-   }
 
-   /* sync registers updated during power-up sequence */
-   twl6030_read(codec, TWL6030_REG_NCPCTL);
-   twl6030_read(codec, TWL6030_REG_LDOCTL);
-   twl6030_read(codec, TWL6030_REG_LPPLLCTL);
+   /* sync registers updated during power-up sequence */
+   twl6030_read(codec, TWL6030_REG_NCPCTL);
+   twl6030_read(codec, TWL6030_REG_LDOCTL);
+   twl6030_read(codec, TWL6030_REG_LPPLLCTL);
+   } else {
+   /* use manual power-up sequence */
+   twl6030_power_up(codec);
+   }
 
/* initialize vdd/vss registers with reg_cache */
  

[PATCHv3 4/7] ASoC: TWL6030: Add support for low-power PLL

2009-10-06 Thread Lopez Cruz, Misael
TWL6030 codec sysclk can be provided by: low-power or high
performance PLL.

The low-power PLL takes a low-frequency input at 32,768 Hz and
generates an approximate of 17.64 or 19.2 MHz.

The high-performance PLL generates an exact 19.2 MHz clock signal
from high-frequency input at 12/19.2/26/38.4 MHz.

For the particular case of headset path, PLL being used defines the
headset power mode: low-power, high-performance. Headset DAC and
output driver should be configured according to the selected mode.
17.64 MHz sysclk is recommended only for headset low-power playback
mode.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |  232 +--
 sound/soc/codecs/twl6030.h |   16 +++
 2 files changed, 215 insertions(+), 33 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index f97dec2..9fc4795 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -39,7 +39,7 @@
 
 #include twl6030.h
 
-#define TWL6030_RATES   (SNDRV_PCM_RATE_48000)
+#define TWL6030_RATES   (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 #define TWL6030_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
 
 /* codec private data */
@@ -47,6 +47,9 @@ struct twl6030_data {
struct snd_soc_codec codec;
int audpwron;
int codec_powered;
+   int pll;
+   unsigned int sysclk;
+   struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
 /*
@@ -326,6 +329,29 @@ static void twl6030_power_down(struct snd_soc_codec *codec)
mdelay(10);
 }
 
+/* set headset dac and driver power mode */
+static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
+{
+   int hslctl, hsrctl;
+   int mask = TWL6030_HSDRVMODEL | TWL6030_HSDACMODEL;
+
+   hslctl = twl6030_read_reg_cache(codec, TWL6030_REG_HSLCTL);
+   hsrctl = twl6030_read_reg_cache(codec, TWL6030_REG_HSRCTL);
+
+   if (high_perf) {
+   hslctl = ~mask;
+   hsrctl = ~mask;
+   } else {
+   hslctl |= mask;
+   hsrctl |= mask;
+   }
+
+   twl6030_write(codec, TWL6030_REG_HSLCTL, hslctl);
+   twl6030_write(codec, TWL6030_REG_HSRCTL, hsrctl);
+
+   return 0;
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -607,55 +633,195 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
return 0;
 }
 
+/* set of rates for each pll: low-power and high-performance */
+
+static unsigned int lp_rates[] = {
+   44100,
+   48000,
+};
+
+static struct snd_pcm_hw_constraint_list lp_constraints = {
+   .count  = ARRAY_SIZE(lp_rates),
+   .list   = lp_rates,
+};
+
+static unsigned int hp_rates[] = {
+   48000,
+};
+
+static struct snd_pcm_hw_constraint_list hp_constraints = {
+   .count  = ARRAY_SIZE(hp_rates),
+   .list   = hp_rates,
+};
+
+static int twl6030_startup(struct snd_pcm_substream *substream,
+   struct snd_soc_dai *dai)
+{
+   struct snd_soc_pcm_runtime *rtd = substream-private_data;
+   struct snd_soc_device *socdev = rtd-socdev;
+   struct snd_soc_codec *codec = socdev-card-codec;
+   struct twl6030_data *priv = codec-private_data;
+
+   if (!priv-sysclk) {
+   dev_err(codec-dev,
+   no mclk configured, call set_sysclk() on init\n);
+   return -EINVAL;
+   }
+
+   snd_pcm_hw_constraint_list(substream-runtime, 0,
+   SNDRV_PCM_HW_PARAM_RATE,
+   priv-sysclk_constraints);
+
+   return 0;
+}
+
+static int twl6030_hw_params(struct snd_pcm_substream *substream,
+   struct snd_pcm_hw_params *params,
+   struct snd_soc_dai *dai)
+{
+   struct snd_soc_pcm_runtime *rtd = substream-private_data;
+   struct snd_soc_device *socdev = rtd-socdev;
+   struct snd_soc_codec *codec = socdev-card-codec;
+   struct twl6030_data *priv = codec-private_data;
+   u8 lppllctl;
+   int rate;
+
+   /* nothing to do for high-perf pll, it supports only 48 kHz */
+   if (priv-pll == TWL6030_HPPLL_ID)
+   return 0;
+
+   lppllctl = twl6030_read_reg_cache(codec, TWL6030_REG_LPPLLCTL);
+
+   rate = params_rate(params);
+   switch (rate) {
+   case 44100:
+   lppllctl |= TWL6030_LPLLFIN;
+   priv-sysclk = 1764;
+   break;
+   case 48000:
+   lppllctl = ~TWL6030_LPLLFIN;
+   priv-sysclk = 1920;
+   break;
+   default:
+   dev_err(codec-dev, unsupported rate %d\n, rate);
+   return -EINVAL;
+   }
+
+   twl6030_write(codec, TWL6030_REG_LPPLLCTL, lppllctl);
+
+   return 0;
+}
+
 static int twl6030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
 {
struct snd_soc_codec *codec = codec_dai-codec;
+   struct 

[PATCHv3 5/7] ASoC: TWL6030: Add restrictions for low-power playback mode

2009-10-06 Thread Lopez Cruz, Misael
Low-power playback mode is a special scenario where only headset path
(headset DAC and driver) is active. Only in this mode the codec can
support 44.1 and 48 kHz, low-power PLL should provide sysclk signal.

Currently, handsfree DAC and driver are the only components that can
prevent codec to enter to low-power playback mode. Other components
like earphone driver, vibrator driver or loopback (which are not yet
supported in the driver) can cause the same effect.

In order to detect conflicting paths, CODEC driver supervises
non-low-power widgets powered by DAPM mechanism, just at the point
pcm trigger callback gets called.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |   79 +++
 1 files changed, 71 insertions(+), 8 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 9fc4795..8548442 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -48,6 +48,7 @@ struct twl6030_data {
int audpwron;
int codec_powered;
int pll;
+   int non_lp;
unsigned int sysclk;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
@@ -352,6 +353,20 @@ static int headset_power_mode(struct snd_soc_codec *codec, 
int high_perf)
return 0;
 }
 
+static int twl6030_power_mode_event(struct snd_soc_dapm_widget *w,
+   struct snd_kcontrol *kcontrol, int event)
+{
+   struct snd_soc_codec *codec = w-codec;
+   struct twl6030_data *priv = codec-private_data;
+
+   if (SND_SOC_DAPM_EVENT_ON(event))
+   priv-non_lp++;
+   else
+   priv-non_lp--;
+
+   return 0;
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -485,10 +500,14 @@ static const struct snd_soc_dapm_widget 
twl6030_dapm_widgets[] = {
TWL6030_REG_HSLCTL, 0, 0),
SND_SOC_DAPM_DAC(HSDAC Right, Headset Playback,
TWL6030_REG_HSRCTL, 0, 0),
-   SND_SOC_DAPM_DAC(HFDAC Left, Handsfree Playback,
-   TWL6030_REG_HFLCTL, 0, 0),
-   SND_SOC_DAPM_DAC(HFDAC Right, Handsfree Playback,
-   TWL6030_REG_HFRCTL, 0, 0),
+   SND_SOC_DAPM_DAC_E(HFDAC Left, Handsfree Playback,
+   TWL6030_REG_HFLCTL, 0, 0,
+   twl6030_power_mode_event,
+   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+   SND_SOC_DAPM_DAC_E(HFDAC Right, Handsfree Playback,
+   TWL6030_REG_HFRCTL, 0, 0,
+   twl6030_power_mode_event,
+   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
/* Analog playback switches */
SND_SOC_DAPM_SWITCH(HSDAC Left Playback,
@@ -504,10 +523,14 @@ static const struct snd_soc_dapm_widget 
twl6030_dapm_widgets[] = {
SND_SOC_NOPM, 0, 0, hsl_driver_switch_controls),
SND_SOC_DAPM_SWITCH(Headset Right Driver,
SND_SOC_NOPM, 0, 0, hsr_driver_switch_controls),
-   SND_SOC_DAPM_SWITCH(Handsfree Left Driver,
-   SND_SOC_NOPM, 0, 0, hfl_driver_switch_controls),
-   SND_SOC_DAPM_SWITCH(Handsfree Right Driver,
-   SND_SOC_NOPM, 0, 0, hfr_driver_switch_controls),
+   SND_SOC_DAPM_SWITCH_E(Handsfree Left Driver,
+   SND_SOC_NOPM, 0, 0, hfl_driver_switch_controls,
+   twl6030_power_mode_event,
+   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+   SND_SOC_DAPM_SWITCH_E(Handsfree Right Driver,
+   SND_SOC_NOPM, 0, 0, hfr_driver_switch_controls,
+   twl6030_power_mode_event,
+   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
/* Analog playback PGAs */
SND_SOC_DAPM_PGA(HFDAC Left PGA,
@@ -668,6 +691,17 @@ static int twl6030_startup(struct snd_pcm_substream 
*substream,
return -EINVAL;
}
 
+   /*
+* capture is not supported at 17.64 MHz,
+* it's reserved for headset low-power playback scenario
+*/
+   if ((priv-sysclk == 1764)  substream-stream) {
+   dev_err(codec-dev,
+   capture mode is not supported at %dHz\n,
+   priv-sysclk);
+   return -EINVAL;
+   }
+
snd_pcm_hw_constraint_list(substream-runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
priv-sysclk_constraints);
@@ -712,6 +746,34 @@ static int twl6030_hw_params(struct snd_pcm_substream 
*substream,
return 0;
 }
 
+static int twl6030_trigger(struct snd_pcm_substream *substream,
+   int cmd, struct snd_soc_dai *dai)
+{
+   struct snd_soc_pcm_runtime *rtd = substream-private_data;
+   struct snd_soc_device *socdev = rtd-socdev;
+   struct snd_soc_codec *codec = socdev-card-codec;
+   

[PATCHv3 6/7] ASoC: TWL6030: Enable audio interrupt

2009-10-06 Thread Lopez Cruz, Misael
NAUDINT interrupt line is provided by the TWL6030 codec to signal
externally events like headset plug/unplug, hook, power-up sequence
completion, etc.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |   70 ---
 sound/soc/codecs/twl6030.h |   14 +
 2 files changed, 79 insertions(+), 5 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 8548442..56fe136 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -46,6 +46,7 @@
 struct twl6030_data {
struct snd_soc_codec codec;
int audpwron;
+   int naudint;
int codec_powered;
int pll;
int non_lp;
@@ -61,7 +62,7 @@ static const u8 twl6030_reg[TWL6030_CACHEREGNUM] = {
0x4B, /* TWL6030_ASICID (ro)0x01*/
0x00, /* TWL6030_ASICREV (ro)   0x02*/
0x00, /* TWL6030_INTID  0x03*/
-   0x7B, /* TWL6030_INTMR  0x04*/
+   0x00, /* TWL6030_INTMR  0x04*/
0x00, /* TWL6030_NCPCTRL0x05*/
0x00, /* TWL6030_LDOCTL 0x06*/
0x00, /* TWL6030_HPPLLCTL   0x07*/
@@ -367,6 +368,39 @@ static int twl6030_power_mode_event(struct 
snd_soc_dapm_widget *w,
return 0;
 }
 
+/* audio interrupt handler */
+static irqreturn_t twl6030_naudint_handler(int irq, void *data)
+{
+   struct snd_soc_codec *codec = data;
+   u8 intid;
+
+   twl_i2c_read_u8(TWL6030_MODULE_AUDIO, intid, TWL6030_REG_INTID);
+
+   switch (intid) {
+   case TWL6030_THINT:
+   dev_alert(codec-dev, die temp over-limit detection\n);
+   break;
+   case TWL6030_PLUGINT:
+   case TWL6030_UNPLUGINT:
+   case TWL6030_HOOKINT:
+   break;
+   case TWL6030_HFINT:
+   dev_alert(codec-dev, hf drivers over current detection\n);
+   break;
+   case TWL6030_VIBINT:
+   dev_alert(codec-dev, vib drivers over current detection\n);
+   break;
+   case TWL6030_READYINT:
+   dev_alert(codec-dev, codec is ready\n);
+   break;
+   default:
+   dev_err(codec-dev, unknown audio interrupt %d\n, intid);
+   break;
+   }
+
+   return IRQ_HANDLED;
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -993,19 +1027,23 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
struct twl_codec_data *twl_codec = pdev-dev.platform_data;
struct snd_soc_codec *codec;
struct twl6030_data *priv;
-   int audpwron;
+   int audpwron, naudint;
int ret = 0;
 
priv = kzalloc(sizeof(struct twl6030_data), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
 
-   if (twl_codec)
+   if (twl_codec) {
audpwron = twl_codec-audpwron_gpio;
-   else
+   naudint = twl_codec-naudint_irq;
+   } else {
audpwron = -EINVAL;
+   naudint = 0;
+   }
 
priv-audpwron = audpwron;
+   priv-naudint = naudint;
 
codec = priv-codec;
codec-dev = pdev-dev;
@@ -1043,13 +1081,28 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
priv-codec_powered = 0;
}
 
+   if (naudint) {
+   /* audio interrupt */
+   ret = request_threaded_irq(naudint, NULL,
+   twl6030_naudint_handler,
+   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+   twl6030_codec, codec);
+   if (ret)
+   goto gpio2_err;
+   } else {
+   dev_warn(codec-dev,
+   no naudint irq, audio interrupts disabled\n);
+   twl6030_write_reg_cache(codec, TWL6030_REG_INTMR,
+   TWL6030_ALLINT_MSK);
+   }
+
/* init vio registers */
twl6030_init_vio_regs(codec);
 
/* power on device */
ret = twl6030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (ret)
-   goto gpio2_err;
+   goto irq_err;
 
ret = snd_soc_register_codec(codec);
if (ret)
@@ -1068,6 +1121,9 @@ dai_err:
twl6030_codec = NULL;
 reg_err:
twl6030_set_bias_level(codec, SND_SOC_BIAS_OFF);
+irq_err:
+   if (naudint)
+   free_irq(naudint, codec);
 gpio2_err:
if (gpio_is_valid(audpwron))
gpio_free(audpwron);
@@ -1082,10 +1138,14 @@ static int __devexit twl6030_codec_remove(struct 
platform_device *pdev)
 {
struct twl6030_data *priv = twl6030_codec-private_data;
int audpwron = priv-audpwron;
+   int naudint = priv-naudint;
 
if (gpio_is_valid(audpwron))
gpio_free(audpwron);
 
+   if (naudint)
+   free_irq(naudint, twl6030_codec);
+

[PATCHv3 7/7] ASoC: TWL6030: Detect power-up sequence completion

2009-10-06 Thread Lopez Cruz, Misael
When the codec is powered-up through external AUDPWRON line it starts
its power-up sequence. The completion of the sequence is signaled
through the audio interrupt, and then codec is operational.

If NAUDINT irq is provided, CODEC driver starts a wait_for_completion
just after AUDPWRON line transitions from low to high. It's signaled as
complete when servicing READYINT interrupt.

If AUDPWRON gpio line is provided but NAUDINT irq is not, then CODEC
driver enables READYINT and polls on INTID register. If none of them are
provided, then CODEC uses manual power sequences and disables all audio
interrupts.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |   61 +--
 sound/soc/codecs/twl6030.h |1 +
 2 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 56fe136..3db7f1d 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -52,6 +52,7 @@ struct twl6030_data {
int non_lp;
unsigned int sysclk;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
+   struct completion ready;
 };
 
 /*
@@ -372,6 +373,7 @@ static int twl6030_power_mode_event(struct 
snd_soc_dapm_widget *w,
 static irqreturn_t twl6030_naudint_handler(int irq, void *data)
 {
struct snd_soc_codec *codec = data;
+   struct twl6030_data *priv = codec-private_data;
u8 intid;
 
twl_i2c_read_u8(TWL6030_MODULE_AUDIO, intid, TWL6030_REG_INTID);
@@ -391,7 +393,7 @@ static irqreturn_t twl6030_naudint_handler(int irq, void 
*data)
dev_alert(codec-dev, vib drivers over current detection\n);
break;
case TWL6030_READYINT:
-   dev_alert(codec-dev, codec is ready\n);
+   complete(priv-ready);
break;
default:
dev_err(codec-dev, unknown audio interrupt %d\n, intid);
@@ -626,11 +628,45 @@ static int twl6030_add_widgets(struct snd_soc_codec 
*codec)
return 0;
 }
 
+static int twl6030_power_up_completion(struct snd_soc_codec *codec,
+   int naudint)
+{
+   struct twl6030_data *priv = codec-private_data;
+   int time_left;
+   u8 intid;
+
+   if (naudint) {
+   /* wait for ready interrupt with 48 ms timeout */
+   time_left = wait_for_completion_timeout(priv-ready,
+   msecs_to_jiffies(48));
+   } else {
+   /* retry 3 times only */
+   for (time_left = 3; time_left  0; time_left--) {
+   mdelay(16);
+   twl_i2c_read_u8(TWL6030_MODULE_AUDIO, intid,
+   TWL6030_REG_INTID);
+   if (intid  TWL6030_READYINT)
+   break;
+   }
+   }
+
+   if (!time_left) {
+   dev_err(codec-dev, timeout waiting for READYINT\n);
+   return -ETIMEDOUT;
+   }
+
+   priv-codec_powered = 1;
+
+   return 0;
+}
+
 static int twl6030_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
 {
struct twl6030_data *priv = codec-private_data;
int audpwron = priv-audpwron;
+   int naudint = priv-naudint;
+   int ret;
 
switch (level) {
case SND_SOC_BIAS_ON:
@@ -643,8 +679,10 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
/* use AUDPWRON line */
gpio_set_value(audpwron, 1);
 
-   /* power-up sequence latency */
-   mdelay(16);
+   /* wait for power-up completion */
+   ret = twl6030_power_up_completion(codec, naudint);
+   if (ret)
+   return ret;
 
/* sync registers updated during power-up sequence */
twl6030_read(codec, TWL6030_REG_NCPCTL);
@@ -653,12 +691,11 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
} else {
/* use manual power-up sequence */
twl6030_power_up(codec);
+   priv-codec_powered = 1;
}
 
/* initialize vdd/vss registers with reg_cache */
twl6030_init_vdd_regs(codec);
-
-   priv-codec_powered = 1;
break;
case SND_SOC_BIAS_OFF:
if (!priv-codec_powered)
@@ -1068,6 +1105,7 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
mutex_init(codec-mutex);
INIT_LIST_HEAD(codec-dapm_widgets);
INIT_LIST_HEAD(codec-dapm_paths);
+   init_completion(priv-ready);
 
if (gpio_is_valid(audpwron)) {
ret = gpio_request(audpwron, audpwron);
@@ -1090,10 +1128,15 @@ 

RE: [alsa-devel] [PATCHv3 1/7] OMAP4: PMIC: Add support for twl6030 codec

2009-10-06 Thread Lopez Cruz, Misael
Peter Ujfalusi wrote:
 On Tuesday 06 October 2009 10:29:39 ext Lopez Cruz, Misael wrote:
 In order to have TWL6030 CODEC driver as a platform driver, codec
 data should be passed through twl_platform_data structure.
 
 For twl6030 audio codec, the following data may be passed:
 
 - audpwron_gpio: gpio line used to power-up/down the codec. A
   low-to-high transition powers codec up. Setting audpwron_gpio to a
   negative value means that codec will use manual power sequence
 instead of automatic   sequence - naudint_irq: irq line for audio
   interrupt. twl6030 drives NAUDINT line to low when an interrupt
 (codec ready, plug insertion/removal, etc) is   detected 
 
 However, codec driver can operate if any or none of them are passed.

 How does the twl4030 series would fit with this modification?
 I have also added the twl4030 codec as a child for the twl
 MFD, but I have not finished the cleanup of the codec fully.

twl6030 codec data won't conflict with twl4030's as it's dependent of
TWL6030_CORE. We can add parallely the required data for twl4030 codec.

 
 Signed-off-by: Misael Lopez Cruz x0052...@ti.com
 ---
  drivers/mfd/twl-core.c  |   15 +++
  include/linux/i2c/twl.h |7 +++
  2 files changed, 22 insertions(+), 0 deletions(-)
 
 diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
 index af4cf47..6432af1 100644
 --- a/drivers/mfd/twl-core.c
 +++ b/drivers/mfd/twl-core.c
 @@ -108,6 +108,12 @@
  #define twl_has_mmc()   false
  #endif
 
 +#if defined(CONFIG_SND_SOC_TWL6030) ||
  defined(CONFIG_SND_SOC_TWL6030_MODULE) +#define
 twl_has_codec()  true +#else +#define twl_has_codec()false
 +#endif
 +
  #if defined(CONFIG_TWL4030_USB) ||
 defined(CONFIG_TWL4030_USB_MODULE)
  #define twl_has_usb()   true
  #else
 @@ -190,6 +196,7 @@
  #define BCI_SUB_CHIP_ID SUB_CHIP_ID1
  #define GPIO_SUB_CHIP_ID0 /* NOT SUPPORTED IN TWL6030 */
  #define KEYPAD_SUB_CHIP_ID  0 /* ADDED FOR COMPILATION ONLY */
 +#define CODEC_SUB_CHIP_ID   SUB_CHIP_ID3

 TWL4030 codec is under ID2 address group.

CODEC_SUB_CHIP_ID for twl6030 is under #ifdef CONFIG_TWL6030_CORE.
There are a different set of _CHIP_IDs for twl4030 children, which
doesn't have a definition for CODEC yet.

 
  /* subchip/slave 0 0x48 - POWER */
  #define TWL6030_BASEADD_RTC 0x
 @@ -632,6 +639,14 @@ add_children(struct twl_platform_data *pdata,
  unsigned long features) if (IS_ERR(child))
  return PTR_ERR(child);
  }
 +
 +if (twl_has_codec()) {
 +child = add_child(CODEC_SUB_CHIP_ID, twl6030_codec,
 +pdata-codec, sizeof(*pdata-codec), false,
 +0, 0);
 +if (IS_ERR(child))
 +return PTR_ERR(child);
 +}

 We are going to have the twl4030 as child as well.

  #endif
 
  if (twl_has_usb()  pdata-usb) {
 diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index
 b687a8b..e76ca9b 100644 --- a/include/linux/i2c/twl.h
 +++ b/include/linux/i2c/twl.h
 @@ -472,6 +472,12 @@ struct twl_usb_data {
  enum twl_usb_mode   usb_mode;
  };
 
 +struct twl_codec_data {
 +/* twl6030 */
 +int audpwron_gpio;  /* audio power-on gpio */
 +int naudint_irq;/* audio interrupt */
 +};

 These are not applicable for the twl4030 codec, should we
 have different
 twl_codec_data for twl6030 and twl4030 series?

Currently, the support for TWL4030 and TWL6030 makes them mutually
exclusive, TWL6030_CORE depends on !TWL4030_CORE. So we can have
separate twl_codec_data definitions to avoid unused space in the
structure.

 Should I merge here the things which will be used for the twl4030
 codec?

I think merging them would suit only if both twl versions can be
enabled at the same time, but not sure it that makes sense.

 At the moment, I only have audio_mclk in my codec_data, but
 most probably the HS ramp related things will be also merged here
 in the future.

 +
  struct twl_platform_data {
  unsignedirq_base, irq_end;
  struct twl_bci_platform_data*bci;
 @@ -479,6 +485,7 @@ struct twl_platform_data {
  struct twl_madc_platform_data   *madc;
  struct twl_keypad_data  *keypad;
  struct twl_usb_data *usb;
 +struct twl_codec_data   *codec;
 
  /* LDO regulators common to TWL4030/TWL6030 */
  struct regulator_init_data  *vdac;

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [alsa-devel] [PATCHv2 5/7] ASoC: TWL6030: Add support for low-power mode

2009-09-29 Thread Lopez Cruz, Misael
Mark,

Mark Brown wrote:
 On Fri, Sep 25, 2009 at 09:03:30PM -0500, Lopez Cruz, Misael wrote:
 
 TWL6030 codec supports two power modes: low-power and high
 performance.

 In low-power mode, headset downlink must be the only path enabled
 and components in that path (headset DAC and driver) should be in
 that mode too. In this mode, codec can stream audio at 44.1 and
 48 kHz if sys clock from CLK32K is configured to 17.64 and 19.2
 MHz using low-power PLL, respectively.

 In high-performance mode, codec can only work at 19.2 MHz from
 high-performance PLL. All paths supported in the codec can be used
 but audio can be streamed only at 48 kHz.

 The driver should also set constraints at runtime so that applications
 know they shouldn't use an unsupported sample rate.  See wm8988 for an
 example of doing this - it has some similar SYSCLK based restrictions.

I think I got confused with what to do in set_sysclk and set_pll. In my
current approach:

- set_sysclk takes care of setting corresponding clk source: lppll
  or hppll. But it also disables the pll not in use (i.e. if lppll is
  set, then disable hppll)
- set_pll takes care of setting pll div for lppll (which is meant to
  receive 32k clk) and configure hppll for any of the supported freq_in
  (12, 19.2, 26, 38.4 MHz). Because only after this point I know the
  value of sysclk, the constraints are set here. Is it fine?
  For lppll the sysclk is set to requested freq_out (if div value is
  in the valid range) and for hppll it's always 19.2 and it's the only
  clk rate support by that pll.

In contrast, in wm8988 the sysclk and contraints are set directly in
set_sysclk.

I have been kind of insecure about all these clk configuration, so I'd
be great if you could explain what's expected to go in set_sysclk as well
as in set_pll.

 It also strikes me that this is something that should be
 exposed to user space since if there's a 19.2MHz MCLK it's something
 that the system could reasonably want to activate and deactivate on
 the fly.

 For bonus points the driver could prevent switching to low power
 mode if any paths are active which conflict with it.  Doing it
 automatically would be ideal but since it sounds like a performance
 degradation to use low power mode that's not really suitable.

Any suggestion on how to detect the active paths? Using widgets with
events?
The only path active to switch to low-power should be headset.

Thanks,
-Misa--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCHv2 0/7] TWL6030 audio codec initial support

2009-09-28 Thread Lopez Cruz, Misael
Santosh,

Shilimkar, Santosh wrote:
 Misa,
 
 -Original Message-
 From: linux-omap-ow...@vger.kernel.org [mailto:linux-omap-
 ow...@vger.kernel.org] On Behalf Of Lopez Cruz, Misael
 Sent: Saturday, September 26, 2009 7:32 AM
 To: alsa-de...@alsa-project.org; linux-omap@vger.kernel.org
 Cc: Mark Brown
 Subject: [PATCHv2 0/7] TWL6030 audio codec initial support
 
 Following patch series adds initial support for TWL6030 codec driver.
 
 TWL6030 codec depends on TWL6030_CORE, which is not accepted yet.
 The main intention then is to get comments, I'll repost the patches
 of this series when TWL6030_CORE support gets accepted and rework
 patches as needed.
 Looking at your series, you have based your patches on
 Balaji's 6030 PMIC series as you mentioned  TWL6030 codec depends on
 TWL6030_CORE. 
 
 While doing that series, we realized that there is a lot of
 code common between TWL5030 and TWL6030 apart from mainly
 interrupt handling and hence a common file approach is taken
 to avoid code duplication. The patch  [PATCHv2 3/7] ASoC:
 TWL6030: Add twl6030 codec driver gives me an impression
 that there is opportunity to have a single file supporting
 both IC's. IC specific code can be handled using the runtime
 check depending on the revision.
 Can you explore this ?

TWL6030 CODEC is very different from TWL4030/TWL5030, for example the
digital audio interface of TWL6030 is a PDM-based propietary interface,
and TWL4030/TWL5030 uses I2S/TDM + PCM interfaces.
Audio components and their interconnections are very different as well,
so I don't see any code reuse for audio codec.

Thanks,
-Misa

 You can find more information on above discussion at below thread.
 
 http://www.mail-archive.com/linux-omap@vger.kernel.org/msg15756.html
 
 
 From
 Changes from v1:
 - Renamed dai format for PDM as SND_SOC_DAIFMT_PDM
 - CODEC driver registered as a platform driver
 - AUDPWRON gpio line handled in the CODEC driver
 - Handle scenario when no AUDPWRON gpio line is provided
 - Corrected names of some widgets
 - Avoid multiple calls to power functions in set_bias_level
 
 Thanks,
 -Misa
 
 ---
 
 Misael Lopez Cruz (7):
   OMAP4: PMIC: Add support for twl6030 codec
   ASoC: Add PDM DAI format definition
   ASoC: TWL6030: Add twl6030 codec driver
   ASoC: TWL6030: Manual power-up/down sequences
   ASoC: TWL6030: Add support for low-power mode
   ASoC: TWL6030: Enable audio interrupt
   ASoC: TWL6030: Power-up seq completion through audio interrupt
 
  drivers/mfd/twl-core.c |   15 +
  include/linux/i2c/twl.h|   11 +
  include/sound/soc-dai.h|1 +
  sound/soc/codecs/Kconfig   |4 +
  sound/soc/codecs/Makefile  |2 +
  sound/soc/codecs/twl6030.c | 1179
 
  sound/soc/codecs/twl6030.h |  137 +
  7 files changed, 1349 insertions(+), 0 deletions(-)  create mode
 100644 sound/soc/codecs/twl6030.c  create mode 100644
 sound/soc/codecs/twl6030.h --
 To unsubscribe from this list: send the line unsubscribe linux-omap
 in the body of a message to majord...@vger.kernel.org More majordomo
 info at  http://vger.kernel.org/majordomo-info.html
 
 
 Regards,
 Santosh

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv2 0/7] TWL6030 audio codec initial support

2009-09-25 Thread Lopez Cruz, Misael
Following patch series adds initial support for TWL6030 codec
driver.

TWL6030 codec depends on TWL6030_CORE, which is not accepted yet.
The main intention then is to get comments, I'll repost the patches
of this series when TWL6030_CORE support gets accepted and rework
patches as needed.

Changes from v1:
- Renamed dai format for PDM as SND_SOC_DAIFMT_PDM
- CODEC driver registered as a platform driver
- AUDPWRON gpio line handled in the CODEC driver
- Handle scenario when no AUDPWRON gpio line is provided
- Corrected names of some widgets
- Avoid multiple calls to power functions in set_bias_level

Thanks,
-Misa

---

Misael Lopez Cruz (7):
  OMAP4: PMIC: Add support for twl6030 codec
  ASoC: Add PDM DAI format definition
  ASoC: TWL6030: Add twl6030 codec driver
  ASoC: TWL6030: Manual power-up/down sequences
  ASoC: TWL6030: Add support for low-power mode
  ASoC: TWL6030: Enable audio interrupt
  ASoC: TWL6030: Power-up seq completion through audio interrupt

 drivers/mfd/twl-core.c |   15 +
 include/linux/i2c/twl.h|   11 +
 include/sound/soc-dai.h|1 +
 sound/soc/codecs/Kconfig   |4 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/twl6030.c | 1179 
 sound/soc/codecs/twl6030.h |  137 +
 7 files changed, 1349 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/twl6030.c
 create mode 100644 sound/soc/codecs/twl6030.h
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv2 1/7] OMAP4: PMIC: Add support for twl6030 codec

2009-09-25 Thread Lopez Cruz, Misael
In order to have TWL6030 CODEC driver as a platform driver, codec data
should be passed through twl_platform_data structure.

For twl6030 audio codec, the following data is required:

- audpwron_gpio: gpio line used to power-up/down the codec. A low-to-high
  transition powers codec up. Setting audpwron_gpio to a negative value
  means that codec will use manual power sequence instead of automatic
  sequence
- naudint_irq: irq line for audio interrupt. twl6030 drives NAUDINT line
  to low when an interrupt (codec ready, plug insertion/removal, etc) is
  detected

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 drivers/mfd/twl-core.c  |   15 +++
 include/linux/i2c/twl.h |   11 +++
 2 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index af4cf47..e9d1ff1 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -108,6 +108,12 @@
 #define twl_has_mmc()   false
 #endif
 
+#if defined(CONFIG_SND_SOC_TWL6030)
+#define twl_has_codec()true
+#else
+#define twl_has_codec()false
+#endif
+
 #if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
 #define twl_has_usb()  true
 #else
@@ -190,6 +196,7 @@
 #define BCI_SUB_CHIP_IDSUB_CHIP_ID1
 #define GPIO_SUB_CHIP_ID   0 /* NOT SUPPORTED IN TWL6030 */
 #define KEYPAD_SUB_CHIP_ID 0 /* ADDED FOR COMPILATION ONLY */
+#define CODEC_SUB_CHIP_ID  SUB_CHIP_ID3
 
 /* subchip/slave 0 0x48 - POWER */
 #define TWL6030_BASEADD_RTC0x
@@ -632,6 +639,14 @@ add_children(struct twl_platform_data *pdata, unsigned 
long features)
if (IS_ERR(child))
return PTR_ERR(child);
}
+
+   if (twl_has_codec()  pdata-codec) {
+   child = add_child(CODEC_SUB_CHIP_ID, twl6030_codec,
+   pdata-codec, sizeof(*pdata-codec), false,
+   0, 0);
+   if (IS_ERR(child))
+   return PTR_ERR(child);
+   }
 #endif
 
if (twl_has_usb()  pdata-usb) {
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index b687a8b..d8a8823 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -472,6 +472,16 @@ struct twl_usb_data {
enum twl_usb_mode   usb_mode;
 };
 
+struct snd_soc_codec;
+
+struct twl_codec_data {
+   struct snd_soc_codec *codec;
+
+   /* twl6030 */
+   int audpwron_gpio;  /* audio power-on gpio */
+   int naudint_irq;/* audio interrupt */
+};
+
 struct twl_platform_data {
unsignedirq_base, irq_end;
struct twl_bci_platform_data*bci;
@@ -479,6 +489,7 @@ struct twl_platform_data {
struct twl_madc_platform_data   *madc;
struct twl_keypad_data  *keypad;
struct twl_usb_data *usb;
+   struct twl_codec_data   *codec;
 
/* LDO regulators common to TWL4030/TWL6030 */
struct regulator_init_data  *vdac;
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv2 2/7] ASoC: Add PDM DAI format definition

2009-09-25 Thread Lopez Cruz, Misael
Add DAI format definition for PDM interfaces.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 include/sound/soc-dai.h |1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 352d7ee..9239cb0 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -30,6 +30,7 @@ struct snd_pcm_substream;
 #define SND_SOC_DAIFMT_DSP_A   3 /* L data msb after FRM LRC */
 #define SND_SOC_DAIFMT_DSP_B   4 /* L data msb during FRM LRC */
 #define SND_SOC_DAIFMT_AC975 /* AC97 */
+#define SND_SOC_DAIFMT_PDM 6 /* Pulse density modulation */
 
 /* left and right justified also known as MSB and LSB respectively */
 #define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCHv2 3/7] ASoC: TWL6030: Add twl6030 codec driver

2009-09-25 Thread Lopez Cruz, Misael
Initial version of TWL6030 codec driver.

The TWL6030 codec uses a propietary PDM-based digital audio interface.
TWL6030 codec has two power modes: low-power and high-performance,
this initial version only supports high-performance mode.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/Kconfig   |4 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/twl6030.c |  842 
 sound/soc/codecs/twl6030.h |   94 +
 4 files changed, 942 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/twl6030.c
 create mode 100644 sound/soc/codecs/twl6030.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index bbc97fd..fd9f8c1 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -25,6 +25,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TWL4030 if TWL4030_CORE
+   select SND_SOC_TWL6030 if TWL6030_CORE  GPIOLIB
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
select SND_SOC_WM8350 if MFD_WM8350
@@ -114,6 +115,9 @@ config SND_SOC_TLV320AIC3X
 config SND_SOC_TWL4030
tristate

+config SND_SOC_TWL6030
+   tristate
+
 config SND_SOC_UDA134X
tristate

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8b75305..b70c8a1 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -13,6 +13,7 @@ snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-twl4030-objs := twl4030.o
+snd-soc-twl6030-objs := twl6030.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wm8350-objs := wm8350.o
@@ -50,6 +51,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)  += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)  += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
+obj-$(CONFIG_SND_SOC_TWL6030)  += snd-soc-twl6030.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WM8350)   += snd-soc-wm8350.o
diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
new file mode 100644
index 000..92797e7
--- /dev/null
+++ b/sound/soc/codecs/twl6030.c
@@ -0,0 +1,842 @@
+/*
+ * ALSA SoC TWL6030 codec driver
+ *
+ * Author:  Misael Lopez Cruz x0052...@ti.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include linux/module.h
+#include linux/moduleparam.h
+#include linux/init.h
+#include linux/delay.h
+#include linux/pm.h
+#include linux/i2c.h
+#include linux/gpio.h
+#include linux/platform_device.h
+#include linux/i2c/twl.h
+
+#include sound/core.h
+#include sound/pcm.h
+#include sound/pcm_params.h
+#include sound/soc.h
+#include sound/soc-dapm.h
+#include sound/initval.h
+#include sound/tlv.h
+
+#include twl6030.h
+
+#define TWL6030_RATES   (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define TWL6030_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct twl6030_data {
+   struct snd_soc_codec codec;
+   int codec_powered;
+};
+
+/*
+ * twl6030 register cache  default register settings
+ */
+static const u8 twl6030_reg[TWL6030_CACHEREGNUM] = {
+   0x00, /* not used   0x00*/
+   0x4B, /* TWL6030_ASICID (ro)0x01*/
+   0x00, /* TWL6030_ASICREV (ro)   0x02*/
+   0x00, /* TWL6030_INTID  0x03*/
+   0x41, /* TWL6030_INTMR  0x04*/
+   0x00, /* TWL6030_NCPCTRL0x05*/
+   0x00, /* TWL6030_LDOCTL 0x06*/
+   0x00, /* TWL6030_HPPLLCTL   0x07*/
+   0x00, /* TWL6030_LPPLLCTL   0x08*/
+   0x00, /* TWL6030_LPPLLDIV   0x09*/
+   0x00, /* TWL6030_AMICBCTL   0x0A*/
+   0x00, /* TWL6030_DMICBCTL   0x0B*/
+   0x18, /* TWL6030_MICLCTL0x0C*/
+   0x18, /* TWL6030_MICRCTL0x0D*/
+   0x00, /* TWL6030_MICGAIN0x0E*/
+   0x1B, /* TWL6030_LINEGAIN   0x0F*/
+   0x00, /* TWL6030_HSLCTL 0x10*/
+   0x00, /* TWL6030_HSRCTL 0x11*/
+   0x00, /* TWL6030_HSGAIN 0x12*/
+   0x06, /* 

[PATCHv2 4/7] ASoC: TWL6030: Manual power-up/down sequences

2009-09-25 Thread Lopez Cruz, Misael
TWL6030 codec device can be powered-up/down through a specific
register writes sequence. These sequences can be used when no
gpio line is provided for AUDPWRON.

When the codec is powered-up in this way, automatic power-down
sequence (triggered by thermal shutdown) is not possible.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |  117 +++-
 sound/soc/codecs/twl6030.h |   16 ++
 2 files changed, 120 insertions(+), 13 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 92797e7..f1e333f 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -223,6 +223,88 @@ static void twl6030_init_vdd_regs(struct snd_soc_codec 
*codec)
}
 }
 
+/* twl6030 codec manual power-up sequence */
+static void twl6030_power_up(struct snd_soc_codec *codec)
+{
+   u8 ncpctl, ldoctl, lppllctl, accctl;
+
+   ncpctl = twl6030_read_reg_cache(codec, TWL6030_REG_NCPCTL);
+   ldoctl = twl6030_read_reg_cache(codec, TWL6030_REG_LDOCTL);
+   lppllctl = twl6030_read_reg_cache(codec, TWL6030_REG_LPPLLCTL);
+   accctl = twl6030_read_reg_cache(codec, TWL6030_REG_ACCCTL);
+
+   /* enable reference system */
+   ldoctl |= TWL6030_REFENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   mdelay(10);
+   /* enable internal oscillator */
+   ldoctl |= TWL6030_OSCENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(10);
+   /* enable high-side ldo */
+   ldoctl |= TWL6030_HSLDOENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(244);
+   /* enable negative charge pump */
+   ncpctl |= TWL6030_NCPENA | TWL6030_NCPOPEN;
+   twl6030_write(codec, TWL6030_REG_NCPCTL, ncpctl);
+   udelay(488);
+   /* enable low-side ldo */
+   ldoctl |= TWL6030_LSLDOENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(244);
+   /* enable low-power pll */
+   lppllctl |= TWL6030_LPLLENA;
+   twl6030_write(codec, TWL6030_REG_LPPLLCTL, lppllctl);
+   /* reset state machine */
+   accctl |= TWL6030_RESETSPLIT;
+   twl6030_write(codec, TWL6030_REG_ACCCTL, accctl);
+   mdelay(5);
+   accctl = ~TWL6030_RESETSPLIT;
+   twl6030_write(codec, TWL6030_REG_ACCCTL, accctl);
+   /* disable internal oscillator */
+   ldoctl = ~TWL6030_OSCENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+}
+
+/* twl6030 codec manual power-down sequence */
+static void twl6030_power_down(struct snd_soc_codec *codec)
+{
+   u8 ncpctl, ldoctl, lppllctl, accctl;
+
+   ncpctl = twl6030_read_reg_cache(codec, TWL6030_REG_NCPCTL);
+   ldoctl = twl6030_read_reg_cache(codec, TWL6030_REG_LDOCTL);
+   lppllctl = twl6030_read_reg_cache(codec, TWL6030_REG_LPPLLCTL);
+   accctl = twl6030_read_reg_cache(codec, TWL6030_REG_ACCCTL);
+
+   /* enable internal oscillator */
+   ldoctl |= TWL6030_OSCENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(10);
+   /* disable low-power pll */
+   lppllctl = ~TWL6030_LPLLENA;
+   twl6030_write(codec, TWL6030_REG_LPPLLCTL, lppllctl);
+   /* disable low-side ldo */
+   ldoctl = ~TWL6030_LSLDOENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(244);
+   /* disable negative charge pump */
+   ncpctl = ~(TWL6030_NCPENA | TWL6030_NCPOPEN);
+   twl6030_write(codec, TWL6030_REG_NCPCTL, ncpctl);
+   udelay(488);
+   /* disable high-side ldo */
+   ldoctl = ~TWL6030_HSLDOENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   udelay(244);
+   /* disable internal oscillator */
+   ldoctl = ~TWL6030_OSCENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   /* disable reference system */
+   ldoctl = ~TWL6030_REFENA;
+   twl6030_write(codec, TWL6030_REG_LDOCTL, ldoctl);
+   mdelay(10);
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -460,12 +542,18 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
 
/* power-up sequence latency */
mdelay(16);
-   }
 
-   /* sync registers updated during power-up sequence */
-   twl6030_write_reg_cache(codec, TWL6030_REG_NCPCTL, 0x81);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LDOCTL, 0x45);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL, 0x01);
+   /* sync registers updated during power-up sequence */
+   twl6030_write_reg_cache(codec, TWL6030_REG_NCPCTL,
+   0x81);
+   twl6030_write_reg_cache(codec, TWL6030_REG_LDOCTL,
+   0x45);
+   twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL,
+

[PATCHv2 5/7] ASoC: TWL6030: Add support for low-power mode

2009-09-25 Thread Lopez Cruz, Misael
TWL6030 codec supports two power modes: low-power and high
performance.

In low-power mode, headset downlink must be the only path enabled
and components in that path (headset DAC and driver) should be in
that mode too. In this mode, codec can stream audio at 44.1 and
48 kHz if sys clock from CLK32K is configured to 17.64 and 19.2
MHz using low-power PLL, respectively.

In high-performance mode, codec can only work at 19.2 MHz from
high-performance PLL. All paths supported in the codec can be used
but audio can be streamed only at 48 kHz.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |  214 ++--
 sound/soc/codecs/twl6030.h |   17 
 2 files changed, 202 insertions(+), 29 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index f1e333f..032619d 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -46,6 +46,7 @@
 struct twl6030_data {
struct snd_soc_codec codec;
int codec_powered;
+   unsigned int sysclk;
 };
 
 /*
@@ -305,6 +306,29 @@ static void twl6030_power_down(struct snd_soc_codec *codec)
mdelay(10);
 }
 
+/* set headset dac and driver power mode */
+static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
+{
+   int hslctl, hsrctl;
+   int mask = TWL6030_HSDRVMODEL | TWL6030_HSDACMODEL;
+
+   hslctl = twl6030_read_reg_cache(codec, TWL6030_REG_HSLCTL);
+   hsrctl = twl6030_read_reg_cache(codec, TWL6030_REG_HSRCTL);
+
+   if (high_perf) {
+   hslctl = ~mask;
+   hsrctl = ~mask;
+   } else {
+   hslctl |= mask;
+   hsrctl |= mask;
+   }
+
+   twl6030_write(codec, TWL6030_REG_HSLCTL, hslctl);
+   twl6030_write(codec, TWL6030_REG_HSRCTL, hsrctl);
+
+   return 0;
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -598,6 +622,7 @@ static int twl6030_hw_params(struct snd_pcm_substream 
*substream,
struct snd_soc_pcm_runtime *rtd = substream-private_data;
struct snd_soc_device *socdev = rtd-socdev;
struct snd_soc_codec *codec = socdev-card-codec;
+   struct twl6030_data *priv = codec-private_data;
int rate, format;
 
/* hardware dai (McPDM) requires bit stream of twice
@@ -607,7 +632,20 @@ static int twl6030_hw_params(struct snd_pcm_substream 
*substream,
rate = params_rate(params);
switch (rate) {
case 44100:
+   if (priv-sysclk != 1764) {
+   dev_err(codec-dev,
+   rate %d not supported at current sysclk %d\n,
+   rate, priv-sysclk);
+   return -EINVAL;
+   }
+   break;
case 48000:
+   if (priv-sysclk != 1920) {
+   dev_err(codec-dev,
+   rate %d not supported at current sysclk %d\n,
+   rate, priv-sysclk);
+   return -EINVAL;
+   }
break;
default:
dev_err(codec-dev, unknown rate %d\n, rate);
@@ -630,46 +668,163 @@ static int twl6030_set_dai_sysclk(struct snd_soc_dai 
*codec_dai,
int clk_id, unsigned int freq, int dir)
 {
struct snd_soc_codec *codec = codec_dai-codec;
+   struct twl6030_data *priv = codec-private_data;
u8 hppll, lppll;
 
+   lppll = twl6030_read_reg_cache(codec, TWL6030_REG_LPPLLCTL);
hppll = twl6030_read_reg_cache(codec, TWL6030_REG_HPPLLCTL);
-   hppll = TWL6030_HPLLRST;
-
-   switch (freq) {
-   case 1200:
-   /* MCLK input, PLL enabled */
-   hppll = TWL6030_MCLK_12000KHZ
-   | TWL6030_HPLLSQRBP
-   | TWL6030_HPLLENA;
-   break;
-   case 1920:
-   /* MCLK input, PLL disabled */
-   hppll = TWL6030_MCLK_19200KHZ
-   | TWL6030_HPLLSQRBP
-   | TWL6030_HPLLBP;
+
+   switch (clk_id) {
+   case TWL6030_SYSCLK_SEL_LPPLL:
+   if (freq != 32768) {
+   dev_err(codec-dev, invalid sysclk freq %d\n, freq);
+   return -EINVAL;
+   }
+
+   /* CLK32K input requires low-power PLL */
+   lppll |= TWL6030_LPLLENA | TWL6030_LPLLSEL;
+   twl6030_write(codec, TWL6030_REG_LPPLLCTL, lppll);
+   mdelay(5);
+   lppll = ~TWL6030_HPLLSEL;
+   twl6030_write(codec, TWL6030_REG_LPPLLCTL, lppll);
+
+   /* headset dac and driver must be in low-power mode */
+   headset_power_mode(codec, 0);
+
+   hppll = ~TWL6030_HPLLENA;
+   twl6030_write(codec, TWL6030_REG_HPPLLCTL, hppll);
break;
-   case 2600:
-   /* MCLK input, PLL enabled */
-

[PATCHv2 6/7] ASoC: TWL6030: Enable audio interrupt

2009-09-25 Thread Lopez Cruz, Misael
NAUDINT interrupt line is provided by the TWL6030 codec to signal
externally events like headset plug/unplug, hook, power-up sequence
completion, etc.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |   78 +++-
 sound/soc/codecs/twl6030.h |   10 ++
 2 files changed, 87 insertions(+), 1 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 032619d..5cf2099 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -47,6 +47,7 @@ struct twl6030_data {
struct snd_soc_codec codec;
int codec_powered;
unsigned int sysclk;
+   struct work_struct audint_work;
 };
 
 /*
@@ -329,6 +330,58 @@ static int headset_power_mode(struct snd_soc_codec *codec, 
int high_perf)
return 0;
 }
 
+/* audio interrupt handler */
+irqreturn_t twl6030_naudint_handler(int irq, void *data)
+{
+   struct snd_soc_codec *codec = data;
+   struct twl6030_data *priv = codec-private_data;
+
+   schedule_work(priv-audint_work);
+
+   /* disable audint irq to let workqueue to execute */
+   disable_irq_nosync(irq);
+
+   return IRQ_HANDLED;
+}
+
+void twl6030_naudint_work(struct work_struct *work)
+{
+   struct twl_codec_data *twl_codec;
+   struct snd_soc_codec *codec;
+   struct twl6030_data *priv;
+   u8 intid;
+
+   priv = container_of(work, struct twl6030_data, audint_work);
+   codec = priv-codec;
+   twl_codec = codec-control_data;
+
+   twl_i2c_read_u8(TWL6030_MODULE_AUDIO, intid, TWL6030_REG_INTID);
+
+   switch (intid) {
+   case TWL6030_THINT:
+   dev_alert(codec-dev, die temp over-limit detection\n);
+   break;
+   case TWL6030_PLUGINT:
+   case TWL6030_UNPLUGINT:
+   case TWL6030_HOOKINT:
+   break;
+   case TWL6030_HFINT:
+   dev_alert(codec-dev, hf drivers over current detection\n);
+   break;
+   case TWL6030_VIBINT:
+   dev_alert(codec-dev, vib drivers over current detection\n);
+   break;
+   case TWL6030_READYINT:
+   dev_alert(codec-dev, codec is ready\n);
+   break;
+   default:
+   dev_err(codec-dev, unknown audio interrupt %d\n, intid);
+   break;
+   }
+
+   enable_irq(twl_codec-naudint_irq);
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -610,6 +663,7 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
priv-codec_powered = 0;
break;
}
+
codec-bias_level = level;
 
return 0;
@@ -954,8 +1008,15 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
struct twl6030_data *priv;
struct snd_soc_codec *codec;
int audpwron_gpio = twl_codec-audpwron_gpio;
+   int naudint_irq = twl_codec-naudint_irq;
int ret = 0;
 
+   /* prerequisites */
+   if (!naudint_irq) {
+   dev_err(pdev-dev, no audio interrupt irq supplied\n);
+   return -EINVAL;
+   }
+
priv = kzalloc(sizeof(struct twl6030_data), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
@@ -998,6 +1059,17 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
priv-codec_powered = 0;
}
 
+   /* audio interrupt */
+   INIT_WORK(priv-audint_work, twl6030_naudint_work);
+
+   ret = request_irq(naudint_irq,
+   twl6030_naudint_handler,
+   IRQF_TRIGGER_LOW | IRQF_DISABLED,
+   twl6030-codec,
+   codec);
+   if (ret)
+   goto gpio2_err;
+
/* init vio registers */
twl6030_init_vio_regs(codec);
 
@@ -1006,7 +1078,7 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
 
ret = snd_soc_register_codec(codec);
if (ret)
-   goto gpio2_err;
+   goto reg_err;
 
twl6030_codec = codec;
 
@@ -1019,6 +1091,8 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
 dai_err:
snd_soc_unregister_codec(codec);
twl6030_codec = NULL;
+reg_err:
+   free_irq(naudint_irq, twl_codec);
 gpio2_err:
if (gpio_is_valid(audpwron_gpio))
gpio_free(audpwron_gpio);
@@ -1036,6 +1110,8 @@ static int __devexit twl6030_codec_remove(struct 
platform_device *pdev)
if (gpio_is_valid(twl_codec-audpwron_gpio))
gpio_free(twl_codec-audpwron_gpio);
 
+   free_irq(twl_codec-naudint_irq, twl6030_codec);
+
snd_soc_unregister_dai(twl6030_dai);
snd_soc_unregister_codec(twl6030_codec);
 
diff --git a/sound/soc/codecs/twl6030.h b/sound/soc/codecs/twl6030.h
index 15d3e1b..8a106f2 100644
--- a/sound/soc/codecs/twl6030.h
+++ b/sound/soc/codecs/twl6030.h
@@ -67,6 +67,16 @@
 #define TWL6030_VIOREGNUM  

[PATCHv2 7/7] ASoC: TWL6030: Power-up seq completion through audio interrupt

2009-09-25 Thread Lopez Cruz, Misael
When the codec is powered-up through external AUDPWRON line it starts
its power-up sequence. The completion of the sequence is signaled
through the audio interrupt, and then codec is operational.

CODEC driver starts a wait_for_completion just after AUDPWRON line
transitions from low to high. It's signaled as complete when servicing
READYINT interrupt.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |   46 ---
 1 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 5cf2099..f8bd8ee 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -48,6 +48,7 @@ struct twl6030_data {
int codec_powered;
unsigned int sysclk;
struct work_struct audint_work;
+   struct completion ready_completion;
 };
 
 /*
@@ -58,7 +59,7 @@ static const u8 twl6030_reg[TWL6030_CACHEREGNUM] = {
0x4B, /* TWL6030_ASICID (ro)0x01*/
0x00, /* TWL6030_ASICREV (ro)   0x02*/
0x00, /* TWL6030_INTID  0x03*/
-   0x41, /* TWL6030_INTMR  0x04*/
+   0x00, /* TWL6030_INTMR  0x04*/
0x00, /* TWL6030_NCPCTRL0x05*/
0x00, /* TWL6030_LDOCTL 0x06*/
0x00, /* TWL6030_HPPLLCTL   0x07*/
@@ -186,6 +187,23 @@ static inline void twl6030_write_reg_cache(struct 
snd_soc_codec *codec,
 }
 
 /*
+ * read from twl6030 hardware register
+ */
+static int twl6030_read(struct snd_soc_codec *codec,
+   unsigned int reg)
+{
+   u8 value;
+
+   if (reg  TWL6030_CACHEREGNUM)
+   return -EIO;
+
+   twl_i2c_read_u8(TWL6030_MODULE_AUDIO, value, reg);
+   twl6030_write_reg_cache(codec, reg, value);
+
+   return value;
+}
+
+/*
  * write to the twl6030 register space
  */
 static int twl6030_write(struct snd_soc_codec *codec,
@@ -372,7 +390,8 @@ void twl6030_naudint_work(struct work_struct *work)
dev_alert(codec-dev, vib drivers over current detection\n);
break;
case TWL6030_READYINT:
-   dev_alert(codec-dev, codec is ready\n);
+   priv-codec_powered = 1;
+   complete(priv-ready_completion);
break;
default:
dev_err(codec-dev, unknown audio interrupt %d\n, intid);
@@ -617,25 +636,21 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
/* use AUDPWRON line */
gpio_set_value(audpwron_gpio, 1);
 
-   /* power-up sequence latency */
-   mdelay(16);
+   /* wait for ready interrupt */
+   wait_for_completion(priv-ready_completion);
 
/* sync registers updated during power-up sequence */
-   twl6030_write_reg_cache(codec, TWL6030_REG_NCPCTL,
-   0x81);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LDOCTL,
-   0x45);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL,
-   0x01);
+   twl6030_read(codec, TWL6030_REG_NCPCTL);
+   twl6030_read(codec, TWL6030_REG_LDOCTL);
+   twl6030_read(codec, TWL6030_REG_LPPLLCTL);
} else {
/* use manual power-up sequence */
twl6030_power_up(codec);
+   priv-codec_powered = 1;
}
 
/* initialize vdd/vss registers with reg_cache */
twl6030_init_vdd_regs(codec);
-
-   priv-codec_powered = 1;
break;
case SND_SOC_BIAS_OFF:
if (!priv-codec_powered)
@@ -649,10 +664,8 @@ static int twl6030_set_bias_level(struct snd_soc_codec 
*codec,
udelay(500);
 
/* sync registers updated during power-down sequence */
-   twl6030_write_reg_cache(codec, TWL6030_REG_NCPCTL,
-   0x00);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LDOCTL,
-   0x00);
+   twl6030_read(codec, TWL6030_REG_NCPCTL);
+   twl6030_read(codec, TWL6030_REG_LDOCTL);
twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL,
0x00);
} else {
@@ -1061,6 +1074,7 @@ static int __devinit twl6030_codec_probe(struct 
platform_device *pdev)
 
/* audio interrupt */
INIT_WORK(priv-audint_work, twl6030_naudint_work);
+   init_completion(priv-ready_completion);
 
ret = request_irq(naudint_irq,

RE: [PATCH 1/3] ASoC: TWL6030: Add twl6030 codec driver

2009-09-15 Thread Lopez Cruz, Misael
Mark Brown wrote:
 On Mon, Sep 14, 2009 at 12:00:25PM -0500, Lopez Cruz, Misael wrote:
 
 
 +/* propietary formats */
 +#define SND_SOC_DAIFMT_MCPDM   0x10 /* Texas Instruments
 McPDM */ 
 
 This should really be split out into a separate patch.  Are you
 absolutely positive that this is a proprietary interface that won't
 interoperate with standard PDM?

I think channel slot definition won't make it able to interoperate with
other PDM interfaces. But I may be wrong.

 +static void twl6030_power_up(struct snd_soc_codec *codec) +{
 +   struct snd_soc_device *socdev = codec-socdev;
 +   struct twl6030_setup_data *setup = socdev-codec_data; +
 +   setup-codec_enable(1);
 
 That's interesting...?

The codec is turned on/off through an external line (i.e. with a gpio).
Then, codec enable is board-dependent.

 +static int twl6030_set_bias_level(struct snd_soc_codec *codec,
 +   enum snd_soc_bias_level level) +{
 +   switch (level) {
 +   case SND_SOC_BIAS_ON:
 +   twl6030_power_up(codec);
 +   break;
 +   case SND_SOC_BIAS_PREPARE:
 +   twl6030_power_up(codec);
 +   break;
 +   case SND_SOC_BIAS_STANDBY:
 +   twl6030_power_up(codec);
 +   break;
 +   case SND_SOC_BIAS_OFF:
 +   twl6030_power_down(codec);
 +   break;
 
 Is there any reason not to just fold these functions into the bias
 management?  It looks like the only caller and it'd save
 jumping around the file to find stuff.

For the moment, there is no reason. I thought it was more clear to have
separate power_up/power_down functions, but I can merge them in bias
management function.

 +   /* power on device */
 +   twl6030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +
 +   twl6030_init_chip(codec);
 
 Is the the right ordering?  I'd have expected to see the one time init
 stuff done prior to bringing up the power for the first time.

Yes, it's the right order. codec chip cannot be initialized if the codec
is not already power-up, registers are not accesible before that.

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [alsa-devel] [PATCH 1/3] ASoC: TWL6030: Add twl6030 codec driver

2009-09-15 Thread Lopez Cruz, Misael
Mark Brown wrote:
 On Tue, Sep 15, 2009 at 12:59:44PM -0500, Lopez Cruz, Misael wrote:
 Mark Brown wrote:
 On Mon, Sep 14, 2009 at 12:00:25PM -0500, Lopez Cruz, Misael wrote:
 
 +/* propietary formats */
 +#define SND_SOC_DAIFMT_MCPDM   0x10 /* Texas Instruments
 McPDM */
 
 This should really be split out into a separate patch.  Are you
 absolutely positive that this is a proprietary interface that won't
 interoperate with standard PDM?
 
 I think channel slot definition won't make it able to interoperate
 with other PDM interfaces. But I may be wrong.
 
 I'd not expect full interoperability but I'd expect that at least the
 basic PDM support would interoperate happily.  It wouldn't surprise me
 if more than one manufacturer came up with the same extension
 for multi channel PDM.

If that's the case, then a more appropriate name should be chosen.
Or is it fine for you _MCPDM?

I was thinking in adding _OMAP4_MCPDM, but if you think someone 
else can use the same extension, then _OMAP4 should not go in the
name.

 +static void twl6030_power_up(struct snd_soc_codec *codec) +{
 +   struct snd_soc_device *socdev = codec-socdev;
 +   struct twl6030_setup_data *setup = socdev-codec_data; +
 +   setup-codec_enable(1);
 
 That's interesting...?
 
 The codec is turned on/off through an external line (i.e. with a
 gpio). Then, codec enable is board-dependent.
 
 Might it make more sense to specify a GPIO line instead, at least by
 default? 

Not sure, if the GPIO line is in TWL6030 (mfd) as well then probably
it's fine, which may be the case for now. But isn't it violating
CODEC independency anyway?

If you mean to sustitute the codec_enable function by the GPIO
line, then it opens the possibility to make the CODEC to request and
operate a GPIO line belonging to a different chip, for example
to the application processor.

On the other hand, if a default GPIO line is provided and if it's
not the correct one, the driver will be waiting forever for
power-up sequence to finish (wait_for_completion). Anyway the
wait_for_completion seems too agresive since codec power-up
sequence might fail and boot process will hang.

 +   /* power on device */
 +   twl6030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +
 +   twl6030_init_chip(codec);
 
 Is the the right ordering?  I'd have expected to see the one time
 init stuff done prior to bringing up the power for the first time.
 
 Yes, it's the right order. codec chip cannot be initialized if the
 codec is not already power-up, registers are not accesible before
 that. 
 
 OK.  Looking at this from another angle, shouldn't the chip init be
 rolled into the bias level function to ensure that there aren't any
 cases where it is omitted. 
 
 It's possible that the core may get facilities to allow more use of
 SND_SOC_BIAS_OFF at runtime which would make this more important.

Yes, that's true. Some register may get unconfigured when codec goes
off. I'll check for those scenarios.--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/3] ASoC: TWL6030: Add twl6030 codec driver

2009-09-14 Thread Lopez Cruz, Misael
Initial version of TWL6030 codec driver.

The TWL6030 codec uses a propietary digital audio interface
called McPDM. TWL6030 codec has two power modes: low-power
and high-performance, this initial version only supports
high-performance mode.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 include/sound/soc-dai.h|3 +
 sound/soc/codecs/Kconfig   |4 +
 sound/soc/codecs/Makefile  |2 +
 sound/soc/codecs/twl6030.c |  670 
 sound/soc/codecs/twl6030.h |   95 +++
 5 files changed, 774 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/twl6030.c
 create mode 100644 sound/soc/codecs/twl6030.h

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 352d7ee..8b0d04b 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -35,6 +35,9 @@ struct snd_pcm_substream;
 #define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
 #define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J

+/* propietary formats */
+#define SND_SOC_DAIFMT_MCPDM   0x10 /* Texas Instruments McPDM */
+
 /*
  * DAI Clock gating.
  *
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index bbc97fd..0effb52 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -25,6 +25,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TWL4030 if TWL4030_CORE
+   select SND_SOC_TWL6030 if TWL6030_CORE
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
select SND_SOC_WM8350 if MFD_WM8350
@@ -114,6 +115,9 @@ config SND_SOC_TLV320AIC3X
 config SND_SOC_TWL4030
tristate

+config SND_SOC_TWL6030
+   tristate
+
 config SND_SOC_UDA134X
tristate

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8b75305..b70c8a1 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -13,6 +13,7 @@ snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-twl4030-objs := twl4030.o
+snd-soc-twl6030-objs := twl6030.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wm8350-objs := wm8350.o
@@ -50,6 +51,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)  += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)  += snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
+obj-$(CONFIG_SND_SOC_TWL6030)  += snd-soc-twl6030.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WM8350)   += snd-soc-wm8350.o
diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
new file mode 100644
index 000..c5e76fa
--- /dev/null
+++ b/sound/soc/codecs/twl6030.c
@@ -0,0 +1,670 @@
+/*
+ * ALSA SoC TWL6030 codec driver
+ *
+ * Author:  Misael Lopez Cruz x0052...@ti.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include linux/module.h
+#include linux/moduleparam.h
+#include linux/init.h
+#include linux/delay.h
+#include linux/pm.h
+#include linux/i2c.h
+#include linux/platform_device.h
+#include linux/i2c/twl.h
+
+#include sound/core.h
+#include sound/pcm.h
+#include sound/pcm_params.h
+#include sound/soc.h
+#include sound/soc-dapm.h
+#include sound/initval.h
+#include sound/tlv.h
+
+#include twl6030.h
+
+#define TWL6030_RATES   (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define TWL6030_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+
+/*
+ * twl6030 register cache  default register settings
+ */
+static const u8 twl6030_reg[TWL6030_CACHEREGNUM] = {
+   0x00, /* not used   0x00*/
+   0x4B, /* TWL6030_ASICID (ro)0x01*/
+   0x00, /* TWL6030_ASICREV (ro)   0x02*/
+   0x00, /* TWL6030_INTID  0x03*/
+   0x41, /* TWL6030_INTMR  0x04*/
+   0x00, /* TWL6030_NCPCTRL0x05*/
+   0x00, /* TWL6030_LDOCTL 0x06*/
+   0x00, /* TWL6030_HPPLLCTL   0x07*/
+   0x00, /* TWL6030_LPPLLCTL   0x08*/
+   0x00, /* TWL6030_LPPLLDIV   0x09*/
+   0x00, /* TWL6030_AMICBCTL   0x0A*/
+   0x00, /* TWL6030_DMICBCTL   0x0B*/
+   0x18, /* 

[PATCH 3/3] ASoC: TWL6030: Handle power-up seq completion thru audio interrupt

2009-09-14 Thread Lopez Cruz, Misael
NAUDINT interrupt line is provided by the TWL6030 codec to
signal externally events like headset plug/unplug, hook,
power-up sequence completion, etc.

When the codec is powered-up through external AUDPWRON line it
will start its power-up sequence. The completion of the sequence
is signaled through the audio interrupt, and then codec is
operational.

CODEC driver starts a wait_for_completion just after calling
external power-up callback. It's signaled as complete when
servicing READYINT interrupt.

MACHINE drivers should request IRQ line used in corresponding
hardware platform and initialize workqueue and completion structs
of twl6030_setup_data as well.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |  103 +---
 sound/soc/codecs/twl6030.h |   17 +++
 2 files changed, 113 insertions(+), 7 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index 0f2269e..dc85399 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -43,6 +43,7 @@
 
 /* codec private data */
 struct twl6030_priv_data {
+   int codec_powered;
unsigned int sysclk;
 };
 
@@ -54,7 +55,7 @@ static const u8 twl6030_reg[TWL6030_CACHEREGNUM] = {
0x4B, /* TWL6030_ASICID (ro)0x01*/
0x00, /* TWL6030_ASICREV (ro)   0x02*/
0x00, /* TWL6030_INTID  0x03*/
-   0x41, /* TWL6030_INTMR  0x04*/
+   0x00, /* TWL6030_INTMR  0x04*/
0x00, /* TWL6030_NCPCTRL0x05*/
0x00, /* TWL6030_LDOCTL 0x06*/
0x00, /* TWL6030_HPPLLCTL   0x07*/
@@ -127,6 +128,23 @@ static inline void twl6030_write_reg_cache(struct 
snd_soc_codec *codec,
 }
 
 /*
+ * read from twl6030 hardware register
+ */
+static int twl6030_read(struct snd_soc_codec *codec,
+   unsigned int reg)
+{
+   u8 value;
+
+   if (reg  TWL6030_CACHEREGNUM)
+   return -EIO;
+
+   twl_i2c_read_u8(TWL6030_MODULE_AUDIO, value, reg);
+   twl6030_write_reg_cache(codec, reg, value);
+
+   return value;
+}
+
+/*
  * write to the twl6030 register space
  */
 static int twl6030_write(struct snd_soc_codec *codec,
@@ -159,27 +177,89 @@ static void twl6030_init_chip(struct snd_soc_codec *codec)
 static void twl6030_power_up(struct snd_soc_codec *codec)
 {
struct snd_soc_device *socdev = codec-socdev;
+   struct twl6030_priv_data *priv = codec-private_data;
struct twl6030_setup_data *setup = socdev-codec_data;
 
+   if (priv-codec_powered)
+   return;
+
setup-codec_enable(1);
 
+   /* wait for ready interrupt */
+   wait_for_completion(setup-ready_completion);
+
/* sync registers updated during power-up sequence */
-   twl6030_write_reg_cache(codec, TWL6030_REG_NCPCTL, 0x81);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LDOCTL, 0x45);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL, 0x01);
+   twl6030_read(codec, TWL6030_REG_NCPCTL);
+   twl6030_read(codec, TWL6030_REG_LDOCTL);
+   twl6030_read(codec, TWL6030_REG_LPPLLCTL);
 }
 
 static void twl6030_power_down(struct snd_soc_codec *codec)
 {
struct snd_soc_device *socdev = codec-socdev;
+   struct twl6030_priv_data *priv = codec-private_data;
struct twl6030_setup_data *setup = socdev-codec_data;
 
setup-codec_enable(0);
+   udelay(500);
 
/* sync registers updated during power-down sequence */
-   twl6030_write_reg_cache(codec, TWL6030_REG_NCPCTL, 0x00);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LDOCTL, 0x00);
-   twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL, 0x00);
+   twl6030_read(codec, TWL6030_REG_NCPCTL);
+   twl6030_read(codec, TWL6030_REG_LDOCTL);
+   twl6030_read(codec, TWL6030_REG_LPPLLCTL);
+
+   priv-codec_powered = 0;
+}
+
+/* audio interrupt handler */
+irqreturn_t twl6030_naudint_handler(int irq, void *data)
+{
+   struct twl6030_setup_data *setup = data;
+
+   schedule_work(setup-audint_work);
+
+   /* disable audint irq to let workqueue to execute */
+   disable_irq_nosync(irq);
+
+   return IRQ_HANDLED;
+}
+
+void twl6030_naudint_work(struct work_struct *work)
+{
+   struct snd_soc_codec *codec;
+   struct twl6030_setup_data *setup;
+   struct twl6030_priv_data *priv;
+   u8 intid;
+
+   setup = container_of(work, struct twl6030_setup_data, audint_work);
+   codec = setup-codec;
+   priv = codec-private_data;
+
+   twl_i2c_read_u8(TWL6030_MODULE_AUDIO, intid, TWL6030_REG_INTID);
+
+   switch (intid) {
+   case TWL6030_THINT:
+   dev_alert(codec-dev, die temp over-limit detection\n);
+   break;
+   case TWL6030_PLUGINT:
+   case TWL6030_UNPLUGINT:
+   case TWL6030_HOOKINT:
+   break;
+   case TWL6030_HFINT:
+   dev_alert(codec-dev, hf drivers over 

[PATCH 2/3] ASoC: TWL6030: Add support for low-power mode

2009-09-14 Thread Lopez Cruz, Misael
TWL6030 codec supports two power modes: low-power and
high-performance.

In low-power mode, headset downlink must be the only path
enabled and components in that path (headset DAC and driver)
should be in that mode too. In this mode, codec can
stream audio at 44.1 and 48 kHz if sys clock is configured
to 17.64 and 19.2 MHz from CLK32K using Low-Power PLL,
respectively.

In high-performance mode, codec can only work at 19.2 MHz
from High-Performance PLL. All paths supported in the
codec can be used but the audio can be streamed only
at 48 kHz.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/codecs/twl6030.c |  192 +---
 sound/soc/codecs/twl6030.h |   19 -
 2 files changed, 181 insertions(+), 30 deletions(-)

diff --git a/sound/soc/codecs/twl6030.c b/sound/soc/codecs/twl6030.c
index c5e76fa..0f2269e 100644
--- a/sound/soc/codecs/twl6030.c
+++ b/sound/soc/codecs/twl6030.c
@@ -41,6 +41,11 @@
 #define TWL6030_RATES   (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 #define TWL6030_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
 
+/* codec private data */
+struct twl6030_priv_data {
+   unsigned int sysclk;
+};
+
 /*
  * twl6030 register cache  default register settings
  */
@@ -177,6 +182,29 @@ static void twl6030_power_down(struct snd_soc_codec *codec)
twl6030_write_reg_cache(codec, TWL6030_REG_LPPLLCTL, 0x00);
 }
 
+/* set headset dac and driver power mode */
+static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
+{
+   int hslctl, hsrctl;
+   int  mask = TWL6030_HSDRVMODEL | TWL6030_HSDACMODEL;
+
+   hslctl = twl6030_read_reg_cache(codec, TWL6030_REG_HSLCTL);
+   hsrctl = twl6030_read_reg_cache(codec, TWL6030_REG_HSRCTL);
+
+   if (high_perf) {
+   hslctl = ~mask;
+   hsrctl = ~mask;
+   } else {
+   hslctl |= mask;
+   hsrctl |= mask;
+   }
+
+   twl6030_write(codec, TWL6030_REG_HSLCTL, hslctl);
+   twl6030_write(codec, TWL6030_REG_HSRCTL, hsrctl);
+
+   return 0;
+}
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -419,6 +447,10 @@ static int twl6030_hw_params(struct snd_pcm_substream 
*substream,
   struct snd_pcm_hw_params *params,
   struct snd_soc_dai *dai)
 {
+   struct snd_soc_pcm_runtime *rtd = substream-private_data;
+   struct snd_soc_device *socdev = rtd-socdev;
+   struct snd_soc_codec *codec = socdev-card-codec;
+   struct twl6030_priv_data *twl6030_priv = codec-private_data;
int rate, format;
 
/* hardware dai (McPDM) requires bit stream of twice
@@ -428,7 +460,20 @@ static int twl6030_hw_params(struct snd_pcm_substream 
*substream,
rate = params_rate(params);
switch (rate) {
case 44100:
+   if (twl6030_priv-sysclk != 1764) {
+   dev_err(codec-dev,
+   rate %d not supported at current sysclk %d\n,
+   rate, twl6030_priv-sysclk);
+   return -EINVAL;
+   }
+   break;
case 48000:
+   if (twl6030_priv-sysclk != 1920) {
+   dev_err(codec-dev,
+   rate %d not supported at current sysclk %d\n,
+   rate, twl6030_priv-sysclk);
+   return -EINVAL;
+   }
break;
default:
dev_err(codec-dev, unknown rate %d\n, rate);
@@ -451,46 +496,120 @@ static int twl6030_set_dai_sysclk(struct snd_soc_dai 
*codec_dai,
int clk_id, unsigned int freq, int dir)
 {
struct snd_soc_codec *codec = codec_dai-codec;
+   struct twl6030_priv_data *twl6030_priv = codec-private_data;
u8 hppll, lppll;
 
+   lppll = twl6030_read_reg_cache(codec, TWL6030_REG_LPPLLCTL);
hppll = twl6030_read_reg_cache(codec, TWL6030_REG_HPPLLCTL);
-   hppll = TWL6030_HPLLRST;
-
-   switch (freq) {
-   case 1200:
-   /* MCLK input, PLL enabled */
-   hppll = TWL6030_MCLK_12000KHZ
-   | TWL6030_HPLLSQRBP
-   | TWL6030_HPLLENA;
-   break;
-   case 1920:
-   /* MCLK input, PLL disabled */
-   hppll = TWL6030_MCLK_19200KHZ
-   | TWL6030_HPLLSQRBP
-   | TWL6030_HPLLBP;
+
+   switch (clk_id) {
+   case TWL6030_SYSCLK_SEL_LPPLL:
+   if (freq != 32768) {
+   dev_err(codec-dev, invalid sysclk freq %d\n, freq);
+   return -EINVAL;
+   }
+
+   /* CLK32K input requires low-power PLL */
+   lppll |= TWL6030_LPLLENA | TWL6030_LPLLSEL;
+   twl6030_write(codec, TWL6030_REG_LPPLLCTL, lppll);
+   mdelay(5);
+   lppll = ~TWL6030_HPLLSEL;
+

[PATCH] ASoC: Declare Headset as Mic and Headphone widgets for SDP3430

2009-03-19 Thread Lopez Cruz, Misael
Headset was declared previously as a Headphone widget connecting
HSMIC and HSOL/HSOR pins of TWL4030 codec in SDP430 machine driver.
The capture path becomes invalid as the Headphone widget is not a
valid input endpoint.

Instead of that, the Headset is declared as separate Microphone
and Headphone widgets. Current patch modifies audio map:

- Headset Mic: HSMIC with bias
- Headset Stereophone: HSOL, HSOR

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/sdp3430.c |   24 
 1 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 0a41de6..10f1c86 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -90,8 +90,12 @@ static struct snd_soc_jack hs_jack;
 /* Headset jack detection DAPM pins */
 static struct snd_soc_jack_pin hs_jack_pins[] = {
{
-   .pin = Headset Jack,
-   .mask = SND_JACK_HEADSET,
+   .pin = Headset Mic,
+   .mask = SND_JACK_MICROPHONE,
+   },
+   {
+   .pin = Headset Stereophone,
+   .mask = SND_JACK_HEADPHONE,
},
 };
 
@@ -109,7 +113,8 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = {
 static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
SND_SOC_DAPM_MIC(Ext Mic, NULL),
SND_SOC_DAPM_SPK(Ext Spk, NULL),
-   SND_SOC_DAPM_HP(Headset Jack, NULL),
+   SND_SOC_DAPM_MIC(Headset Mic, NULL),
+   SND_SOC_DAPM_HP(Headset Stereophone, NULL),
 };
 
 static const struct snd_soc_dapm_route audio_map[] = {
@@ -123,11 +128,13 @@ static const struct snd_soc_dapm_route audio_map[] = {
{Ext Spk, NULL, HFL},
{Ext Spk, NULL, HFR},
 
-   /* Headset: HSMIC (with bias), HSOL, HSOR */
-   {Headset Jack, NULL, HSOL},
-   {Headset Jack, NULL, HSOR},
+   /* Headset Mic: HSMIC with bias */
{HSMIC, NULL, Headset Mic Bias},
-   {Headset Mic Bias, NULL, Headset Jack},
+   {Headset Mic Bias, NULL, Headset Mic},
+
+   /* Headset Stereophone (Headphone): HSOL, HSOR */
+   {Headset Stereophone, NULL, HSOL},
+   {Headset Stereophone, NULL, HSOR},
 };
 
 static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
@@ -146,7 +153,8 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
/* SDP3430 connected pins */
snd_soc_dapm_enable_pin(codec, Ext Mic);
snd_soc_dapm_enable_pin(codec, Ext Spk);
-   snd_soc_dapm_disable_pin(codec, Headset Jack);
+   snd_soc_dapm_disable_pin(codec, Headset Mic);
+   snd_soc_dapm_disable_pin(codec, Headset Stereophone);
 
/* TWL4030 not connected pins */
snd_soc_dapm_nc_pin(codec, AUXL);
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] ASoC: Add headset jack detection for SDP3430 machine driver

2009-03-05 Thread Lopez Cruz, Misael
Add headset jack detection for SDP3430 boards using SoC jack
reporting interface. Headset detection on SDP3430 board is
achieved through TWL4030 GPIO_2 pin.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/sdp3430.c |   43 +--
 1 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 4eab4b4..715c648 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -28,6 +28,7 @@
 #include sound/pcm.h
 #include sound/soc.h
 #include sound/soc-dapm.h
+#include sound/jack.h
 
 #include asm/mach-types.h
 #include mach/hardware.h
@@ -122,7 +123,7 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
/* SDP3430 connected pins */
snd_soc_dapm_enable_pin(codec, Ext Mic);
snd_soc_dapm_enable_pin(codec, Ext Spk);
-   snd_soc_dapm_enable_pin(codec, Headset Jack);
+   snd_soc_dapm_disable_pin(codec, Headset Jack);
 
/* TWL4030 not connected pins */
snd_soc_dapm_nc_pin(codec, AUXL);
@@ -144,6 +145,27 @@ static int sdp3430_twl4030_init(struct snd_soc_codec 
*codec)
return ret;
 }
 
+/* Headset jack */
+static struct snd_soc_jack hs_jack;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+   {
+   .pin = Headset Jack,
+   .mask = SND_JACK_HEADSET,
+   },
+};
+
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+   {
+   .gpio = (OMAP_MAX_GPIO_LINES + 2),
+   .name = hsdet-gpio,
+   .report = SND_JACK_HEADSET,
+   .debounce_time = 200,
+   },
+};
+
 /* Digital audio interface glue - connects codec -- CPU */
 static struct snd_soc_dai_link sdp3430_dai = {
.name = TWL4030,
@@ -194,7 +216,21 @@ static int __init sdp3430_soc_init(void)
if (ret)
goto err1;
 
-   return 0;
+   /* Headset jack detection */
+   ret = snd_soc_jack_new(snd_soc_sdp3430, SDP3430 headset jack,
+   SND_JACK_HEADSET, hs_jack);
+   if (ret)
+   return ret;
+
+   ret = snd_soc_jack_add_pins(hs_jack, ARRAY_SIZE(hs_jack_pins),
+   hs_jack_pins);
+   if (ret)
+   return ret;
+
+   ret = snd_soc_jack_add_gpios(hs_jack, ARRAY_SIZE(hs_jack_gpios),
+   hs_jack_gpios);
+
+   return ret;
 
 err1:
printk(KERN_ERR Unable to add platform device\n);
@@ -206,6 +242,9 @@ module_init(sdp3430_soc_init);
 
 static void __exit sdp3430_soc_exit(void)
 {
+   snd_soc_jack_free_gpios(hs_jack, ARRAY_SIZE(hs_jack_gpios),
+   hs_jack_gpios);
+
platform_device_unregister(sdp3430_snd_device);
 }
 module_exit(sdp3430_soc_exit);
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] ASoC: Add DAPM machine widgets to SDP3430 driver

2009-03-04 Thread Lopez Cruz, Misael
Add DAPM machine domain widgets to SDP3430 machine driver.
Interconnection:
* Ext Mic: MAINMIC, SUBMIC
* Ext Spk: HFL, HFR
* Headset Jack: HSMIC, HSOL, HSOR

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/sdp3430.c |   64 ++
 1 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index e226fa7..4eab4b4 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -81,12 +81,76 @@ static struct snd_soc_ops sdp3430_ops = {
.hw_params = sdp3430_hw_params,
 };
 
+/* SDP3430 machine DAPM */
+static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
+   SND_SOC_DAPM_MIC(Ext Mic, NULL),
+   SND_SOC_DAPM_SPK(Ext Spk, NULL),
+   SND_SOC_DAPM_HP(Headset Jack, NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+   /* External Mics: MAINMIC, SUBMIC with bias*/
+   {MAINMIC, NULL, Mic Bias 1},
+   {SUBMIC, NULL, Mic Bias 2},
+   {Mic Bias 1, NULL, Ext Mic},
+   {Mic Bias 2, NULL, Ext Mic},
+
+   /* External Speakers: HFL, HFR */
+   {Ext Spk, NULL, HFL},
+   {Ext Spk, NULL, HFR},
+
+   /* Headset: HSMIC (with bias), HSOL, HSOR */
+   {Headset Jack, NULL, HSOL},
+   {Headset Jack, NULL, HSOR},
+   {HSMIC, NULL, Headset Mic Bias},
+   {Headset Mic Bias, NULL, Headset Jack},
+};
+
+static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
+{
+   int ret;
+
+   /* Add SDP3430 specific widgets */
+   ret = snd_soc_dapm_new_controls(codec, sdp3430_twl4030_dapm_widgets,
+   ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
+   if (ret)
+   return ret;
+
+   /* Set up SDP3430 specific audio path audio_map */
+   snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+   /* SDP3430 connected pins */
+   snd_soc_dapm_enable_pin(codec, Ext Mic);
+   snd_soc_dapm_enable_pin(codec, Ext Spk);
+   snd_soc_dapm_enable_pin(codec, Headset Jack);
+
+   /* TWL4030 not connected pins */
+   snd_soc_dapm_nc_pin(codec, AUXL);
+   snd_soc_dapm_nc_pin(codec, AUXR);
+   snd_soc_dapm_nc_pin(codec, CARKITMIC);
+   snd_soc_dapm_nc_pin(codec, DIGIMIC0);
+   snd_soc_dapm_nc_pin(codec, DIGIMIC1);
+
+   snd_soc_dapm_nc_pin(codec, OUTL);
+   snd_soc_dapm_nc_pin(codec, OUTR);
+   snd_soc_dapm_nc_pin(codec, EARPIECE);
+   snd_soc_dapm_nc_pin(codec, PREDRIVEL);
+   snd_soc_dapm_nc_pin(codec, PREDRIVER);
+   snd_soc_dapm_nc_pin(codec, CARKITL);
+   snd_soc_dapm_nc_pin(codec, CARKITR);
+
+   ret = snd_soc_dapm_sync(codec);
+
+   return ret;
+}
+
 /* Digital audio interface glue - connects codec -- CPU */
 static struct snd_soc_dai_link sdp3430_dai = {
.name = TWL4030,
.stream_name = TWL4030,
.cpu_dai = omap_mcbsp_dai[0],
.codec_dai = twl4030_dai,
+   .init = sdp3430_twl4030_init,
.ops = sdp3430_ops,
 };
 
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] ASoC: Add headset jack detection for SDP3430 machine driver

2009-03-04 Thread Lopez Cruz, Misael
Add headset jack detection for SDP3430 boards using SoC jack
reporting interface. Headset detection on SDP3430 board is
achieved through TWL4030 GPIO_2 pin.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/sdp3430.c |   49 -
 1 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 4eab4b4..b595aa4 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -28,6 +28,7 @@
 #include sound/pcm.h
 #include sound/soc.h
 #include sound/soc-dapm.h
+#include sound/jack.h
 
 #include asm/mach-types.h
 #include mach/hardware.h
@@ -122,7 +123,7 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
/* SDP3430 connected pins */
snd_soc_dapm_enable_pin(codec, Ext Mic);
snd_soc_dapm_enable_pin(codec, Ext Spk);
-   snd_soc_dapm_enable_pin(codec, Headset Jack);
+   snd_soc_dapm_disable_pin(codec, Headset Jack);
 
/* TWL4030 not connected pins */
snd_soc_dapm_nc_pin(codec, AUXL);
@@ -144,6 +145,29 @@ static int sdp3430_twl4030_init(struct snd_soc_codec 
*codec)
return ret;
 }
 
+/* Headset jack */
+struct snd_soc_jack *hs_jack;
+
+/* Headset jack DAPM pins */
+struct snd_soc_jack_pin hs_jack_pins[] = {
+   {
+   .pin = Headset Jack,
+   .mask = SND_JACK_HEADSET,
+   .invert = 0,
+   },
+};
+
+/* Headset jack gpios */
+struct snd_soc_jack_gpio hs_jack_gpios[] = {
+   {
+   .gpio = (OMAP_MAX_GPIO_LINES + 2),
+   .name = hsdet-gpio,
+   .report = SND_JACK_HEADSET,
+   .invert = 0,
+   .debounce_time = 200,
+   },
+};
+
 /* Digital audio interface glue - connects codec -- CPU */
 static struct snd_soc_dai_link sdp3430_dai = {
.name = TWL4030,
@@ -194,8 +218,25 @@ static int __init sdp3430_soc_init(void)
if (ret)
goto err1;
 
-   return 0;
+   /* Headset jack detection */
+   hs_jack = kzalloc(sizeof(struct snd_soc_jack), GFP_KERNEL);
+   if (!hs_jack)
+   return -ENOMEM;
+
+   ret = snd_soc_jack_new(snd_soc_sdp3430, SDP3430 headset jack,
+   SND_JACK_HEADSET, hs_jack);
+   if (ret)
+   return ret;
+
+   ret = snd_soc_jack_add_pins(hs_jack, ARRAY_SIZE(hs_jack_pins),
+   hs_jack_pins);
+   if (ret)
+   return ret;
+
+   ret = snd_soc_jack_add_gpios(hs_jack, ARRAY_SIZE(hs_jack_gpios),
+   hs_jack_gpios);
 
+   return ret;
 err1:
printk(KERN_ERR Unable to add platform device\n);
platform_device_put(sdp3430_snd_device);
@@ -206,6 +247,10 @@ module_init(sdp3430_soc_init);
 
 static void __exit sdp3430_soc_exit(void)
 {
+   snd_soc_jack_free_gpios(hs_jack, ARRAY_SIZE(hs_jack_gpios),
+   hs_jack_gpios);
+   kfree(hs_jack);
+
platform_device_unregister(sdp3430_snd_device);
 }
 module_exit(sdp3430_soc_exit);
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 2/2] ASoC: Add headset jack detection for SDP3430 machine driver

2009-03-04 Thread Lopez Cruz, Misael

  +   ret = snd_soc_jack_new(snd_soc_sdp3430, SDP3430 headset jack,
  +   SND_JACK_HEADSET, hs_jack);
  +   if (ret)
  +   return ret;

 This leaks the jack.

If hs_jack is declared as a direct static variable instead, then no mem
leaks, isn't it? Or do you mean to clean the hs_jack if any error?

-Misa--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [alsa-devel] [PATCH 1/3] ASoC: Add GPIO support for jack reporting interface

2009-03-02 Thread Lopez Cruz, Misael

  Could we leave the actual implementation of this report function to
  the machine driver? Since the things being done in detection function
  are common (even if other status are wanted to be updated), then
  probably machine driver could define a specific function (action)
  for doing extra tasks, it can be called from generic gpio detect
  function. Could it be a valid approach?

 That sounds like adding a callback for power updates on the jack itself
 to me (which isn't a bad idea), rather than changing the report function
 of the jack detection method.  The need for machine-specific extra
 actions probably isn't specific to jacks that are detected via GPIOs.

In that situation, power updates should come only when the jack reporting
bits are either all active (jack enabled) or none (jack disabled), is that
correct?

If so, then machine drivers can create callbacks receiving the soc_codec
the jack belongs to and the current state of the jack. All the power updates
(dapm_enable_pin/damp_disable_pin) will happen in the callback in machine
driver but the dapm sync will happen in soc jack framework (i.e. when
reporting current status of the jack).

-Misa--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [alsa-devel] [PATCH 1/3] ASoC: Add GPIO support for jack reporting interface

2009-03-02 Thread Lopez Cruz, Misael

   That sounds like adding a callback for power updates on the jack
   itself to me (which isn't a bad idea), rather than changing the 
   report function of the jack detection method.  The need for
   machine-specific extra actions probably isn't specific to jacks
   that are detected via GPIOs.

  In that situation, power updates should come only when the jack
  reporting bits are either all active (jack enabled) or none (jack 
  disabled), is that correct?

 No, the jack detect bits can change independently - you won't always
 physically be able to get everything that can be detected to report at
 once (eg, something that can distinguish between headphones and line
 output) or things may not always be present together (eg, a jack could
 detect headphones but no microphone even if it's possible  that both
 may be present simultaneously).

Then, when to trigger the callback? Every time jack status is going to
be updated?
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [alsa-devel] [PATCH 1/3] ASoC: Add GPIO support for jack reporting interface

2009-02-27 Thread Lopez Cruz, Misael

   struct snd_soc_jack_pin {
  +   struct snd_soc_jack *jack;
  +   struct snd_soc_jack_gpio *gpio_pin;
  struct list_head list;
  const char *pin;
  int mask;
  bool invert;
  +   /* GPIO */
  +   unsigned int gpio;
  +   unsigned int irq;
  +   unsigned long irqflags;
  +   irq_handler_t handler;
  +   struct work_struct work;
   };
 
 This needs to be rethought - it breaks the abstraction layers.

Ok, I see. Here is the new plan:

* Create a new structure snd_soc_jack_gpio holding info specific for a
  gpio pin like: gpio, irq, irqflags, irqhandler, private data (to be
  passed to irqhandler).

* Create a new function snd_soc_jack_add_gpios to add all jack_gpios that
  belong to a specific jack. This function should add all gpio pin references
  in a linked list as it's done for dapm pins. The linked list will be
  useful to be able to release acquired resources in another function
  snd_soc_jack_free_gpios.

* Machine driver will be responsible to call add_gpios function passing an
  array of gpios related to each jack.

* Machine driver will tie each jack_gpio with corresponding jack in a
  machine specific jack_data structure, one hook per jack_gpio in the jack.
  A handler will also be associated to the jack_data structure. This
  jack_data struct will be passed to the gpio irqhandler as private data.

-Misa--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/3] GPIO for jack reporting interface

2009-02-25 Thread Lopez Cruz, Misael
The following patch set implements GPIO support for SoC jack reporting
interface and uses it in SDP3430 machine driver.

The jack detection interface is used in SDP3430 driver to handle headset
events. That requires DAPM machine widgets to be added to the machine
driver before the actual use of the interface. 

ASoC: Add GPIO support for jack reporting interface
ASoC: Add DAPM machine widgets to SDP3430 driver
ASoC: Add headset jack detection for SDP3430 machine driver--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/3] ASoC: Add GPIO support for jack reporting interface

2009-02-25 Thread Lopez Cruz, Misael
Add GPIO support for jack reporting framework in ASoC, by using
gpiolib calls. It's only required to append GPIO information (gpio
number, irq handler and flags) to standard jack_pin declaration.
GPIO request, data direction configuration and irq request are
handled by the utility.

The minimal GPIO information that can be provided is the gpio number,
in that case default handler/flags will be used. Default handler queues
a work that reads the current value in the gpio pin and informs to the
jack framework.

If the GPIO support is not required, the gpio field ot jack_pin
structure must be set to NO_JACK_PIN_GPIO.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 include/sound/soc.h  |   15 ++
 sound/soc/soc-jack.c |   70 -
 2 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 68d8149..846e2c1 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -16,6 +16,8 @@
 #include linux/platform_device.h
 #include linux/types.h
 #include linux/workqueue.h
+#include linux/interrupt.h
+#include linux/kernel.h
 #include sound/core.h
 #include sound/pcm.h
 #include sound/control.h
@@ -254,14 +256,27 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
  * @pin:name of the pin to update
  * @mask:   bits to check for in reported jack status
  * @invert: if non-zero then pin is enabled when status is not reported
+ * @gpio:   gpio number associated to the pin (gpiolib calls will be used)
+ * @irqflags IRQ flags
+ * @handler: handler for servicing interrupt events on gpio pin
  */
 struct snd_soc_jack_pin {
+   struct snd_soc_jack *jack;
+   struct snd_soc_jack_gpio *gpio_pin;
struct list_head list;
const char *pin;
int mask;
bool invert;
+   /* GPIO */
+   unsigned int gpio;
+   unsigned int irq;
+   unsigned long irqflags;
+   irq_handler_t handler;
+   struct work_struct work;
 };
 
+#define NO_JACK_PIN_GPIO   UINT_MAX
+
 struct snd_soc_jack {
struct snd_jack *jack;
struct snd_soc_card *card;
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 8cc00c3..0d048b2 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -14,6 +14,9 @@
 #include sound/jack.h
 #include sound/soc.h
 #include sound/soc-dapm.h
+#include linux/gpio.h
+#include linux/interrupt.h
+#include linux/workqueue.h
 
 /**
  * snd_soc_jack_new - Create a new jack
@@ -96,6 +99,32 @@ out:
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
 
+/* Default IRQ handler for a GPIO jack pin, it will queue a
+ * work that reads current value in GPIO pin and reports it
+ * to the jack framework.
+ */
+static irqreturn_t gpio_interrupt(int irq, void *data)
+{
+   struct snd_soc_jack_pin *pin = data;
+
+   return IRQ_RETVAL(schedule_work(pin-work));
+}
+
+static void gpio_work(struct work_struct *work)
+{
+   struct snd_soc_jack_pin *pin;
+   int report;
+
+   pin = container_of(work, struct snd_soc_jack_pin, work);
+   report = pin-jack-status  pin-mask;
+   if (gpio_get_value(pin-gpio))
+   report |= pin-mask;
+   else
+   report = ~pin-mask;
+
+   snd_soc_jack_report(pin-jack, report, pin-jack-jack-type);
+}
+
 /**
  * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack
  *
@@ -106,11 +135,18 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_report);
  * After this function has been called the DAPM pins specified in the
  * pins array will have their status updated to reflect the current
  * state of the jack whenever the jack status is updated.
+ *
+ * A GPIO pin (using gpiolib) can be used to detect events. It requieres
+ * an IRQ handler and flags to be set in jack_pin structure; if they are
+ * not provided, default handler/flags will be used instead. If this
+ * feature is not desired, gpio field of jack_pin structure must be
+ * set to NO_JACK_PIN_GPIO.
  */
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
  struct snd_soc_jack_pin *pins)
 {
-   int i;
+   unsigned int gpio = 0;
+   int i, ret = 0;
 
for (i = 0; i  count; i++) {
if (!pins[i].pin) {
@@ -123,6 +159,32 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int 
count,
return -EINVAL;
}
 
+   if (pins[i].gpio != NO_JACK_PIN_GPIO) {
+   pins[i].jack = jack;
+   gpio = pins[i].gpio;
+   ret = gpio_request(gpio, pins[i].pin);
+   if (ret)
+   return ret;
+
+   ret = gpio_direction_input(gpio);
+   if (ret)
+   goto out;
+   pins[i].irq = gpio_to_irq(gpio);
+   /* If none set, use the default handler */
+   if (!pins[i].handler) {
+   

[PATCH 2/3] ASoC: Add DAPM machine widgets to SDP3430 driver

2009-02-25 Thread Lopez Cruz, Misael
Add DAPM machine domain widgets to SDP3430 machine driver.
Current interconection:
* Ext Mic: MAINMIC, SUBMIC
* Ext Spk: HFL, HFR
* Headset Jack: HSMIC, HSOL, HSOR

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/sdp3430.c |   61 ++
 1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index e226fa7..7a996d9 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -81,12 +81,73 @@ static struct snd_soc_ops sdp3430_ops = {
.hw_params = sdp3430_hw_params,
 };
 
+/* SDP3430 machine DAPM */
+static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
+   SND_SOC_DAPM_MIC(Ext Mic, NULL),
+   SND_SOC_DAPM_SPK(Ext Spk, NULL),
+   SND_SOC_DAPM_HP(Headset Jack, NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+   /* External Mics: MAINMIC, SUBMIC */
+   {MAINMIC, NULL, Ext Mic},
+   {SUBMIC, NULL, Ext Mic},
+
+   /* External Speakers: HFL, HFR */
+   {Ext Spk, NULL, HFL},
+   {Ext Spk, NULL, HFR},
+
+   /* Headset: HSMIC, HSOL, HSOR */
+   {Headset Jack, NULL, HSOL},
+   {Headset Jack, NULL, HSOR},
+   {HSMIC, NULL, Headset Jack},
+};
+
+static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
+{
+   int ret;
+
+   /* SDP3430 connected pins */
+   snd_soc_dapm_enable_pin(codec, Ext Mic);
+   snd_soc_dapm_enable_pin(codec, Ext Spk);
+   snd_soc_dapm_enable_pin(codec, Headset Jack);
+
+   /* TWL4030 not connected pins */
+   snd_soc_dapm_nc_pin(codec, AUXL);
+   snd_soc_dapm_nc_pin(codec, AUXR);
+   snd_soc_dapm_nc_pin(codec, CARKITMIC);
+   snd_soc_dapm_nc_pin(codec, DIGIMIC0);
+   snd_soc_dapm_nc_pin(codec, DIGIMIC1);
+
+   snd_soc_dapm_nc_pin(codec, OUTL);
+   snd_soc_dapm_nc_pin(codec, OUTR);
+   snd_soc_dapm_nc_pin(codec, EARPIECE);
+   snd_soc_dapm_nc_pin(codec, PREDRIVEL);
+   snd_soc_dapm_nc_pin(codec, PREDRIVER);
+   snd_soc_dapm_nc_pin(codec, CARKITL);
+   snd_soc_dapm_nc_pin(codec, CARKITR);
+
+   /* Add SDP3430 specific widgets */
+   ret = snd_soc_dapm_new_controls(codec, sdp3430_twl4030_dapm_widgets,
+   ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
+   if (ret)
+   return ret;
+
+   /* Set up SDP3430 specific audio path audio_map */
+   snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+   ret = snd_soc_dapm_sync(codec);
+
+   return ret;
+}
+
 /* Digital audio interface glue - connects codec -- CPU */
 static struct snd_soc_dai_link sdp3430_dai = {
.name = TWL4030,
.stream_name = TWL4030,
.cpu_dai = omap_mcbsp_dai[0],
.codec_dai = twl4030_dai,
+   .init = sdp3430_twl4030_init,
.ops = sdp3430_ops,
 };
 
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/3] ASoC: Add headset jack detection for SDP3430 machine driver

2009-02-25 Thread Lopez Cruz, Misael
Add headset jack detection for SDP3430 boards using SoC jack
reporting interface. Headset detection on SDP3430 board is
achieved through TWL4030 GPIO_2 pin.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/sdp3430.c |   31 ++-
 1 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 7a996d9..7695675 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -28,6 +28,7 @@
 #include sound/pcm.h
 #include sound/soc.h
 #include sound/soc-dapm.h
+#include sound/jack.h
 
 #include asm/mach-types.h
 #include mach/hardware.h
@@ -141,6 +142,18 @@ static int sdp3430_twl4030_init(struct snd_soc_codec 
*codec)
return ret;
 }
 
+/* Jack detection */
+struct snd_soc_jack *sdp3430_jack;
+
+struct snd_soc_jack_pin sdp3430_jack_pins[] = {
+   {
+   .pin = Headset Jack,
+   .mask = SND_JACK_HEADSET,
+   .invert = 0,
+   .gpio = (OMAP_MAX_GPIO_LINES + 2),
+   },
+};
+
 /* Digital audio interface glue - connects codec -- CPU */
 static struct snd_soc_dai_link sdp3430_dai = {
.name = TWL4030,
@@ -191,7 +204,23 @@ static int __init sdp3430_soc_init(void)
if (ret)
goto err1;
 
-   return 0;
+   /* Jack detection */
+   sdp3430_jack = kzalloc(sizeof(struct snd_soc_jack), GFP_KERNEL);
+   if (!sdp3430_jack) {
+   printk(KERN_ERR SDP3430 SoC Jack allocation failed\n);
+   return -ENOMEM;
+   }
+
+   snd_soc_jack_new(snd_soc_sdp3430, SDP3430 SoC Jack,
+   SND_JACK_HEADSET, sdp3430_jack);
+   if (ret)
+   return ret;
+
+   ret = snd_soc_jack_add_pins(sdp3430_jack,
+   ARRAY_SIZE(sdp3430_jack_pins),
+   sdp3430_jack_pins);
+
+   return ret;
 
 err1:
printk(KERN_ERR Unable to add platform device\n);
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: Configuring a TWL GPIO pin as an interrupt

2009-02-24 Thread Lopez Cruz, Misael
 If these are CPU side GPIOs that you're talking about you'll 
 also want to write the standard utility for using gpiolib for 
 jack detection that I've not got round to doing yet :)

The GPIOs belong to a submodule of TWL4030, but they are configured
using standard gpiolib.

About adding GPIO functionality to jack detection, if the right
place to request GPIOs and set its data direction is in board files
(arch/*/mach-*/board-*.c), then there won't be much to do in jack
code, only the irq request. Unless we move request and data direction
setting to jack detection layer.

-Misa--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: Configuring a TWL GPIO pin as an interrupt

2009-02-23 Thread Lopez Cruz, Misael
 On Sunday 22 February 2009, Lopez Cruz, Misael wrote:
  In the particular case of ALSA SoC, could the machine/board 
  driver be a better place to handle all GPIO/IRQ configuration?
  That driver also contains only board specific code.
 
 It'd be best of the ASoC stuff could sit with all the other 
 board-specfic init code, in arch/*/mach-*/board-*.c files, 
 but I understand those interfaces are not yet stable enough 
 to support that ... that's why they're in sound/soc/*/*.c 
 files instead.
 
 In any case ... everything I said still stands.  If you're 
 doing this for ASoC, you'll need some way to pass data to the 
 ASoC board-specific code from normal board-specific code, 
 since some of the relevant config data is not static.

I think that if I move the platform_device registration from machine driver to 
board file I can append jack detection information (gpio pin, irq) through 
platform_data of dev field in platform_device structure. And then in the 
probe part in ASoC machine driver I can receive it.

Could that be correct? Any other better/standard option?

 The current ASoC model seems to be biased towards static 
 configurations.  Notice how it's got to create its own 
 platform_device nodes ... it can't easily use the standard 
 mechanisms for associating platform_data or archdata with 
 those nodes, ditto clocks.--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: Configuring a TWL GPIO pin as an interrupt

2009-02-22 Thread Lopez Cruz, Misael
  I'm interested in bringing headset detection feature for audio. The
  detection is done through TWL GPIO_2. How can I configure a GPIO pin
  to generate an interrupt? Is there any API? Could you please point
  out another driver using that functionality so I can use as reference?

In the setup() callback for the TWL4030 GPIOs:
 {
  int GPIO_NUMBER = gpio_base + 2;
 gpio_request(GPIO_NUMBER, Headset IRQ);
 gpio_direction_input(GPIO_NUMBER);
  lm8323_board_info.irq = gpio_to_irq(GPIO_NUMBER);
  ... something registers this board_info ...
  return 0;
 }

 and then later the lm8323 driver will use that IRQ:

 request_irq(client-irq, lm8323_irq, flags | IRQF_SHARED, DRIVER_NAME, dev);

 that should do it :-)

 see that GPIO_NUMBER will be gpio_base + 2, base is board-specific

  and hence client-irq is also board-specific,
 which is why it needs to be set up

In the particular case of ALSA SoC, could the machine/board driver be a better 
place to handle all GPIO/IRQ configuration? That driver also contains only 
board specific code.--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] ASoC: Replace snd_soc_machine by snd_soc_card structure in SDP3430 machine driver

2009-02-10 Thread Lopez Cruz, Misael
This patch replaces snd_soc_machine structure by snd_soc_card in
SP3430 driver. This change is needed in SDP3430 driver to reflect
changes introduced by ASoC: Rename snd_soc_card to snd_soc_machine patch
(875065491fba8eb13219f16c36e79a6fb4e15c68).

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/sdp3430.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index ad97836..e226fa7 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -91,7 +91,7 @@ static struct snd_soc_dai_link sdp3430_dai = {
 };
 
 /* Audio machine driver */
-static struct snd_soc_machine snd_soc_machine_sdp3430 = {
+static struct snd_soc_card snd_soc_sdp3430 = {
.name = SDP3430,
.platform = omap_soc_platform,
.dai_link = sdp3430_dai,
@@ -100,7 +100,7 @@ static struct snd_soc_machine snd_soc_machine_sdp3430 = {
 
 /* Audio subsystem */
 static struct snd_soc_device sdp3430_snd_devdata = {
-   .machine = snd_soc_machine_sdp3430,
+   .card = snd_soc_sdp3430,
.codec_dev = soc_codec_dev_twl4030,
 };
 
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH] ASoC: Replace snd_soc_machine by snd_soc_card structure in SDP3430 machine driver

2009-02-09 Thread Lopez Cruz, Misael
 On Tue, 10 Feb 2009 00:57:00 +0100
 ext Lopez Cruz, Misael x0052...@ti.com wrote:
 
  This patch replaces snd_soc_machine structure by snd_soc_card in 
  SP3430 driver. This change is needed in SDP3430 driver to reflect 
  changes introduced by ASoC: Rename snd_soc_card to snd_soc_machine
  patch (875065491fba8eb13219f16c36e79a6fb4e15c68).
  
  Signed-off-by: Misael Lopez Cruz x0052...@ti.com
  ---
   sound/soc/omap/sdp3430.c |4 ++--
   1 files changed, 2 insertions(+), 2 deletions(-)
  
 Looks like you haven't subscribed to alsa-devel since I don't 
 see your patch there? You can subscribe but have mail 
 delivery disabled if you don't want to get mailing list 
 traffic to your account.

I'm sorry I used 'alsa-devel-request' instead of 'alsa-devel'. I'll resend the 
patch right away.

 Patch itself looks like for 2.6.29-rc since it fixes a 
 compilation error. Ack from me, compile tested on linux-omap.
 
 Acked-by: Jarkko Nikula jarkko.nik...@nokia.com
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] SoC: OMAP: Initialize XCCR and RCCR registers in McBSP DAI driver

2009-01-23 Thread Lopez Cruz, Misael
This patch explicitly initializes McBSP Transmit Configuration
Control Register (XCCR) and Receive Configuration Control
Register (RCCR) to their reset values. Reset values are 26 ns
of DX delay and Transmit DMA disabled for XCCR register;
receive full cycle mode enabled and Receive DMA disabled for
RCCR register.

This patch requires a counterpart in OMAP McBSP driver before
to apply it. The required changes in McBSP were sent and approved
in linux-omap mailing list and patch is going upstream
(commit 3456ef483b5322ba4a7647f024e2c5b7846cd7e3 from linux-omap-2.6
tree).

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/omap-mcbsp.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 8485a8a..f50cbaf 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -295,6 +295,10 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai 
*cpu_dai,
regs-spcr1 |= RINTM(3);
regs-rcr2  |= RFIG;
regs-xcr2  |= XFIG;
+   if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+   regs-xccr = DXENDLY(1) | XDMAEN;
+   regs-rccr = RFULL_CYCLE | RDMAEN;
+   }
 
switch (fmt  SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] ARM: OMAP3: Initialize XCCR and RCCR McBSP registers for McBSP DAI driver

2008-12-18 Thread Lopez Cruz, Misael
This patch enables XCCR and RCCR McBSP register writing in OMAP 24xx/34xx
platforms. It also explicitly initializes those registers to their default
values in ASoC McBSP DAI driver.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 arch/arm/plat-omap/include/mach/mcbsp.h |6 ++
 arch/arm/plat-omap/mcbsp.c  |4 
 sound/soc/omap/omap-mcbsp.c |4 
 3 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h 
b/arch/arm/plat-omap/include/mach/mcbsp.h
index 6a0d1a0..5885f3a 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/mach/mcbsp.h
@@ -231,11 +231,16 @@
 #define XPBBLK(value)  ((value)7)/* Bits 7:8 */
 
 /*** McBSP XCCR bit definitions */
+#define EXTCLKGATE 0x8000
+#define PPCONNECT  0x4000
+#define DXENDLY(value) ((value)12)   /* Bits 12:13 */
+#define XFULL_CYCLE0x0800
 #define DILB   0x0020
 #define XDMAEN 0x0008
 #define XDISABLE   0x0001

 /** McBSP RCCR bit definitions */
+#define RFULL_CYCLE0x0800
 #define RDMAEN 0x0008
 #define RDISABLE   0x0001

@@ -267,6 +271,8 @@ struct omap_mcbsp_reg_cfg {
u16 rcerh;
u16 xcerg;
u16 xcerh;
+   u16 xccr;
+   u16 rccr;
 };
 
 typedef enum {
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index af33fc7..d71b30b 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -173,6 +173,10 @@ void omap_mcbsp_config(unsigned int id, const struct 
omap_mcbsp_reg_cfg *config)
OMAP_MCBSP_WRITE(io_base, MCR2, config-mcr2);
OMAP_MCBSP_WRITE(io_base, MCR1, config-mcr1);
OMAP_MCBSP_WRITE(io_base, PCR0, config-pcr0);
+   if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+   OMAP_MCBSP_WRITE(io_base, XCCR, config-xccr);
+   OMAP_MCBSP_WRITE(io_base, RCCR, config-rccr);
+   }
 }
 EXPORT_SYMBOL(omap_mcbsp_config);
 
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 8485a8a..2e7000d 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -295,6 +295,10 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai 
*cpu_dai,
regs-spcr1 |= RINTM(3);
regs-rcr2  |= RFIG;
regs-xcr2  |= XFIG;
+   if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+   regs-xccr = DXENDLY(1) | XDMAEN;
+   regs-rccr = RFULL_CYCLE | RDMAEN;
+   }
 
switch (fmt  SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] ARM: OMAP3: Enable writing to XCCR and RCCR McBSP registers for OMAP 2430/34xx

2008-12-18 Thread Lopez Cruz, Misael
This patch enables writing to McBSP Transmit Configuration Control
Register (XCCR) and Receive Configuration Control Register (RCCR)
for 2430/34xx platforms. It also adds XCCR, RCCR entries in McBSP
register configuration structure and bit definitions for both
registers.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 arch/arm/plat-omap/include/mach/mcbsp.h |7 +++
 arch/arm/plat-omap/mcbsp.c  |4 
 2 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h 
b/arch/arm/plat-omap/include/mach/mcbsp.h
index 6a0d1a0..cc48f2f 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/mach/mcbsp.h
@@ -231,11 +231,16 @@
 #define XPBBLK(value)  ((value)7)/* Bits 7:8 */
 
 /*** McBSP XCCR bit definitions */
+#define EXTCLKGATE 0x8000
+#define PPCONNECT  0x4000
+#define DXENDLY(value) ((value)12)   /* Bits 12:13 */
+#define XFULL_CYCLE0x0800
 #define DILB   0x0020
 #define XDMAEN 0x0008
 #define XDISABLE   0x0001
 
 /** McBSP RCCR bit definitions */
+#define RFULL_CYCLE0x0800
 #define RDMAEN 0x0008
 #define RDISABLE   0x0001
 
@@ -267,6 +272,8 @@ struct omap_mcbsp_reg_cfg {
u16 rcerh;
u16 xcerg;
u16 xcerh;
+   u16 xccr;
+   u16 rccr;
 };
 
 typedef enum {
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index af33fc7..f2401a8 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -173,6 +173,10 @@ void omap_mcbsp_config(unsigned int id, const struct 
omap_mcbsp_reg_cfg *config)
OMAP_MCBSP_WRITE(io_base, MCR2, config-mcr2);
OMAP_MCBSP_WRITE(io_base, MCR1, config-mcr1);
OMAP_MCBSP_WRITE(io_base, PCR0, config-pcr0);
+   if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+   OMAP_MCBSP_WRITE(io_base, XCCR, config-xccr);
+   OMAP_MCBSP_WRITE(io_base, RCCR, config-rccr);
+   }
 }
 EXPORT_SYMBOL(omap_mcbsp_config);
 
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


SoC: OMAP: Initialize XCCR and RCCR registers in McBSP DAI driver

2008-12-18 Thread Lopez Cruz, Misael
This patch explicitly initializes McBSP Transmit Configuration
Control Register (XCCR) and Receive Configuration Control
Register (RCCR) to their reset values. Reset values are 26 ns
of DX delay and Transmit DMA disabled for XCCR register;
receive full cycle mode enabled and Receive DMA disabled for
RCCR register.

Signed-off-by: Misael Lopez Cruz x0052...@ti.com
---
 sound/soc/omap/omap-mcbsp.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 8485a8a..f50cbaf 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -295,6 +295,10 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai 
*cpu_dai,
regs-spcr1 |= RINTM(3);
regs-rcr2  |= RFIG;
regs-xcr2  |= XFIG;
+   if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+   regs-xccr = DXENDLY(1) | XDMAEN;
+   regs-rccr = RFULL_CYCLE | RDMAEN;
+   }
 
switch (fmt  SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
-- 
1.5.4.3
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH][OMAPZOOM] OMAP3: Initialize XCCR and RCCR registers for McBSP DAI driver

2008-11-24 Thread Lopez Cruz, Misael
 This patch initializes XCCR and RCCR registers for OMAP McBSP DAI driver
 for
 OMAP 2430/34xx platforms. Those registers were being set to 0 as they were
 not properly initialized.
 
 Signed-off-by: Misael Lopez Cruz [EMAIL PROTECTED]
This version includes Anand and Chandra's comments.
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: busybox output to display

2008-11-22 Thread Lopez Cruz, Misael
We accidentally saw this behavior when saving bootargs like:

setenv bootargs='...' instead of setenv bootargs '...'

Try removing '='

Misa

 -Original Message-
 From: [EMAIL PROTECTED] [mailto:linux-omap-
 [EMAIL PROTECTED] On Behalf Of Sudipta GHOSH
 Sent: Saturday, November 22, 2008 1:35 PM
 To: linux-omap@vger.kernel.org
 Subject: busybox output to display
 
 Hi,
 
 This issue is more with busybox. Hope you will not mind for posting here.
 
 In my development board, I use uboot as boot loader. busybox files are in
 flash.
 when I boot , I can see the boot logo (peguin) in the lcd display and
 all printk output.
 
 But I am unable to see the busybox in the lcd display.
 
 busybox prompt and all output from busybox is going to the serial port.
 
 Like  if I do ls, then I see the output of ls in my serial port
 (teraterm/hyper terminal).
 
 How I can see busybox prompt and all output to my lcd display.
 
 
 I use console=tty0 in the bootargs.
 
 any advice?
 
 
 Regards,
 -SG
 --
 To unsubscribe from this list: send the line unsubscribe linux-omap in
 the body of a message to [EMAIL PROTECTED]
 More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH] ALSA: SoC: Add support for TI SDP3430

2008-11-20 Thread Lopez Cruz, Misael
 On Thursday 20 November 2008, [EMAIL PROTECTED] wrote:
  +   tristate SoC Audio support for Texas Instruments SDP3430
  +   depends on SND_OMAP_SOC  MACH_OMAP_3430SDP
  +   select SND_OMAP_SOC_MCBSP
  +   select SND_SOC_TWL4030
 
 depends also on TWL4030_CORE, yes?
The machine driver itself doesn't depend on TWL4030_CORE, but TWL4030 SoC codec 
driver does (sound/soc/codecs/Kconfig)

config SND_SOC_TWL4030
tristate
depends on TWL4030_CORE

Although that dependency is overridden by _select_ statement.

What should be the best way to handle this dependency? Directly in kconfig 
entry for each TWL4030-related machine driver?
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html