RE: [PATCH 2/2] omap: zoom: Move new code introduced by ASoC m-c to board-zoom-peripherals
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
+ 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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