* [PATCH 2/3] arm: pmu: support pmu irq routed from CTI
From: Ming Lei @ 2011-03-01 15:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <-294597288559385401@unknownmsgid>
Hi,
2011/3/1 Will Deacon <will.deacon@arm.com>:
> Hello,
>
>> Subject: [PATCH 2/3] arm: pmu: support pmu irq routed from CTI
>>
>> From: Ming Lei <tom.leiming@gmail.com>
>>
>> This patch introduces pmu_platform_data struct to
>> support pmu irq routed from CTI, such as implemented
>> on OMAP4.
>>
>> Generally speaking, clearing cti irq should be done in
>> irq handler, also enabling cti module after calling
>> request_irq and disabling cti module before calling
>> free_irq.
>>
>> Signed-off-by: Ming Lei <tom.leiming@gmail.com>
>> ---
>> ?arch/arm/include/asm/pmu.h ? | ? 12 ++++++++++
>> ?arch/arm/kernel/perf_event.c | ? 51 ++++++++++++++++++++++++++++++++++++-----
>> ?2 files changed, 56 insertions(+), 7 deletions(-)
>
> This will conflict with the the ux500 PMU workaround:
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2011-February/041145.html
Thanks for your pointing out it.
I will send out -v1 of these patches against the latest -next tree.
thanks,
--
Lei Ming
^ permalink raw reply
* [PATCH] mach-ux500: activate USB in the U8500 defconfig
From: Linus Walleij @ 2011-03-01 15:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Linus Walleij <linus.walleij@linaro.org>
Activate the new USB stuff so we atleast get some compile
coverage for this stuff.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
arch/arm/configs/u8500_defconfig | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index a5cce24..e1d6020 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -67,7 +67,11 @@ CONFIG_AB8500_CORE=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_AB8500=y
# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_MUSB_PIO_ONLY=y
+CONFIG_USB_GADGET=y
+CONFIG_AB8500_USB=y
CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y
CONFIG_NEW_LEDS=y
--
1.7.3.2
^ permalink raw reply related
* [PATCH V6 02/17] ST SPEAr13xx: Added PCIe host controller base driver support.
From: Arnd Bergmann @ 2011-03-01 15:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <30b834e959889fb20404f45e7e66de78155874c2.1298977728.git.viresh.kumar@st.com>
On Tuesday 01 March 2011, Viresh Kumar wrote:
> From: Pratyush Anand <pratyush.anand@st.com>
Hi Viresh and Pratyush,
The code looks really nice, I have just a few comments, mostly
about pointer type conversion.
> SPEAr13xx family contains Synopsys designware PCIe version 3.30a. This
> patch adds support for this PCIe module for spear platform.
If this is a standard PCIe controller, why add it to the platform
code instead of a common place like arch/arch/common or arch/arm/kernel ?
> diff --git a/arch/arm/mach-spear13xx/include/mach/hardware.h b/arch/arm/mach-spear13xx/include/mach/hardware.h
> index fd8c2dc..c3fb454 100644
> --- a/arch/arm/mach-spear13xx/include/mach/hardware.h
> +++ b/arch/arm/mach-spear13xx/include/mach/hardware.h
> @@ -28,4 +28,11 @@
> /* typesafe io address */
> #define __io_address(n) __io(IO_ADDRESS(n))
I could not find the definition for __io() here, but I suspect this is
wrong. If __io_address() is what you use for accessing the direct-mapped
MMIO registers, it cannot also be what you use to access the PCIe PIO
ports, so most likely one of the two is broken. Can you explain?
> +#if defined(CONFIG_PCI)
> +#define PCIBIOS_MIN_IO 0
> +#define PCIBIOS_MIN_MEM 0
> +#define pcibios_assign_all_busses() 0
> +#endif
> +
No need for the #ifdef here, if you have no PCI, there won't be a conflict.
Better make PCIBIOS_MIN_IO 0x1000, in order to avoid stepping over
ISA port ranges.
> +static u32 spr_pcie_base[NUM_PCIE_PORTS] = {
> + SPEAR13XX_PCIE0_BASE,
> + SPEAR13XX_PCIE1_BASE,
> + SPEAR13XX_PCIE2_BASE,
> +};
> +static u32 spr_pcie_app_base[NUM_PCIE_PORTS] = {
> + SPEAR13XX_PCIE0_APP_BASE,
> + SPEAR13XX_PCIE1_APP_BASE,
> + SPEAR13XX_PCIE2_APP_BASE,
> +};
I think these should be __iomem pointers, not u32 tokens, since you
are listing virtual addresses. If you unroll the loop in
spear13xx_pcie_init() that uses these, you can actually get rid
of the two arrays, and simplify the code used there at the
same time.
> +#ifdef CONFIG_PCI_MSI
> +static DECLARE_BITMAP(msi_irq_in_use[NUM_PCIE_PORTS], SPEAR_NUM_MSI_IRQS);
> +static unsigned int spear_msi_data[NUM_PCIE_PORTS];
> +
> +static void spear13xx_msi_init(struct pcie_port *pp);
> +#endif
> +
> +static void spear_pcie_int_handler(unsigned int irq, struct irq_desc *desc);
It would be nice if you could avoid the forward declarations by reordering
the functions if possible.
> +static int __init spear13xx_pcie_setup(int nr, struct pci_sys_data *sys)
> +{
> + struct pcie_port *pp;
> + u32 val = 0;
> +
> + if (nr >= NUM_PCIE_PORTS)
> + return 0;
> +
> + if ((*pcie_port_is_host)(nr) != 1)
> + return 0;
> +
> + pp = &pcie_port[nr];
> + if (!spear13xx_pcie_link_up((void __iomem *)pp->va_app_base))
> + return 0;
No need for the cast, va_app_base is already (void __iomem *).
> +static void __init add_pcie_port(int port, u32 base, u32 app_base)
> +{
> + struct pcie_port *pp = &pcie_port[port];
> + struct pcie_app_reg *app_reg;
> +
> + pp->port = port;
> + pp->root_bus_nr = -1;
> + pp->base = (void __iomem *)base;
> + pp->app_base = (void __iomem *)app_base;
> + pp->va_app_base = (void __iomem *) ioremap(app_base, 0x200);
> + if (!pp->va_app_base) {
> + pr_err("error with ioremap in function %s\n", __func__);
> + return;
> + }
> + pp->va_dbi_base = (void __iomem *) ioremap(base, 0x2000);
> + if (!pp->va_dbi_base) {
> + pr_err("error with ioremap in function %s\n", __func__);
> + return;
> + }
Please remove all these casts. Some are unneeded, some can go away
after the things I mention above.
> + spin_lock_init(&pp->conf_lock);
> + memset(pp->res, 0, sizeof(pp->res));
> + pr_info("spear13xx PCIe port %d\n", port);
> + if (spear13xx_pcie_link_up((void __iomem *)pp->va_app_base)) {
> + pr_info("link up in bios\n");
> + } else {
> + pr_info("link down in bios\n");
> + spear13xx_pcie_host_init(pp);
> + spear13xx_int_init(pp);
> + app_reg = (struct pcie_app_reg *)pp->va_app_base;
This cast looks invalid, you cast from __iomem to a regular pointer,
> + pp->va_cfg0_base = (void __iomem *)
> + ioremap(app_reg->in_cfg0_addr_start, IN_CFG0_SIZE);
which breaks here when you pass the value to ioremap without doing a readl.
> +#ifdef CONFIG_PCI_MSI
> +/* MSI int handler
> + */
> +static void handle_msi(struct pcie_port *pp)
> +{
> + unsigned long val;
> + int i, pos;
> +
> + for (i = 0; i < 8; i++) {
> + spear_dbi_read_reg(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
> + (u32 *)&val);
> + if (val) {
> + pos = 0;
> + while ((pos = find_next_bit(&val, 32, pos)) != 32) {
> + generic_handle_irq(SPEAR_MSI0_INT_BASE
> + + pp->port * SPEAR_NUM_MSI_IRQS
> + + (i * 32) + pos);
> + pos++;
> + }
> + }
> + spear_dbi_write_reg(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, val);
> + }
> +}
> +#else
> +static void handle_msi(struct pcie_port *pp)
> +{
> +}
> +#endif
The MSI code is not big, but I'd still recommend moving it to a separate
file, which gets compiled only when CONFIG_PCI_MSI is set. You can have
the #ifdef and inline NOP alternative in a header for this.
Arnd
^ permalink raw reply
* [PATCH 2/4] ARM:boot:device tree: Merge specific atags into the device tree
From: Grant Likely @ 2011-03-01 14:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.00.1103010141140.10356@xanadu.home>
On Mon, Feb 28, 2011 at 11:45 PM, Nicolas Pitre <nico@fluxnic.net> wrote:
> On Mon, 28 Feb 2011, John Bonesio wrote:
>
>> This patch is to merge in key atags into the appended device tree. ?An appended
>> device tree is where the zImage has a dtb binary appended at the end of it. The
>> boot code looks for an appended device tree, then looks for a few key atags
>> passed in by the bootloader.
>>
>> The bootargs and memory size settings, if they exist, override existing values
>> in the appended device tree. If these values don't currently exist in the
>> appended device tree, they are added.
>>
>> Signed-off-by: John Bonesio <bones@secretlab.ca>
>
> Is this really useful?
>
> I understand this might be handy for testing purposes. ?But if your
> bootloader does ATAG only then your hardware is likely to have support
> in the kernel without device tree support just fine.
>
> IOW I don't think this would be of much value in upstream.
That's fine. This feature was implemented to meet a client's
requirement and to experiment with manipulating the .dtb in the zimage
wrapper. We're posting it here for completeness if anyone else wants
to play with it. Same for the last patch that allows appending
multiple dtbs.
g.
^ permalink raw reply
* [PATCH v2 1/4] ASoC: Add TI tlv320aic32x4 codec support.
From: Mark Brown @ 2011-03-01 14:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <AANLkTinSqVuuiif33yd1zZBTzeb4mvvLpDd4+=RPiHHM@mail.gmail.com>
On Tue, Mar 01, 2011 at 03:36:13PM +0100, javier Martin wrote:
> Ok, let me organize all this stuff for better understanding. By the
> way, when you said it should be configured by platform are you
> referring to machine driver or to board specific code? Can you please
Either the machine driver or board specific code depending on what's
idiomatic for the thing you're configuring (they're both machine
specific anyway).
> point me to a codec driver which uses a similar approach?
Quite a lot of CODEC drivers have platform data of various kinds, pretty
much all of them have an include file in include/sound - look there for
a list.
^ permalink raw reply
* [PATCH v2 1/4] ASoC: Add TI tlv320aic32x4 codec support.
From: javier Martin @ 2011-03-01 14:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110301142231.GH9662@opensource.wolfsonmicro.com>
Thank you for your fast response.
On 1 March 2011 15:22, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> On Tue, Mar 01, 2011 at 03:02:05PM +0100, Javier Martin wrote:
>
>> + ? ? SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL,
>> + ? ? ? ? ? ? ? ? ? ? AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
>> + ? ? SOC_DOUBLE_R_TLV("PGA Gain Level Volume", AIC32X4_LMICPGAVOL,
>> + ? ? ? ? ? ? ? ? ? ? AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
>
> I suspect you don't want to have Gain and Level in there.
>
>> + ? ? SOC_SINGLE("AGC Left Enable Switch", AIC32X4_LAGC1, 7, 1, 0),
>> + ? ? SOC_SINGLE("AGC Right Enable Switch", AIC32X4_RAGC1, 7, 1, 0),
>
> A switch is obviously an enable.
>
Yes, let me fix that in a following version.
>> +static const struct aic32x4_configs aic32x4_reg_init[] = {
>
> As I said in reply to your previous posting this looks like it shouldn't
> be here. ?A few things jump out as suspicious but not everything you're
> doing is clear:
>
>> + ? ? {AIC32X4_LDOCTL, AIC32X4_LDOCTLEN},
>
> This looks like it should be dynamically managed at runtime, either via
> DAPM or in the bias level functions.
>
>> + ? ? {AIC32X4_CMMODE, AIC32X4_LDOIN_18_36 | AIC32X4_LDOIN2HP},
>> + ? ? {AIC32X4_CLKMUX, AIC32X4_PLLCLKIN},
>> + ? ? {AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK},
>> + ? ? {AIC32X4_DACSETUP,
>> + ? ? ?AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN | AIC32X4_SSTEP2WCLK},
>> + ? ? {AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K},
>> + ? ? {AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K},
>
> These look like platform configuration.
>
>> + ? ? {AIC32X4_LMICPGAVOL, 0x00},
>> + ? ? {AIC32X4_RMICPGAVOL, 0x00},
>
> These look like volume controls which should be exposed to users.
>
>> + ? ? /* Unmute ADC left and right channels */
>> + ? ? {AIC32X4_ADCFGA, 0x00},
>
> This looks like it should be user visible.
>
>> + ? ? /* MICBIAS = 2.075V(CM=0.75V) generated from LDOIN */
>> + ? ? {AIC32X4_MICBIAS, 0x68},
>
> This should be configured by the platform.
>
Ok, let me organize all this stuff for better understanding. By the
way, when you said it should be configured by platform are you
referring to machine driver or to board specific code? Can you please
point me to a codec driver which uses a similar approach?
Thank you.
--
Javier Martin
Vista Silicon S.L.
CDTUC - FASE C - Oficina S-345
Avda de los Castros s/n
39005- Santander. Cantabria. Spain
+34 942 25 32 60
www.vista-silicon.com
^ permalink raw reply
* [PATCH v2 1/4] ASoC: Add TI tlv320aic32x4 codec support.
From: Mark Brown @ 2011-03-01 14:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298988128-11520-2-git-send-email-javier.martin@vista-silicon.com>
On Tue, Mar 01, 2011 at 03:02:05PM +0100, Javier Martin wrote:
> + SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL,
> + AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
> + SOC_DOUBLE_R_TLV("PGA Gain Level Volume", AIC32X4_LMICPGAVOL,
> + AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
I suspect you don't want to have Gain and Level in there.
> + SOC_SINGLE("AGC Left Enable Switch", AIC32X4_LAGC1, 7, 1, 0),
> + SOC_SINGLE("AGC Right Enable Switch", AIC32X4_RAGC1, 7, 1, 0),
A switch is obviously an enable.
> +static const struct aic32x4_configs aic32x4_reg_init[] = {
As I said in reply to your previous posting this looks like it shouldn't
be here. A few things jump out as suspicious but not everything you're
doing is clear:
> + {AIC32X4_LDOCTL, AIC32X4_LDOCTLEN},
This looks like it should be dynamically managed at runtime, either via
DAPM or in the bias level functions.
> + {AIC32X4_CMMODE, AIC32X4_LDOIN_18_36 | AIC32X4_LDOIN2HP},
> + {AIC32X4_CLKMUX, AIC32X4_PLLCLKIN},
> + {AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK},
> + {AIC32X4_DACSETUP,
> + AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN | AIC32X4_SSTEP2WCLK},
> + {AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K},
> + {AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K},
These look like platform configuration.
> + {AIC32X4_LMICPGAVOL, 0x00},
> + {AIC32X4_RMICPGAVOL, 0x00},
These look like volume controls which should be exposed to users.
> + /* Unmute ADC left and right channels */
> + {AIC32X4_ADCFGA, 0x00},
This looks like it should be user visible.
> + /* MICBIAS = 2.075V(CM=0.75V) generated from LDOIN */
> + {AIC32X4_MICBIAS, 0x68},
This should be configured by the platform.
^ permalink raw reply
* [PATCH 1/4] ASoC: Add TI tlv320aic32x4 codec support.
From: Mark Brown @ 2011-03-01 14:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <AANLkTinjj8rZS_Y9qiHbrU2nAYSXTikTNtyU71Bk7UqL@mail.gmail.com>
On Tue, Mar 01, 2011 at 08:59:23AM +0100, javier Martin wrote:
> > What are these "aic32x4_configs" all about? ?They look like you're
> > setting non-default configurations...
> This tlv320aic32x4 codec is kind of a huge monster; it has more than
> 200 registers which provide more flexibility than it is needed.
So what is all this magic stuff and why is it using such an odd way of
implementing whatever it's doing? Part of the problem here is that the
functionality is scattered all the way through the driver so it's less
clear than it should be what's going on.
> For example, BCLK and MCLK are forced here to derive from internal PLL
> which is needed for frequency calculation table to be valid. Bypassing
> this PLL doesn't provide new or better functionality.
I rather suspect it provides lower power consumption.
> The same happens regarding DAC internal connections. I don't think
> allowing the user to swap left and right channels makes sense here.
There are a number of CPUs out there that end up being happier with
channels in the wrong order due to peculiarities of the DMA. This is
also used to get a microphone input connected to the right analogue
input to appear on the left channel of a recording for mono use.
^ permalink raw reply
* [PATCH 3/8] Add a mfd IPUv3 driver
From: Thomas Gleixner @ 2011-03-01 14:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201103011243.33765.arnd@arndb.de>
On Tue, 1 Mar 2011, Arnd Bergmann wrote:
> On Tuesday 01 March 2011, Sascha Hauer wrote:
> > > Taking one step back from this, have you considered making this
> > > a regular interrupt controller? That would make the client drivers
> > > more standard -- you could define the interrupt numbers as resources
> > > of a platform device or in the device tree, for instance.
> > > The cost might be more complex code, e.g. when a device requires
> > > many interrupts, but I think it will be at least as efficient
> > > at run-time, and less surprising for readers and authors of
> > > client drivers.
> >
> > I thought about this, but hesitated to increase NR_IRQS by 463. Do you
> > think we should do this instead?
>
> I think there is a plan to virtualize the interrupt numbers on ARM,
> and in that case NR_IRQS becomes rather meaningless. I don't know
> exactly how far that effort has come.
Also sparse irqs allows us now to allocate beyond NR_IRQS. With sparse
irqs NR_IRQS is pretty meaningless and just gives us an indicator how
large the irq space might become, but we allow up to 8k dynamically
allocated irqs beyond NR_IRQS, so this should be sufficient for your
problem.
Thanks,
tglx
^ permalink raw reply
* [PATCH v2 13/13] tty: pruss SUART driver
From: Alan Cox @ 2011-03-01 14:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <99CE1730AA2F4F2F91AFA71BD75FDC41@subhasishg>
> I tried using a tasklet for the TX part, but that did not help.
> Another way is to prepare the buffer for the next read and read the data
> immediately.
> Something like this:
>
> 1. Call tty_prepare_flip_string while startup.
> 2. When the read interrupt arrives, read the data immediately.
> 3. Call tty_prepare_flip_string for the next read.
Only you then don't know the size of space required/
> Again, the problem here is that we need to use global variables to store the
> pre-allocated buffers
You don't. You can store them per port in the existing objects !
> The best way is if we can keep the current implementation, one extra copy is
> not hurting us
> as we do it after the read_data API.
No problem with that at all.
^ permalink raw reply
* [PATCH v2 4/4] ARM: Add SSI and aic3204 code to Visstrim_M10 boards.
From: Javier Martin @ 2011-03-01 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298988128-11520-1-git-send-email-javier.martin@vista-silicon.com>
Visstrim_M10 boards have an TI tlv320aic3204 codec
attached to SSI1.
Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-imx/mach-imx27_visstrim_m10.c | 14 ++++++++++++++
2 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 197f9e2..4d01d8c 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -168,6 +168,7 @@ config MACH_IMX27_VISSTRIM_M10
bool "Vista Silicon i.MX27 Visstrim_m10"
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IMX_SSI
help
Include support for Visstrim_m10 platform and its different variants.
This includes specific configurations for the board and its
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index 59716fa..b346484 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -69,6 +69,11 @@ static const int visstrim_m10_pins[] __initconst = {
PD15_AOUT_FEC_COL,
PD16_AIN_FEC_TX_ER,
PF23_AIN_FEC_TX_EN,
+ /* SSI1 */
+ PC20_PF_SSI1_FS,
+ PC21_PF_SSI1_RXD,
+ PC22_PF_SSI1_TXD,
+ PC23_PF_SSI1_CLK,
/* SDHC1 */
PE18_PF_SD1_D0,
PE19_PF_SD1_D1,
@@ -207,6 +212,9 @@ static struct i2c_board_info visstrim_m10_i2c_devices[] = {
I2C_BOARD_INFO("pca9555", 0x20),
.platform_data = &visstrim_m10_pca9555_pdata,
},
+ {
+ I2C_BOARD_INFO("tlv320aic32x4", 0x18),
+ }
};
/* USB OTG */
@@ -222,6 +230,11 @@ static struct mxc_usbh_platform_data visstrim_m10_usbotg_pdata = {
.flags = MXC_EHCI_POWER_PINS_ENABLED,
};
+/* SSI */
+static const struct imx_ssi_platform_data visstrim_m10_ssi_pdata __initconst = {
+ .flags = IMX_SSI_DMA | IMX_SSI_SYN,
+};
+
static void __init visstrim_m10_board_init(void)
{
int ret;
@@ -231,6 +244,7 @@ static void __init visstrim_m10_board_init(void)
if (ret)
pr_err("Failed to setup pins (%d)\n", ret);
+ imx27_add_imx_ssi(0, &visstrim_m10_ssi_pdata);
imx27_add_imx_uart0(&uart_pdata);
i2c_register_board_info(0, visstrim_m10_i2c_devices,
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 3/4] ASoC: Add machine driver for Visstrim_M10 board.
From: Javier Martin @ 2011-03-01 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298988128-11520-1-git-send-email-javier.martin@vista-silicon.com>
Visstrim_M10 board uses a tlv320aic3204 codec. This driver
provides support for it.
Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
sound/soc/imx/Kconfig | 10 +++
sound/soc/imx/Makefile | 2 +
sound/soc/imx/mx27vis-aic32x4.c | 137 +++++++++++++++++++++++++++++++++++++++
3 files changed, 149 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/imx/mx27vis-aic32x4.c
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 642270a..15e7c04 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -30,6 +30,16 @@ config SND_MXC_SOC_WM1133_EV1
Enable support for audio on the i.MX31ADS with the WM1133-EV1
PMIC board with WM8835x fitted.
+config SND_SOC_MX27VIS_AIC32X4
+ tristate "SoC audio support for Visstrim M10 boards"
+ depends on MACH_IMX27_VISSTRIM_M10
+ select SND_SOC_TVL320AIC32X4
+ select SND_MXC_SOC_SSI
+ select SND_MXC_SOC_MX2
+ help
+ Say Y if you want to add support for SoC audio on Visstrim SM10
+ board with TLV320AIC32X4 codec.
+
config SND_SOC_PHYCORE_AC97
tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
depends on MACH_PCM043 || MACH_PCA100
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index b67fc02..d6d609b 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -10,8 +10,10 @@ obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o
# i.MX Machine Support
snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
snd-soc-phycore-ac97-objs := phycore-ac97.o
+snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
snd-soc-wm1133-ev1-objs := wm1133-ev1.o
obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/imx/mx27vis-aic32x4.c
new file mode 100644
index 0000000..054110b
--- /dev/null
+++ b/sound/soc/imx/mx27vis-aic32x4.c
@@ -0,0 +1,137 @@
+/*
+ * mx27vis-aic32x4.c
+ *
+ * Copyright 2011 Vista Silicon S.L.
+ *
+ * Author: Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+#include <mach/audmux.h>
+
+#include "../codecs/tlv320aic32x4.h"
+#include "imx-ssi.h"
+
+static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret;
+ u32 dai_format;
+
+ dai_format = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+
+ /* set codec DAI configuration */
+ snd_soc_dai_set_fmt(codec_dai, dai_format);
+
+ /* set cpu DAI configuration */
+ snd_soc_dai_set_fmt(cpu_dai, dai_format);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+ 25000000, SND_SOC_CLOCK_OUT);
+ if (ret) {
+ pr_err("%s: failed setting codec sysclk\n", __func__);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops mx27vis_aic32x4_snd_ops = {
+ .hw_params = mx27vis_aic32x4_hw_params,
+};
+
+static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
+ .name = "tlv320aic32x4",
+ .stream_name = "TLV320AIC32X4",
+ .codec_dai_name = "tlv320aic32x4-hifi",
+ .platform_name = "imx-pcm-audio.0",
+ .codec_name = "tlv320aic32x4.0-0018",
+ .cpu_dai_name = "imx-ssi.0",
+ .ops = &mx27vis_aic32x4_snd_ops,
+};
+
+static struct snd_soc_card mx27vis_aic32x4 = {
+ .name = "visstrim_m10-audio",
+ .dai_link = &mx27vis_aic32x4_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *mx27vis_aic32x4_snd_device;
+
+static int __init mx27vis_aic32x4_init(void)
+{
+ int ret;
+
+ mx27vis_aic32x4_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!mx27vis_aic32x4_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(mx27vis_aic32x4_snd_device, &mx27vis_aic32x4);
+ ret = platform_device_add(mx27vis_aic32x4_snd_device);
+
+ if (ret) {
+ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+ platform_device_put(mx27vis_aic32x4_snd_device);
+ }
+
+ /* Connect SSI0 as clock slave to SSI1 external pins */
+ mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
+ MXC_AUDMUX_V1_PCR_SYN |
+ MXC_AUDMUX_V1_PCR_TFSDIR |
+ MXC_AUDMUX_V1_PCR_TCLKDIR |
+ MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) |
+ MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1)
+ );
+ mxc_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1,
+ MXC_AUDMUX_V1_PCR_SYN |
+ MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
+ );
+
+ return ret;
+}
+
+static void __exit mx27vis_aic32x4_exit(void)
+{
+ platform_device_unregister(mx27vis_aic32x4_snd_device);
+}
+
+module_init(mx27vis_aic32x4_init);
+module_exit(mx27vis_aic32x4_exit);
+
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim");
+MODULE_LICENSE("GPL");
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 2/4] ASoC: Fix burstsize and DSP_B format problems in imx-ssi.
From: Javier Martin @ 2011-03-01 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298988128-11520-1-git-send-email-javier.martin@vista-silicon.com>
When choosing IMX_DMA flag, burtsizes are set to its default
value (0) which leads to driver malfunction. Change them to 4.
DSP_B interface needs additional flag to match DSP_B formats
as described in several codecs as wm8741 and aic3205.
Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
sound/soc/imx/imx-ssi.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 390b6ff..971d3db 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -108,7 +108,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
break;
case SND_SOC_DAIFMT_DSP_B:
/* data on rising edge of bclk, frame high with data */
- strcr |= SSI_STCR_TFSL;
+ strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0;
break;
case SND_SOC_DAIFMT_DSP_A:
/* data on rising edge of bclk, frame high 1clk before data */
@@ -656,6 +656,9 @@ static int imx_ssi_probe(struct platform_device *pdev)
ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
+ ssi->dma_params_tx.burstsize = 4;
+ ssi->dma_params_rx.burstsize = 4;
+
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
if (res)
ssi->dma_params_tx.dma = res->start;
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 1/4] ASoC: Add TI tlv320aic32x4 codec support.
From: Javier Martin @ 2011-03-01 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298988128-11520-1-git-send-email-javier.martin@vista-silicon.com>
This patch adds support for tlv320aic3205 and tlv320aic3254 codecs.
It doesn't include miniDSP support for aic3254.
Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/tlv320aic32x4.c | 765 ++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/tlv320aic32x4.h | 138 +++++++
4 files changed, 909 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/codecs/tlv320aic32x4.c
create mode 100644 sound/soc/codecs/tlv320aic32x4.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 3b5690d..497c9a6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TLV320AIC23 if I2C
select SND_SOC_TLV320AIC26 if SPI_MASTER
+ select SND_SOC_TVL320AIC32X4 if I2C
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
@@ -182,6 +183,9 @@ config SND_SOC_TLV320AIC26
tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
depends on SPI
+config SND_SOC_TVL320AIC32X4
+ tristate
+
config SND_SOC_TLV320AIC3X
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f67a2d6..5709ca6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -23,6 +23,7 @@ snd-soc-stac9766-objs := stac9766.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
@@ -98,6 +99,7 @@ obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
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_TVL320AIC32X4) += snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
new file mode 100644
index 0000000..21e7cf4
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -0,0 +1,765 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic32x4.c
+ *
+ * Copyright 2011 Vista Silicon S.L.
+ *
+ * Author: Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, 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/cdev.h>
+#include <linux/slab.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 "tlv320aic32x4.h"
+
+struct aic32x4_rate_divs {
+ u32 mclk;
+ u32 rate;
+ u8 p_val;
+ u8 pll_j;
+ u16 pll_d;
+ u16 dosr;
+ u8 ndac;
+ u8 mdac;
+ u8 aosr;
+ u8 nadc;
+ u8 madc;
+ u8 blck_N;
+};
+
+struct aic32x4_priv {
+ u32 sysclk;
+ s32 master;
+ u8 page_no;
+ void *control_data;
+};
+
+struct aic32x4_configs {
+ u8 reg_offset;
+ u8 reg_val;
+};
+
+/* 0dB min, 1dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0);
+/* 0dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
+
+static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
+ AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5),
+ SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
+ AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1),
+ SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
+ AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1),
+ SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
+ AIC32X4_HPRGAIN, 6, 0x01, 1),
+ SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
+ AIC32X4_LORGAIN, 6, 0x01, 1),
+
+ SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL,
+ AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
+ SOC_DOUBLE_R_TLV("PGA Gain Level Volume", AIC32X4_LMICPGAVOL,
+ AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
+
+ SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
+
+ SOC_SINGLE("AGC Left Enable Switch", AIC32X4_LAGC1, 7, 1, 0),
+ SOC_SINGLE("AGC Right Enable Switch", AIC32X4_RAGC1, 7, 1, 0),
+ SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1,
+ 4, 0x07, 0),
+ SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1,
+ 0, 0x03, 0),
+ SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2,
+ 6, 0x03, 0),
+ SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2,
+ 1, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3,
+ 0, 0x7F, 0),
+ SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4,
+ 3, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5,
+ 3, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6,
+ 0, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7,
+ 0, 0x0F, 0),
+};
+
+static const struct aic32x4_rate_divs aic32x4_divs[] = {
+ /* 8k rate */
+ {AIC32X4_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
+ {AIC32X4_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
+ {AIC32X4_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
+ /* 11.025k rate */
+ {AIC32X4_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
+ {AIC32X4_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
+ /* 16k rate */
+ {AIC32X4_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
+ {AIC32X4_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
+ {AIC32X4_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
+ /* 22.05k rate */
+ {AIC32X4_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
+ {AIC32X4_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
+ {AIC32X4_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
+ /* 32k rate */
+ {AIC32X4_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
+ {AIC32X4_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
+ /* 44.1k rate */
+ {AIC32X4_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
+ {AIC32X4_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
+ {AIC32X4_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
+ /* 48k rate */
+ {AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
+ {AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
+ {AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4}
+};
+
+static const struct aic32x4_configs aic32x4_reg_init[] = {
+ {AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE},
+ {AIC32X4_LDOCTL, AIC32X4_LDOCTLEN},
+ {AIC32X4_CMMODE, AIC32X4_LDOIN_18_36 | AIC32X4_LDOIN2HP},
+ {AIC32X4_CLKMUX, AIC32X4_PLLCLKIN},
+ {AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK},
+ {AIC32X4_DACSETUP,
+ AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN | AIC32X4_SSTEP2WCLK},
+ {AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K},
+ {AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K},
+ {AIC32X4_LMICPGAVOL, 0x00},
+ {AIC32X4_RMICPGAVOL, 0x00},
+ /* Unmute ADC left and right channels */
+ {AIC32X4_ADCFGA, 0x00},
+ /* MICBIAS = 2.075V(CM=0.75V) generated from LDOIN */
+ {AIC32X4_MICBIAS, 0x68},
+ {AIC32X4_DACSPB, AIC32X4_DACSPBLOCK_MASK & 0x1},
+ {AIC32X4_ADCSPB, AIC32X4_ADCSPBLOCK_MASK & 0x1},
+};
+
+static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
+ SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_HPRROUTE, 3, 1, 0),
+ SOC_DAPM_SINGLE("IN1_R Switch", AIC32X4_HPRROUTE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_LOLROUTE, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer_controls[] = {
+ SOC_DAPM_SINGLE("IN1_L P Switch", AIC32X4_LMICPGAPIN, 6, 1, 0),
+ SOC_DAPM_SINGLE("IN2_L P Switch", AIC32X4_LMICPGAPIN, 4, 1, 0),
+ SOC_DAPM_SINGLE("IN3_L P Switch", AIC32X4_LMICPGAPIN, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer_controls[] = {
+ SOC_DAPM_SINGLE("IN1_R P Switch", AIC32X4_RMICPGAPIN, 6, 1, 0),
+ SOC_DAPM_SINGLE("IN2_R P Switch", AIC32X4_RMICPGAPIN, 4, 1, 0),
+ SOC_DAPM_SINGLE("IN3_R P Switch", AIC32X4_RMICPGAPIN, 2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", AIC32X4_DACSETUP, 7, 0),
+ SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
+ &hpl_output_mixer_controls[0],
+ ARRAY_SIZE(hpl_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("HPL Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
+ &lol_output_mixer_controls[0],
+ ARRAY_SIZE(lol_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("LOL Power", AIC32X4_OUTPWRCTL, 3, 0, NULL, 0),
+
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", AIC32X4_DACSETUP, 6, 0),
+ SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
+ &hpr_output_mixer_controls[0],
+ ARRAY_SIZE(hpr_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("HPR Power", AIC32X4_OUTPWRCTL, 4, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0,
+ &lor_output_mixer_controls[0],
+ ARRAY_SIZE(lor_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0,
+ &left_input_mixer_controls[0],
+ ARRAY_SIZE(left_input_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0,
+ &right_input_mixer_controls[0],
+ ARRAY_SIZE(right_input_mixer_controls)),
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0),
+ SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0),
+
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("LOL"),
+ SND_SOC_DAPM_OUTPUT("LOR"),
+ SND_SOC_DAPM_INPUT("IN1_L"),
+ SND_SOC_DAPM_INPUT("IN1_R"),
+ SND_SOC_DAPM_INPUT("IN2_L"),
+ SND_SOC_DAPM_INPUT("IN2_R"),
+ SND_SOC_DAPM_INPUT("IN3_L"),
+ SND_SOC_DAPM_INPUT("IN3_R"),
+};
+
+static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
+ /* Left Output */
+ {"HPL Output Mixer", "L_DAC Switch", "Left DAC"},
+ {"HPL Output Mixer", "IN1_L Switch", "IN1_L"},
+
+ {"HPL Power", NULL, "HPL Output Mixer"},
+ {"HPL", NULL, "HPL Power"},
+
+ {"LOL Output Mixer", "L_DAC Switch", "Left DAC"},
+
+ {"LOL Power", NULL, "LOL Output Mixer"},
+ {"LOL", NULL, "LOL Power"},
+
+ /* Right Output */
+ {"HPR Output Mixer", "R_DAC Switch", "Right DAC"},
+ {"HPR Output Mixer", "IN1_R Switch", "IN1_R"},
+
+ {"HPR Power", NULL, "HPR Output Mixer"},
+ {"HPR", NULL, "HPR Power"},
+
+ {"LOR Output Mixer", "R_DAC Switch", "Right DAC"},
+
+ {"LOR Power", NULL, "LOR Output Mixer"},
+ {"LOR", NULL, "LOR Power"},
+
+ /* Left input */
+ {"Left Input Mixer", "IN1_L P Switch", "IN1_L"},
+ {"Left Input Mixer", "IN2_L P Switch", "IN2_L"},
+ {"Left Input Mixer", "IN3_L P Switch", "IN3_L"},
+
+ {"Left ADC", NULL, "Left Input Mixer"},
+
+ /* Right Input */
+ {"Right Input Mixer", "IN1_R P Switch", "IN1_R"},
+ {"Right Input Mixer", "IN2_R P Switch", "IN2_R"},
+ {"Right Input Mixer", "IN3_R P Switch", "IN3_R"},
+
+ {"Right ADC", NULL, "Right Input Mixer"},
+};
+
+static inline int aic32x4_change_page(struct snd_soc_codec *codec,
+ unsigned int new_page)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u8 data[2];
+ int ret;
+
+ data[0] = 0x00;
+ data[1] = new_page & 0xff;
+
+ ret = codec->hw_write(codec->control_data, data, 2);
+ if (ret == 2) {
+ aic32x4->page_no = new_page;
+ return 0;
+ } else {
+ return ret;
+ }
+}
+
+static int aic32x4_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int val)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ unsigned int page = reg / 128;
+ unsigned int fixed_reg = reg % 128;
+ u8 data[2];
+ int ret;
+
+ /* A write to AIC32X4_PSEL is really a non-explicit page change */
+ if (reg == AIC32X4_PSEL)
+ return aic32x4_change_page(codec, val);
+
+ if (aic32x4->page_no != page) {
+ ret = aic32x4_change_page(codec, page);
+ if (ret != 0)
+ return ret;
+ }
+
+ data[0] = fixed_reg & 0xff;
+ data[1] = val & 0xff;
+
+ if (codec->hw_write(codec->control_data, data, 2) == 2)
+ return 0;
+ else
+ return -EIO;
+}
+
+static unsigned int aic32x4_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ unsigned int page = reg / 128;
+ unsigned int fixed_reg = reg % 128;
+ int ret;
+
+ if (aic32x4->page_no != page) {
+ ret = aic32x4_change_page(codec, page);
+ if (ret != 0)
+ return ret;
+ }
+ return i2c_smbus_read_byte_data(codec->control_data, fixed_reg & 0xff);
+}
+
+static inline int aic32x4_get_divs(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
+ if ((aic32x4_divs[i].rate == rate)
+ && (aic32x4_divs[i].mclk == mclk)) {
+ return i;
+ }
+ }
+ printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n");
+ return -EINVAL;
+}
+
+static int aic32x4_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, aic32x4_dapm_widgets,
+ ARRAY_SIZE(aic32x4_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, aic32x4_dapm_routes,
+ ARRAY_SIZE(aic32x4_dapm_routes));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static int aic32x4_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 aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+
+ switch (freq) {
+ case AIC32X4_FREQ_12000000:
+ case AIC32X4_FREQ_24000000:
+ case AIC32X4_FREQ_25000000:
+ aic32x4->sysclk = freq;
+ return 0;
+ }
+ printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
+ return -EINVAL;
+}
+
+static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u8 iface_reg_1;
+ u8 iface_reg_2;
+ u8 iface_reg_3;
+
+ iface_reg_1 = snd_soc_read(codec, AIC32X4_IFACE1);
+ iface_reg_1 = iface_reg_1 & ~(3 << 6 | 3 << 2);
+ iface_reg_2 = snd_soc_read(codec, AIC32X4_IFACE2);
+ iface_reg_2 = 0;
+ iface_reg_3 = snd_soc_read(codec, AIC32X4_IFACE3);
+ iface_reg_3 = iface_reg_3 & ~(1 << 3);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aic32x4->master = 1;
+ iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ aic32x4->master = 0;
+ break;
+ default:
+ printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT);
+ iface_reg_3 |= (1 << 3); /* invert bit clock */
+ iface_reg_2 = 0x01; /* add offset 1 */
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT);
+ iface_reg_3 |= (1 << 3); /* invert bit clock */
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ iface_reg_1 |=
+ (AIC32X4_RIGHT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface_reg_1 |=
+ (AIC32X4_LEFT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT);
+ break;
+ default:
+ printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, AIC32X4_IFACE1, iface_reg_1);
+ snd_soc_write(codec, AIC32X4_IFACE2, iface_reg_2);
+ snd_soc_write(codec, AIC32X4_IFACE3, iface_reg_3);
+ return 0;
+}
+
+static int aic32x4_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u8 data;
+ int i;
+
+ i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
+ if (i < 0) {
+ printk(KERN_ERR "aic32x4: sampling rate not supported\n");
+ return i;
+ }
+
+ /* We will fix R value to 1 and will make P & J=K.D as varialble */
+ data = snd_soc_read(codec, AIC32X4_PLLPR);
+ data &= ~(7 << 4);
+ snd_soc_write(codec, AIC32X4_PLLPR,
+ (data | (aic32x4_divs[i].p_val << 4) | 0x01));
+
+ snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
+
+ snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
+ snd_soc_write(codec, AIC32X4_PLLDLSB,
+ (aic32x4_divs[i].pll_d & 0xff));
+
+ /* NDAC divider value */
+ data = snd_soc_read(codec, AIC32X4_NDAC);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_NDAC, data | aic32x4_divs[i].ndac);
+
+ /* MDAC divider value */
+ data = snd_soc_read(codec, AIC32X4_MDAC);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_MDAC, data | aic32x4_divs[i].mdac);
+
+ /* DOSR MSB & LSB values */
+ snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
+ snd_soc_write(codec, AIC32X4_DOSRLSB,
+ (aic32x4_divs[i].dosr & 0xff));
+
+ /* NADC divider value */
+ data = snd_soc_read(codec, AIC32X4_NADC);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_NADC, data | aic32x4_divs[i].nadc);
+
+ /* MADC divider value */
+ data = snd_soc_read(codec, AIC32X4_MADC);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_MADC, data | aic32x4_divs[i].madc);
+
+ /* AOSR value */
+ snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr);
+
+ /* BCLK N divider */
+ data = snd_soc_read(codec, AIC32X4_BCLKN);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_BCLKN, data | aic32x4_divs[i].blck_N);
+
+ data = snd_soc_read(codec, AIC32X4_IFACE1);
+ data = data & ~(3 << 4);
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ data |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_DOSRMSB_SHIFT);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ data |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_DOSRMSB_SHIFT);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ data |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_DOSRMSB_SHIFT);
+ break;
+ }
+ snd_soc_write(codec, AIC32X4_IFACE1, data);
+
+ return 0;
+}
+
+static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 dac_reg;
+
+ dac_reg = snd_soc_read(codec, AIC32X4_DACMUTE) & ~AIC32X4_MUTEON;
+ if (mute)
+ snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg | AIC32X4_MUTEON);
+ else
+ snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg);
+ return 0;
+}
+
+static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u8 value;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ if (aic32x4->master) {
+ /* Switch on PLL */
+ value = snd_soc_read(codec, AIC32X4_PLLPR);
+ snd_soc_write(codec, AIC32X4_PLLPR,
+ (value | AIC32X4_PLLEN));
+
+ /* Switch on NDAC Divider */
+ value = snd_soc_read(codec, AIC32X4_NDAC);
+ snd_soc_write(codec, AIC32X4_NDAC,
+ value | AIC32X4_NDACEN);
+
+ /* Switch on MDAC Divider */
+ value = snd_soc_read(codec, AIC32X4_MDAC);
+ snd_soc_write(codec, AIC32X4_MDAC,
+ value | AIC32X4_MDACEN);
+
+ /* Switch on NADC Divider */
+ value = snd_soc_read(codec, AIC32X4_NADC);
+ snd_soc_write(codec, AIC32X4_NADC,
+ value | AIC32X4_MDACEN);
+
+ /* Switch on MADC Divider */
+ value = snd_soc_read(codec, AIC32X4_MADC);
+ snd_soc_write(codec, AIC32X4_MADC,
+ value | AIC32X4_MDACEN);
+
+ /* Switch on BCLK_N Divider */
+ value = snd_soc_read(codec, AIC32X4_BCLKN);
+ snd_soc_write(codec, AIC32X4_BCLKN,
+ value | AIC32X4_BCLKEN);
+ }
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (aic32x4->master) {
+ /* Switch off PLL */
+ value = snd_soc_read(codec, AIC32X4_PLLPR);
+ snd_soc_write(codec, AIC32X4_PLLPR,
+ (value & ~AIC32X4_PLLEN));
+
+ /* Switch off NDAC Divider */
+ value = snd_soc_read(codec, AIC32X4_NDAC);
+ snd_soc_write(codec, AIC32X4_NDAC,
+ value & ~AIC32X4_NDACEN);
+
+ /* Switch off MDAC Divider */
+ value = snd_soc_read(codec, AIC32X4_MDAC);
+ snd_soc_write(codec, AIC32X4_MDAC,
+ value & ~AIC32X4_MDACEN);
+
+ /* Switch off NADC Divider */
+ value = snd_soc_read(codec, AIC32X4_NADC);
+ snd_soc_write(codec, AIC32X4_NADC,
+ value & ~AIC32X4_NDACEN);
+
+ /* Switch off MADC Divider */
+ value = snd_soc_read(codec, AIC32X4_MADC);
+ snd_soc_write(codec, AIC32X4_MADC,
+ value & ~AIC32X4_MDACEN);
+ value = snd_soc_read(codec, AIC32X4_BCLKN);
+
+ /* Switch off BCLK_N Divider */
+ snd_soc_write(codec, AIC32X4_BCLKN,
+ value & ~AIC32X4_BCLKEN);
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define AIC32X4_RATES SNDRV_PCM_RATE_8000_48000
+#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops aic32x4_ops = {
+ .hw_params = aic32x4_hw_params,
+ .digital_mute = aic32x4_mute,
+ .set_fmt = aic32x4_set_dai_fmt,
+ .set_sysclk = aic32x4_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver aic32x4_dai = {
+ .name = "tlv320aic32x4-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC32X4_RATES,
+ .formats = AIC32X4_FORMATS,},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC32X4_RATES,
+ .formats = AIC32X4_FORMATS,},
+ .ops = &aic32x4_ops,
+ .symmetric_rates = 1,
+};
+
+static int aic32x4_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int aic32x4_resume(struct snd_soc_codec *codec)
+{
+ aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+
+static int aic32x4_probe(struct snd_soc_codec *codec)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ int i;
+
+ codec->hw_write = (hw_write_t) i2c_master_send;
+ codec->control_data = aic32x4->control_data;
+
+ snd_soc_write(codec, AIC32X4_RESET, 0x01);
+
+ /* Initial value for some registers */
+ for (i = 0; i < ARRAY_SIZE(aic32x4_reg_init); i++)
+ snd_soc_write(codec, aic32x4_reg_init[i].reg_offset,
+ aic32x4_reg_init[i].reg_val);
+
+ aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_add_controls(codec, aic32x4_snd_controls,
+ ARRAY_SIZE(aic32x4_snd_controls));
+ aic32x4_add_widgets(codec);
+
+ return 0;
+}
+
+static int aic32x4_remove(struct snd_soc_codec *codec)
+{
+ aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
+ .read = aic32x4_read,
+ .write = aic32x4_write,
+ .probe = aic32x4_probe,
+ .remove = aic32x4_remove,
+ .suspend = aic32x4_suspend,
+ .resume = aic32x4_resume,
+ .set_bias_level = aic32x4_set_bias_level,
+};
+
+static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct aic32x4_priv *aic32x4;
+ int ret;
+
+ aic32x4 = kzalloc(sizeof(struct aic32x4_priv), GFP_KERNEL);
+ if (aic32x4 == NULL)
+ return -ENOMEM;
+
+ aic32x4->control_data = i2c;
+ i2c_set_clientdata(i2c, aic32x4);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_aic32x4, &aic32x4_dai, 1);
+ if (ret < 0)
+ kfree(aic32x4);
+ return ret;
+}
+
+static __devexit int aic32x4_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id aic32x4_i2c_id[] = {
+ { "tlv320aic32x4", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
+
+static struct i2c_driver aic32x4_i2c_driver = {
+ .driver = {
+ .name = "tlv320aic32x4",
+ .owner = THIS_MODULE,
+ },
+ .probe = aic32x4_i2c_probe,
+ .remove = __devexit_p(aic32x4_i2c_remove),
+ .id_table = aic32x4_i2c_id,
+};
+
+static int __init aic32x4_modinit(void)
+{
+ int ret = 0;
+
+ ret = i2c_add_driver(&aic32x4_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n",
+ ret);
+ }
+ return ret;
+}
+module_init(aic32x4_modinit);
+
+static void __exit aic32x4_exit(void)
+{
+ i2c_del_driver(&aic32x4_i2c_driver);
+}
+module_exit(aic32x4_exit);
+
+MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
new file mode 100644
index 0000000..48c0a3d
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -0,0 +1,138 @@
+/*
+ * tlv320aic32x4.h
+ *
+ * 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.
+ */
+
+
+#ifndef _TLV320AIC32X4_H
+#define _TLV320AIC32X4_H
+
+/* tlv320aic32x4 register space (in decimal to match datasheet) */
+
+#define AIC32X4_PAGE1 128
+
+#define AIC32X4_PSEL 0
+#define AIC32X4_RESET 1
+#define AIC32X4_CLKMUX 4
+#define AIC32X4_PLLPR 5
+#define AIC32X4_PLLJ 6
+#define AIC32X4_PLLDMSB 7
+#define AIC32X4_PLLDLSB 8
+#define AIC32X4_NDAC 11
+#define AIC32X4_MDAC 12
+#define AIC32X4_DOSRMSB 13
+#define AIC32X4_DOSRLSB 14
+#define AIC32X4_NADC 18
+#define AIC32X4_MADC 19
+#define AIC32X4_AOSR 20
+#define AIC32X4_CLKMUX2 25
+#define AIC32X4_CLKOUTM 26
+#define AIC32X4_IFACE1 27
+#define AIC32X4_IFACE2 28
+#define AIC32X4_IFACE3 29
+#define AIC32X4_BCLKN 30
+#define AIC32X4_IFACE4 31
+#define AIC32X4_IFACE5 32
+#define AIC32X4_IFACE6 33
+#define AIC32X4_DOUTCTL 53
+#define AIC32X4_DINCTL 54
+#define AIC32X4_DACSPB 60
+#define AIC32X4_ADCSPB 61
+#define AIC32X4_DACSETUP 63
+#define AIC32X4_DACMUTE 64
+#define AIC32X4_LDACVOL 65
+#define AIC32X4_RDACVOL 66
+#define AIC32X4_ADCSETUP 81
+#define AIC32X4_ADCFGA 82
+#define AIC32X4_LADCVOL 83
+#define AIC32X4_RADCVOL 84
+#define AIC32X4_LAGC1 86
+#define AIC32X4_LAGC2 87
+#define AIC32X4_LAGC3 88
+#define AIC32X4_LAGC4 89
+#define AIC32X4_LAGC5 90
+#define AIC32X4_LAGC6 91
+#define AIC32X4_LAGC7 92
+#define AIC32X4_RAGC1 94
+#define AIC32X4_RAGC2 95
+#define AIC32X4_RAGC3 96
+#define AIC32X4_RAGC4 97
+#define AIC32X4_RAGC5 98
+#define AIC32X4_RAGC6 99
+#define AIC32X4_RAGC7 100
+#define AIC32X4_PWRCFG (AIC32X4_PAGE1 + 1)
+#define AIC32X4_LDOCTL (AIC32X4_PAGE1 + 2)
+#define AIC32X4_OUTPWRCTL (AIC32X4_PAGE1 + 9)
+#define AIC32X4_CMMODE (AIC32X4_PAGE1 + 10)
+#define AIC32X4_HPLROUTE (AIC32X4_PAGE1 + 12)
+#define AIC32X4_HPRROUTE (AIC32X4_PAGE1 + 13)
+#define AIC32X4_LOLROUTE (AIC32X4_PAGE1 + 14)
+#define AIC32X4_LORROUTE (AIC32X4_PAGE1 + 15)
+#define AIC32X4_HPLGAIN (AIC32X4_PAGE1 + 16)
+#define AIC32X4_HPRGAIN (AIC32X4_PAGE1 + 17)
+#define AIC32X4_LOLGAIN (AIC32X4_PAGE1 + 18)
+#define AIC32X4_LORGAIN (AIC32X4_PAGE1 + 19)
+#define AIC32X4_HEADSTART (AIC32X4_PAGE1 + 20)
+#define AIC32X4_MICBIAS (AIC32X4_PAGE1 + 51)
+#define AIC32X4_LMICPGAPIN (AIC32X4_PAGE1 + 52)
+#define AIC32X4_LMICPGANIN (AIC32X4_PAGE1 + 54)
+#define AIC32X4_RMICPGAPIN (AIC32X4_PAGE1 + 55)
+#define AIC32X4_RMICPGANIN (AIC32X4_PAGE1 + 57)
+#define AIC32X4_FLOATINGINPUT (AIC32X4_PAGE1 + 58)
+#define AIC32X4_LMICPGAVOL (AIC32X4_PAGE1 + 59)
+#define AIC32X4_RMICPGAVOL (AIC32X4_PAGE1 + 60)
+
+#define AIC32X4_FREQ_12000000 12000000
+#define AIC32X4_FREQ_24000000 24000000
+#define AIC32X4_FREQ_25000000 25000000
+
+#define AIC32X4_WORD_LEN_16BITS 0x00
+#define AIC32X4_WORD_LEN_20BITS 0x01
+#define AIC32X4_WORD_LEN_24BITS 0x02
+#define AIC32X4_WORD_LEN_32BITS 0x03
+
+#define AIC32X4_I2S_MODE 0x00
+#define AIC32X4_DSP_MODE 0x01
+#define AIC32X4_RIGHT_JUSTIFIED_MODE 0x02
+#define AIC32X4_LEFT_JUSTIFIED_MODE 0x03
+
+#define AIC32X4_AVDDWEAKDISABLE 0x08
+#define AIC32X4_LDOCTLEN 0x01
+
+#define AIC32X4_LDOIN_18_36 0x01
+#define AIC32X4_LDOIN2HP 0x02
+
+#define AIC32X4_DACSPBLOCK_MASK 0x1f
+#define AIC32X4_ADCSPBLOCK_MASK 0x1f
+
+#define AIC32X4_PLLJ_SHIFT 6
+#define AIC32X4_DOSRMSB_SHIFT 4
+
+#define AIC32X4_PLLCLKIN 0x03
+
+#define AIC32X4_LMICPGANIN_IN2R_10K 0x10
+#define AIC32X4_RMICPGANIN_IN1L_10K 0x10
+
+#define AIC32X4_LMICPGAVOL_NOGAIN 0x80
+#define AIC32X4_RMICPGAVOL_NOGAIN 0x80
+
+#define AIC32X4_BCLKMASTER 0x08
+#define AIC32X4_WCLKMASTER 0x04
+#define AIC32X4_PLLEN (0x01 << 7)
+#define AIC32X4_NDACEN (0x01 << 7)
+#define AIC32X4_MDACEN (0x01 << 7)
+#define AIC32X4_NADCEN (0x01 << 7)
+#define AIC32X4_MADCEN (0x01 << 7)
+#define AIC32X4_BCLKEN (0x01 << 7)
+#define AIC32X4_DACEN (0x03 << 6)
+#define AIC32X4_LDAC2LCHN (0x01 << 4)
+#define AIC32X4_RDAC2RCHN (0x01 << 2)
+
+#define AIC32X4_SSTEP2WCLK 0x01
+#define AIC32X4_MUTEON 0x0C
+#define AIC32X4_DACMOD2BCLK 0x01
+
+#endif /* _TLV320AIC32X4_H */
--
1.7.0.4
^ permalink raw reply related
* No subject
From: Javier Martin @ 2011-03-01 14:02 UTC (permalink / raw)
To: linux-arm-kernel
This series of patches provides support for audio in Visstrim_M10 boards.
This second version has some fixes in the aic32x4 codec driver as asked by
Mark Brown.
^ permalink raw reply
* [PATCH 2/3] arm: pmu: support pmu irq routed from CTI
From: Will Deacon @ 2011-03-01 14:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298985434-3009-3-git-send-email-tom.leiming@gmail.com>
Hello,
> Subject: [PATCH 2/3] arm: pmu: support pmu irq routed from CTI
>
> From: Ming Lei <tom.leiming@gmail.com>
>
> This patch introduces pmu_platform_data struct to
> support pmu irq routed from CTI, such as implemented
> on OMAP4.
>
> Generally speaking, clearing cti irq should be done in
> irq handler, also enabling cti module after calling
> request_irq and disabling cti module before calling
> free_irq.
>
> Signed-off-by: Ming Lei <tom.leiming@gmail.com>
> ---
> arch/arm/include/asm/pmu.h | 12 ++++++++++
> arch/arm/kernel/perf_event.c | 51 ++++++++++++++++++++++++++++++++++++-----
> 2 files changed, 56 insertions(+), 7 deletions(-)
This will conflict with the the ux500 PMU workaround:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-February/041145.html
Will
^ permalink raw reply
* [PATCH 2/4] msm: scm: Fix improper register assignment
From: Will Deacon @ 2011-03-01 13:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.00.1102261452340.22034@xanadu.home>
Nicolas,
On Sat, 2011-02-26 at 20:04 +0000, Nicolas Pitre wrote:
> Right. A minimal test case may look like this if someone feels like
> filling a gcc bug report:
>
> extern int foo(int x);
>
> int bar(int x)
> {
> register int a asm("r0") = 1;
> x = foo(x);
> asm ("add %0, %1, %2" : "=r" (x) : "r" (a), "r" (x));
> return x;
> }
>
> And the produced code is:
>
> bar:
> stmfd sp!, {r3, lr}
> bl foo
> #APP
> add r0, r0, r0
> ldmfd sp!, {r3, pc}
>
> So this is clearly bogus.
I've had a chat with the compiler guys and they confirmed that this is a
known bug. There's a really hairy bug report here:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38815
It looks like the GCC stance will change in the future so that register
variables will only be guaranteed to live in the specified register
during asm blocks which use them. If the register is required elsewhere,
spill/reload code will be emitted as necessary. This might break some
weird and wonderful code (passing hidden operands to functions?) but I
don't think we rely on the current behaviour anywhere in the kernel.
Will
^ permalink raw reply
* [PATCH 1/2] ARM imx53: add pwm devices support
From: Fabio Estevam @ 2011-03-01 13:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298972303-1010-1-git-send-email-b02280@freescale.com>
Hi Jason,
On Tue, Mar 1, 2011 at 6:38 AM, Jason Chen <b02280@freescale.com> wrote:
...
> - ? ? ? if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx51()) {
> + ? ? ? if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx51() ||
> + ? ? ? ? ? ? ? cpu_is_mx53()) {
Wouldn?t "if (!cpu_is_mx1() && !cpu_is_mx21())" work here and make
the if statement simpler?
Regards,
Fabio Estevam
^ permalink raw reply
* [PATCH] mach-ux500: activate fix for errata 753970
From: Linus Walleij @ 2011-03-01 13:39 UTC (permalink / raw)
To: linux-arm-kernel
This applies errata fix 753970 for all ux500 platforms. All
current ASICs suffer from this. If the problem is resolved in
later ASICs, the errata selection can be pushed down to other
Kconfig options.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
arch/arm/mach-ux500/Kconfig | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 247caa3..203b986 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -6,6 +6,7 @@ config UX500_SOC_COMMON
select ARM_GIC
select HAS_MTU
select NOMADIK_GPIO
+ select ARM_ERRATA_753970
menu "Ux500 SoC"
--
1.7.3.2
^ permalink raw reply related
* [PATCH v2 13/13] tty: pruss SUART driver
From: Subhasish Ghosh @ 2011-03-01 13:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110222111103.5d0dd0a7@lxorguk.ukuu.org.uk>
Hello,
I tried using the tty_prepare_flip_string as shown below, but this is
causing some latency issues.
Problem is, we do not have any flow control, so we must copy the FIFO data
before the next data
is available. As we are using the tty_prepare_flip_string just before the
read API, the FIFO is getting
overwritten and we are ending up missing chunks (FIFO sized) of data.
I tried using a tasklet for the TX part, but that did not help.
Another way is to prepare the buffer for the next read and read the data
immediately.
Something like this:
1. Call tty_prepare_flip_string while startup.
2. When the read interrupt arrives, read the data immediately.
3. Call tty_prepare_flip_string for the next read.
Again, the problem here is that we need to use global variables to store the
pre-allocated buffers
and at the last read, we allocated the buffer but never used it. I think
this will cause a memory leak.
Or we can de-allocate it while driver close, not sure how to.
The best way is if we can keep the current implementation, one extra copy is
not hurting us
as we do it after the read_data API.
==================================================================================
--- a/drivers/tty/serial/da8xx_pruss/pruss_suart.c
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -170,8 +170,9 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
s8 flags = TTY_NORMAL;
u16 rx_status, data_len = SUART_FIFO_LEN;
u32 data_len_read;
- u8 suart_data[SUART_FIFO_LEN + 1];
+ u8 *suart_data = NULL;
s32 i = 0;
+ s32 alloc_len = 0;
if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
return;
@@ -199,9 +200,10 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
soft_uart->port[uart_no].sysrq = 0;
#endif
} else {
+ alloc_len = tty_prepare_flip_string(tty, &suart_data,
data_len + 1);
pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
- suart_data, data_len + 1,
- &data_len_read);
+ suart_data, alloc_len,
+ &data_len_read);
for (i = 0; i <= data_len_read; i++) {
soft_uart->port[uart_no].icount.rx++;
@@ -210,8 +212,6 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
(&soft_uart->port[uart_no], suart_data))
continue;
}
- /* update the tty data structure */
- tty_insert_flip_string(tty, suart_data, data_len_read);
}
============================================================================================
--------------------------------------------------
From: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Sent: Tuesday, February 22, 2011 4:41 PM
To: "Subhasish" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>;
<linux-arm-kernel@lists.infradead.org>; <m-watkins@ti.com>;
<nsekhar@ti.com>; <sachi@mistralsolutions.com>; "Greg Kroah-Hartman"
<gregkh@suse.de>; "open list" <linux-kernel@vger.kernel.org>; "Stalin
Srinivasan" <stalin.s@mistralsolutions.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver
>> we used separate files and hence we decided to keep the code in a
>> separate
>> directory so that the related files can be identified easily.
>
> Fair enough but I would have thought you could drop the two files in the
> serial directory if they have obviously related names- trivial item/
>>
>> >
>> >
>> >
>> >> +#ifdef __SUART_DEBUG
>> >> +#define __suart_debug(fmt, args...) \
>> >> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
>> >> +#else
>> >> +#define __suart_debug(fmt, args...)
>> >> +#endif
>> >> +
>> >> +#define __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt,
>> >> ##
>> >> args)
>> >
>> > Use dev_dbg/dev_err/pr_debug/pr_err
>>
>> SG - did you mean replace the printks above with dev_dgb/err or the
>> suart_dbg/err.
>
> Ideally all the messages shopuld use dev_dbg/dev_err etc. That allows you
> to configure debug levels and the like nicely as well as producing
> clearer printk info. In some cases with tty code you may not know the
> device so have to use pr_err/pr_debug etc.
>
> Ok
>
>> > Which is never checked. Far better to use WARN_ON and the like for such
>> > cases - or if like this one they don't appear to be possible to simply
>> > delete them
>>
>> SG -- OK, does this look ok ?
>> =================================
>> if (h_uart == NULL) {
>> +WARN_ON(1);
>> - return PRU_SUART_ERR_HANDLE_INVALID;
>> +return -EINVAL;
>> }
>
> Yep - the user will now get a backtrace, and in addition kerneloops.org
> can capture it if that is set up in the distro in use.
>
> Alan
^ permalink raw reply
* [PATCH 3/3] arm: omap4: support pmu
From: Santosh Shilimkar @ 2011-03-01 13:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298985434-3009-4-git-send-email-tom.leiming@gmail.com>
> -----Original Message-----
> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-
> owner at vger.kernel.org] On Behalf Of tom.leiming at gmail.com
> Sent: Tuesday, March 01, 2011 6:47 PM
> To: linux at arm.linux.org.uk
> Cc: linux-arm-kernel at lists.infradead.org; Ming Lei; Woodruff
> Richard; Tony Lindgren; linux-omap at vger.kernel.org
> Subject: [PATCH 3/3] arm: omap4: support pmu
>
> From: Ming Lei <tom.leiming@gmail.com>
>
> This patch supports pmu irq routed from CTI, so
> make pmu/perf working on OMAP4.
>
> The idea is from Woodruff Richard in the disscussion
> "Oprofile on Pandaboard / Omap4" of pandaboard at googlegroups.com.
>
> Cc: Woodruff Richard <r-woodruff2@ti.com>
> Cc: Tony Lindgren <tony@atomide.com>
> Cc: linux-omap at vger.kernel.org
> Signed-off-by: Ming Lei <tom.leiming@gmail.com>
> ---
Thanks Mein Lei for this.
> arch/arm/mach-omap2/devices.c | 54
> ++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 53 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-
> omap2/devices.c
> index 71f099b..54e9705 100644
> --- a/arch/arm/mach-omap2/devices.c
> +++ b/arch/arm/mach-omap2/devices.c
> @@ -34,6 +34,7 @@
>
> #include "mux.h"
> #include "control.h"
> +#include "dbg44xx.h"
>
> #if defined(CONFIG_VIDEO_OMAP2) ||
> defined(CONFIG_VIDEO_OMAP2_MODULE)
>
> @@ -347,19 +348,70 @@ static struct resource omap3_pmu_resource = {
> .flags = IORESOURCE_IRQ,
> };
>
> +static struct resource omap4_pmu_resource[] = {
> + {
> + .start = OMAP44XX_IRQ_CTI0,
> + .end = OMAP44XX_IRQ_CTI0,
> + .flags = IORESOURCE_IRQ,
> + },
> + {
> + .start = OMAP44XX_IRQ_CTI1,
> + .end = OMAP44XX_IRQ_CTI1,
> + .flags = IORESOURCE_IRQ,
> + }
> +};
> +
> static struct platform_device omap_pmu_device = {
> .name = "arm-pmu",
> .id = ARM_PMU_DEVICE_CPU,
> .num_resources = 1,
> };
>
> +struct pmu_platform_data omap4_pmu_data;
> +
> +static void omap4_configure_pmu_irq(void)
> +{
> + void *base0;
> + void *base1;
> +
> + base0 = ioremap(OMAP4430_CTI0_BASE, 4096);
> + base1 = ioremap(OMAP4430_CTI1_BASE, 4096);
> + if (!base0 && !base1) {
> + pr_err("ioremap for omap4 CTI failed\n");
> + return;
> + }
> +
> + /*configure CTI0 for pmu irq routing*/
> + cti_init(&omap4_pmu_data.cti[0], base0,
> + OMAP44XX_IRQ_CTI0, 6);
> + cti_unlock(&omap4_pmu_data.cti[0]);
> + cti_map_trigger(&omap4_pmu_data.cti[0],
> + 1, 6, 2);
> +
> + /*configure CTI1 for pmu irq routing*/
> + cti_init(&omap4_pmu_data.cti[1], base1,
> + OMAP44XX_IRQ_CTI1, 6);
> + cti_unlock(&omap4_pmu_data.cti[1]);
> + cti_map_trigger(&omap4_pmu_data.cti[1],
> + 1, 6, 3);
> +
> + omap4_pmu_data.cti_cnt = 2;
> + omap4_pmu_data.use_cti_irq = 1;
> +}
> +
> static void omap_init_pmu(void)
> {
> if (cpu_is_omap24xx())
> omap_pmu_device.resource = &omap2_pmu_resource;
> else if (cpu_is_omap34xx())
> omap_pmu_device.resource = &omap3_pmu_resource;
> - else
> + else if (cpu_is_omap44xx()) {
> + omap_pmu_device.resource = omap4_pmu_resource;
> + omap_pmu_device.num_resources = 2;
> + omap_pmu_device.dev.platform_data = &omap4_pmu_data;
> +
> + omap4_configure_pmu_irq();
> + } else
> return;
>
> platform_device_register(&omap_pmu_device);
> --
> 1.7.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-
> omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [RFC] MMC: error handling improvements
From: Sahitya Tummala @ 2011-03-01 13:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110219150006.GH29493@n2100.arm.linux.org.uk>
Hi Russell King,
On Sat, 2011-02-19 at 15:00 +0000, Russell King - ARM Linux wrote:
> On Tue, Feb 15, 2011 at 03:49:04PM -0800, David Brown wrote:
> > On Tue, Feb 15 2011, Russell King - ARM Linux wrote:
> >
> > > This patch is for RFC only; it needs splitting up somewhat. However, I
> > > wanted to get it out there for some comment.
> >
> > Just for kicks, I applied this and ran it on an MSM target (8x50). It
> > seems to cause lots of:
> >
> > mmc0: Data timeout
> > mmc0: Controller has been re-initialized
> > ...
> > mmc0: Data CRC error
> >
> > and I can post more if you would find them interesting. Eventually the
> > MSM mmc driver derefernces a null pointer in the interrupt code.
>
> That doesn't look right. If resetting the MMC controller results in all
> state being lost, it presumably means the card gets powered down too.
> If that happens, the card needs to be reinitialized from scratch again,
> and I don't see how that happens in this driver.
>
> Nothing in this patch should cause data timeouts to appear where they
> weren't already appearing before the patch - the patch only changes
> what happens after an error occurs, so you must already be encountering
> errors on the interface before you applied this patch.
This patch sends CMD22 (mmc_sd_num_wr_blocks()) for SD cards after a
write command. This function relies on csd->tacc_ns and csd->tacc_clks
for setting timeout values. But for SDHC cards, these CSD values are not
read and will always be 0. The host driver will only use the timeout
values sent by upper layers and thus in this case we are writing 0 to
MMCIDATATIMER. This is the reason for getting data timeout error for
CMD22. Before sending CMD22 if I add mmc_set_data_timeout(), then it is
working fine for me because mmc_set_data_timeout() uses hardcoded
timeout values for SDHC cards.
All other SD read commands are also using mmc_set_data_timeout() to set
the timeout values - mmc_sd_switch(), mmc_app_sd_status() and
mmc_app_send_scr(). I think it is a problem in mmc_sd_num_wr_blocks to
use CSD contents for timeout values for all types of SD cards.
--
Thanks,
Sahitya.
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
Forum.
^ permalink raw reply
* [PATCH 3/6] ARM: tegra: update GPIO chained IRQ handler to use EOI in parent chip
From: Will Deacon @ 2011-03-01 13:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4D6CF08C.6030109@ru.mvista.com>
Sergei,
> On 28-02-2011 16:33, Will Deacon wrote:
>
> > The chained GPIO IRQ handler on Tegra calls ->irq_ack on the parent
> > chip prior to handling the interrupt.
>
> > This patch updates the code to use ->irq_eoi now that the GIC has moved
> > to using the fasteoi flow model.
>
> > Acked-by: Colin Cross<ccross@android.com>
> > Signed-off-by: Will Deacon<will.deacon@arm.com>
> > ---
> > arch/arm/mach-tegra/gpio.c | 17 +----------------
> > 1 files changed, 1 insertions(+), 16 deletions(-)
> >
> > diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c
> > index ad80488..5019b01 100644
> > --- a/arch/arm/mach-tegra/gpio.c
> > +++ b/arch/arm/mach-tegra/gpio.c
> > @@ -219,9 +219,6 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
> > struct tegra_gpio_bank *bank;
> > int port;
> > int pin;
> > - int unmasked = 0;
> > -
> > - desc->irq_data.chip->irq_ack(&desc->irq_data);
>
> Won't this code break after the first patch as it removes irq_ack()
> method? I.e. shouldn't the patches be combined to keep them bisectable?
If you read the cover letter, I said:
> This is going to be a PITA to merge so any thoughts relating to that
> are welcome.
I'm aware of the bisecting issues and Russell has come up with a solution
using entry/exit functions to sort this out (with the GIC changes moved to
the end of the series).
But we have bigger fish to fry.
The whole question about whether or not chained handlers should be written
with multiple parent chips in mind is a hot topic. Thomas has some interesting
ideas for the core code which will allow the chained handler not to care about
flow control. Once we've sorted out the mechanism for this stuff, the merging
should be fairly straightforward because the chip details will be irrelevant.
Will
^ permalink raw reply
* [PATCH 3/3] arm: omap4: support pmu
From: tom.leiming at gmail.com @ 2011-03-01 13:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298985434-3009-1-git-send-email-tom.leiming@gmail.com>
From: Ming Lei <tom.leiming@gmail.com>
This patch supports pmu irq routed from CTI, so
make pmu/perf working on OMAP4.
The idea is from Woodruff Richard in the disscussion
"Oprofile on Pandaboard / Omap4" of pandaboard at googlegroups.com.
Cc: Woodruff Richard <r-woodruff2@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
Cc: linux-omap at vger.kernel.org
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
---
arch/arm/mach-omap2/devices.c | 54 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 53 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 71f099b..54e9705 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -34,6 +34,7 @@
#include "mux.h"
#include "control.h"
+#include "dbg44xx.h"
#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
@@ -347,19 +348,70 @@ static struct resource omap3_pmu_resource = {
.flags = IORESOURCE_IRQ,
};
+static struct resource omap4_pmu_resource[] = {
+ {
+ .start = OMAP44XX_IRQ_CTI0,
+ .end = OMAP44XX_IRQ_CTI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = OMAP44XX_IRQ_CTI1,
+ .end = OMAP44XX_IRQ_CTI1,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
static struct platform_device omap_pmu_device = {
.name = "arm-pmu",
.id = ARM_PMU_DEVICE_CPU,
.num_resources = 1,
};
+struct pmu_platform_data omap4_pmu_data;
+
+static void omap4_configure_pmu_irq(void)
+{
+ void *base0;
+ void *base1;
+
+ base0 = ioremap(OMAP4430_CTI0_BASE, 4096);
+ base1 = ioremap(OMAP4430_CTI1_BASE, 4096);
+ if (!base0 && !base1) {
+ pr_err("ioremap for omap4 CTI failed\n");
+ return;
+ }
+
+ /*configure CTI0 for pmu irq routing*/
+ cti_init(&omap4_pmu_data.cti[0], base0,
+ OMAP44XX_IRQ_CTI0, 6);
+ cti_unlock(&omap4_pmu_data.cti[0]);
+ cti_map_trigger(&omap4_pmu_data.cti[0],
+ 1, 6, 2);
+
+ /*configure CTI1 for pmu irq routing*/
+ cti_init(&omap4_pmu_data.cti[1], base1,
+ OMAP44XX_IRQ_CTI1, 6);
+ cti_unlock(&omap4_pmu_data.cti[1]);
+ cti_map_trigger(&omap4_pmu_data.cti[1],
+ 1, 6, 3);
+
+ omap4_pmu_data.cti_cnt = 2;
+ omap4_pmu_data.use_cti_irq = 1;
+}
+
static void omap_init_pmu(void)
{
if (cpu_is_omap24xx())
omap_pmu_device.resource = &omap2_pmu_resource;
else if (cpu_is_omap34xx())
omap_pmu_device.resource = &omap3_pmu_resource;
- else
+ else if (cpu_is_omap44xx()) {
+ omap_pmu_device.resource = omap4_pmu_resource;
+ omap_pmu_device.num_resources = 2;
+ omap_pmu_device.dev.platform_data = &omap4_pmu_data;
+
+ omap4_configure_pmu_irq();
+ } else
return;
platform_device_register(&omap_pmu_device);
--
1.7.3
^ permalink raw reply related
* [PATCH 2/3] arm: pmu: support pmu irq routed from CTI
From: tom.leiming at gmail.com @ 2011-03-01 13:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1298985434-3009-1-git-send-email-tom.leiming@gmail.com>
From: Ming Lei <tom.leiming@gmail.com>
This patch introduces pmu_platform_data struct to
support pmu irq routed from CTI, such as implemented
on OMAP4.
Generally speaking, clearing cti irq should be done in
irq handler, also enabling cti module after calling
request_irq and disabling cti module before calling
free_irq.
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
---
arch/arm/include/asm/pmu.h | 12 ++++++++++
arch/arm/kernel/perf_event.c | 51 ++++++++++++++++++++++++++++++++++++-----
2 files changed, 56 insertions(+), 7 deletions(-)
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 8ccea012..afb879e 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -12,11 +12,23 @@
#ifndef __ARM_PMU_H__
#define __ARM_PMU_H__
+#include <asm/cti.h>
+
enum arm_pmu_type {
ARM_PMU_DEVICE_CPU = 0,
ARM_NUM_PMU_DEVICES,
};
+#define MAX_CTI_NUM 4
+/*If the irq of pmu is routed from CTI, the pmu_platfrom_data
+ * instance must be passed to pmu driver via platform_data of
+ * platform_devic.dev*/
+struct pmu_platform_data {
+ int use_cti_irq;
+ int cti_cnt;
+ struct cti cti[MAX_CTI_NUM];
+};
+
#ifdef CONFIG_CPU_HAS_PMU
/**
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index d150ad1..85791b0 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -377,10 +377,38 @@ validate_group(struct perf_event *event)
return 0;
}
+static inline int cti_irq(struct pmu_platform_data *data)
+{
+ return data && data->use_cti_irq;
+}
+
+static inline struct cti *irq_to_cti(struct pmu_platform_data *data,
+ int irq)
+{
+ int idx;
+
+ for(idx = 0; idx < data->cti_cnt; idx++)
+ if (data->cti[idx].irq == irq)
+ return &data->cti[idx];
+ return NULL;
+}
+
+static inline irqreturn_t armpmu_handle_irq(int irq_num, void *dev)
+{
+ struct pmu_platform_data *data = dev;
+
+ if (cti_irq(data))
+ cti_irq_ack(irq_to_cti(data, irq_num));
+
+ return armpmu->handle_irq(irq_num, NULL);
+}
+
+
static int
armpmu_reserve_hardware(void)
{
int i, err = -ENODEV, irq;
+ struct pmu_platform_data *data;
pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU);
if (IS_ERR(pmu_device)) {
@@ -395,26 +423,31 @@ armpmu_reserve_hardware(void)
return -ENODEV;
}
+ data = pmu_device->dev.platform_data;
for (i = 0; i < pmu_device->num_resources; ++i) {
irq = platform_get_irq(pmu_device, i);
if (irq < 0)
continue;
- err = request_irq(irq, armpmu->handle_irq,
+ err = request_irq(irq, armpmu_handle_irq,
IRQF_DISABLED | IRQF_NOBALANCING,
- "armpmu", NULL);
+ "armpmu", data);
if (err) {
pr_warning("unable to request IRQ%d for ARM perf "
"counters\n", irq);
break;
- }
+ } else if (cti_irq(data))
+ cti_enable(irq_to_cti(data, irq));
}
if (err) {
for (i = i - 1; i >= 0; --i) {
irq = platform_get_irq(pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
+ if (irq >= 0) {
+ if (cti_irq(data))
+ cti_enable(irq_to_cti(data, irq));
+ free_irq(irq, data);
+ }
}
release_pmu(pmu_device);
pmu_device = NULL;
@@ -427,11 +460,15 @@ static void
armpmu_release_hardware(void)
{
int i, irq;
+ struct pmu_platform_data *data = pmu_device->dev.platform_data;
for (i = pmu_device->num_resources - 1; i >= 0; --i) {
irq = platform_get_irq(pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
+ if (irq >= 0) {
+ if (cti_irq(data))
+ cti_enable(irq_to_cti(data, irq));
+ free_irq(irq, data);
+ }
}
armpmu->stop();
--
1.7.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox