alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
From: "Prchal Jiří" <jiri.prchal@aksignal.cz>
To: support@atmel.com
Cc: slapin@ossfans.org, broonie@opensource.wolfsonmicro.com,
	alsa-devel@alsa-project.org, lrg@slimlogic.co.uk
Subject: Re: PROBLEM: Asoc driver in 2.6.37.3 for AT91SAM9260 / TLV320AIC3X is broken
Date: Wed, 23 Mar 2011 14:53:22 +0100	[thread overview]
Message-ID: <4D89FB52.60405@aksignal.cz> (raw)
In-Reply-To: <4D79E428.2060408@aksignal.cz>

[-- Attachment #1: Type: text/plain, Size: 1703 bytes --]

Hi,
I fixed the problem:
in file "linux-2.6.38/sound/soc/atmel/snd-soc-afeb9260.c"
in function "afeb9260_soc_init"
is missing "platform_device_alloc("soc-audio", -1);".

I also add SPI functionality and external clock on BCLK to codec tlv320aic3x.
I'm sending diff, is this the right way to add it as patch to kernel releases?

I also discover the problem with SD card: not all cards can run at 375kHz at init state, I change minimal freq to
200kHz. It's in diff too.

Dne 11.3.2011 09:58, Prchal Jiří napsal(a):
> Hallo,
> at first I would like to apologize of sending this report to too many mails, but I can't find the right person / list.
> 
> [2.] Full description of the problem/report:
> I try for almost 2 month to make kernel with alsa for my hardware. I first try version 2.6.37, now trying 2.6.37.3. My
> hw i similar to board afeb-9260, just with difference my codec is TLV320AIC3106 connected as slave with clock on BCLK.
> So I change file snd-soc-afeb9260.c, diff is attached, and Kconfig and Makefile too.
> In version 2.6.35.11 it works good, but MMC/SD card doesn't work. (Something is broken it that driver just in this
> version). I need to work sound and SD card.
> I thing the problem is somewhere between "tlv320aic3x-codec 0-001a: probe" and "i2c-core: driver [tlv320aic3x-codec]
> registered". In version 2.6.35.11 there is I2C communication, in 2.6.37 and higher nothing on I2C.
> I also try to put newer alsa 1.0.24 to kernel 2.6.37.3 without any improvement.
> Trying to put older alsa (but same version?) from kernel 2.6.35.11 to 2.6.37.3 produce soundcard, but when try to play
> kernel oops, "cannot dereference null pointer" and freezes.
> 

[-- Attachment #2: patch.diff --]
[-- Type: text/x-patch, Size: 30683 bytes --]

diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/arch/arm/mach-at91/Kconfig b/linux-2.6.38/arch/arm/mach-at91/Kconfig
--- a/linux-2.6.38/arch/arm/mach-at91/Kconfig	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/arch/arm/mach-at91/Kconfig	2011-03-16 09:19:40.000000000 +0100
@@ -213,6 +213,12 @@
 	  Select this if you are using Atmel's AT91SAM9260-EK or AT91SAM9XE Evaluation Kit
 	  <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933>
 
+config MACH_CDU
+	bool "CDU AKsignal board"
+	help
+	  Select this if you are using AKsignal CDU board
+	  <http://www.aksignal.cz>
+
 config MACH_CAM60
 	bool "KwikByte KB9260 (CAM60) board"
 	help
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/arch/arm/mach-at91/Makefile b/linux-2.6.38/arch/arm/mach-at91/Makefile
--- a/linux-2.6.38/arch/arm/mach-at91/Makefile	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/arch/arm/mach-at91/Makefile	2011-03-16 09:19:40.000000000 +0100
@@ -40,6 +40,7 @@
 
 # AT91SAM9260 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
+obj-$(CONFIG_MACH_CDU)		 += board-cdu.o
 obj-$(CONFIG_MACH_CAM60)	+= board-cam60.o
 obj-$(CONFIG_MACH_SAM9_L9260)	+= board-sam9-l9260.o
 obj-$(CONFIG_MACH_USB_A9260)	+= board-usb-a9260.o
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/arch/arm/mach-at91/board-cdu.c b/linux-2.6.38/arch/arm/mach-at91/board-cdu.c
--- a/linux-2.6.38/arch/arm/mach-at91/board-cdu.c	1970-01-01 01:00:00.000000000 +0100
+++ b/linux-2.6.38/arch/arm/mach-at91/board-cdu.c	2011-03-23 11:15:47.000000000 +0100
@@ -0,0 +1,351 @@
+/*
+ * linux/arch/arm/mach-at91/board-cdu.c
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2006 Atmel
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/clk.h>
+#include <linux/spi/mcp23s08.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init cdu_map_io(void)
+{
+	/* Initialize processor: 6 MHz crystal */
+	at91sam9260_initialize (6000000);
+
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* USART1 on ttyS2. (Rx, Tx, RTS) */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_RTS);
+
+	/* USART2 on ttyS3. (Rx, Tx, RTS) */
+	at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_RTS);
+
+	/* USART3 on ttyS4. (Rx, Tx, RTS) */
+	at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
+
+	/* USART4 on ttyS5. (Tx) */
+	// EBUS - transmit audio, no rx
+	//at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
+}
+
+static void __init cdu_init_irq(void)
+{
+	at91sam9260_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata cdu_usbh_data = {
+	.ports		= 2,
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata cdu_udc_data = {
+	.vbus_pin	= AT91_PIN_PC15,
+	.pullup_pin	= 0,		/* pull-up driven by UDC */
+};
+
+
+/*
+ * SPI devices.
+ */
+#define MCP23S08_GPIO_BASE    128
+
+static const struct mcp23s08_platform_data mcp23s08_gpio_info = {
+  .chip[0].is_present = true,
+  .chip[0].pullups = 0,
+  .base = MCP23S08_GPIO_BASE,
+};
+
+static struct spi_board_info cdu_spi_devices[] = {
+	{ // ADC LTC2488
+		.modalias	= "spidev",
+		.chip_select	= 0,
+		.max_speed_hz	= 1 * 1000 * 1000,
+		.bus_num	= 1,
+	},
+	{ // GPIO expander MCP23S08
+		.modalias	= "mcp23s08",
+		.chip_select	= 1,
+		.max_speed_hz	= 1000000,
+		.bus_num	= 1,
+		.platform_data	= &mcp23s08_gpio_info,
+		.mode		= SPI_MODE_3,
+	},
+	{ // non volatile memory (F-RAM) FM25VN10
+		.modalias	= "spidev",
+		.chip_select	= 2,
+		.max_speed_hz	= 1 * 1000 * 1000,
+		.bus_num	= 1,
+	},
+	{ // audiocodec TLV320AIC3106
+		.modalias	= "tlv320aic3x-codec",
+		.chip_select	= 3,
+		.max_speed_hz	= 1000000,
+		.bus_num	= 1,
+		.mode		= SPI_MODE_1,
+	},
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata cdu_macb_data = {
+	.phy_irq_pin	= 0, //nc,
+	.is_rmii	= 1,
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata cdu_nand_partition[] = {
+	{
+	  .name   = "bootstrap",
+	  .offset = 0,
+	  .size   = 0x40000,
+	},
+	{
+	  .name   = "uboot",
+	  .offset = 0x40000,
+	  .size   = (0xc0000 - 0x40000),
+	},
+	{
+	  .name   = "ubootenv",
+	  .offset = 0xc0000,
+	  .size   = (0x100000 - 0xc0000),
+	},
+	{
+	  .name   = "kernel",
+	  .offset = 0x100000,
+	  .size   = (0x400000 - 0x100000),
+	},
+	{
+	  .name   = "rootfs",
+	  .offset = 0x400000,
+	  .size   = (0x8000000 - 0x400000),
+	},
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+	*num_partitions = ARRAY_SIZE(cdu_nand_partition);
+	return cdu_nand_partition;
+}
+
+static struct atmel_nand_data __initdata cdu_nand_data = {
+	.ale		= 21,
+	.cle		= 22,
+//	.det_pin	= ... not connected
+	.rdy_pin	= AT91_PIN_PC13,
+	.enable_pin	= AT91_PIN_PC14,
+	.partition_info	= nand_partitions,
+	.bus_width_16	= 0,
+};
+
+static struct sam9_smc_config __initdata cdu_nand_smc_config = {
+	.ncs_read_setup		= 0,
+	.nrd_setup		= 1,
+	.ncs_write_setup	= 0,
+	.nwe_setup		= 1,
+
+	.ncs_read_pulse		= 3,
+	.nrd_pulse		= 3,
+	.ncs_write_pulse	= 3,
+	.nwe_pulse		= 3,
+
+	.read_cycle		= 5,
+	.write_cycle		= 5,
+
+	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+	.tdf_cycles		= 2,
+};
+
+static void __init cdu_add_device_nand(void)
+{
+	/* setup bus-width (8 or 16) */
+	if (cdu_nand_data.bus_width_16)
+		cdu_nand_smc_config.mode |= AT91_SMC_DBW_16;
+	else
+		cdu_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+	/* configure chip-select 3 (NAND) */
+	sam9_smc_configure(3, &cdu_nand_smc_config);
+
+	at91_add_device_nand(&cdu_nand_data);
+}
+
+
+/*
+* MCI (SD/MMC)
+*/
+static struct at91_mmc_data __initdata ek_mmc_data = {
+  .slot_b		= 0,
+  .wire4		= 1,
+  //	.det_pin	= ... not connected
+  //	.wp_pin		= ... not connected
+  //	.vcc_pin	= ... not connected
+};
+
+
+/*
+ * LEDs
+ */
+static struct gpio_led cdu_leds[] = {
+  {    // Red led
+    .name            = "red",
+    .gpio            = AT91_PIN_PC10,
+    .default_trigger = "timer",
+  },
+  {    // Green led
+    .name            = "green",
+    .gpio            = AT91_PIN_PA5,
+    .default_trigger = "heartbeat",
+  },
+  {   // Yellow led
+    .name            = "yellow",
+    .gpio            = AT91_PIN_PB20,
+    .active_low      = 1,
+    .default_trigger = "mmc0",
+  },
+  {   // Blue led
+    .name            = "blue",
+    .gpio            = AT91_PIN_PB21,
+    .active_low      = 1,
+    .default_trigger = "nand-disk",
+  },
+};
+
+
+/*
+ * GPIOs
+ */
+static struct gpio gpios[] = {
+  { AT91_PIN_PA0,  GPIOF_OUT_INIT_LOW,  "ebus_dir"},
+  { AT91_PIN_PA1,  GPIOF_OUT_INIT_LOW,  "time_dir"},
+  { AT91_PIN_PB12, GPIOF_OUT_INIT_LOW,  "gsm_rst"},
+  { AT91_PIN_PB13, GPIOF_OUT_INIT_LOW,  "gsm_on"},
+  { AT91_PIN_PC2,  GPIOF_IN,            "por"},
+  { AT91_PIN_PC7,  GPIOF_OUT_INIT_HIGH, "spk_shdn"},
+
+  { AT91_PIN_PC0,  GPIOF_IN,            "in0"},
+  { AT91_PIN_PC1,  GPIOF_IN,            "in1"},
+  { AT91_PIN_PA22, GPIOF_IN,            "in4"},
+  { AT91_PIN_PA23, GPIOF_IN,            "in5"},
+  { AT91_PIN_PA24, GPIOF_IN,            "in6"},
+  { AT91_PIN_PA25, GPIOF_IN,            "in7"},
+
+  { AT91_PIN_PA26, GPIOF_OUT_INIT_LOW,  "out2"},
+  { AT91_PIN_PA27, GPIOF_OUT_INIT_LOW,  "out3"},
+  { AT91_PIN_PA28, GPIOF_OUT_INIT_LOW,  "out4"},
+  { AT91_PIN_PA29, GPIOF_OUT_INIT_LOW,  "out5"},
+  { AT91_PIN_PA30, GPIOF_OUT_INIT_LOW,  "out6"},
+  { AT91_PIN_PB29, GPIOF_OUT_INIT_LOW,  "out7"},
+
+  { MCP23S08_GPIO_BASE + 0, GPIOF_IN,   "busadrp"},
+  { MCP23S08_GPIO_BASE + 2, GPIOF_IN,   "busadr5"},
+  { MCP23S08_GPIO_BASE + 3, GPIOF_IN,   "busadr4"},
+  { MCP23S08_GPIO_BASE + 4, GPIOF_IN,   "busadr3"},
+  { MCP23S08_GPIO_BASE + 5, GPIOF_IN,   "busadr2"},
+  { MCP23S08_GPIO_BASE + 6, GPIOF_IN,   "busadr1"},
+  { MCP23S08_GPIO_BASE + 7, GPIOF_IN,   "busadr0"},
+};
+
+static void __init cdu_add_gpio (void)
+{
+  int i;
+
+  for (i = 0; i < ARRAY_SIZE (gpios); i++) {
+    gpio_request_one (gpios[i].gpio, gpios[i].flags, gpios[i].label);
+    gpio_export_name (gpios[i].gpio, 0, gpios[i].label);
+  }
+}
+
+/*
+ * init
+ */
+static void __init cdu_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* USB Host */
+	at91_add_device_usbh(&cdu_usbh_data);
+	/* USB Device */
+	at91_add_device_udc(&cdu_udc_data);
+	/* SPI */
+	at91_add_device_spi(cdu_spi_devices, ARRAY_SIZE(cdu_spi_devices));
+	/* NAND */
+	cdu_add_device_nand();
+	/* Ethernet */
+	at91_add_device_eth(&cdu_macb_data);
+	/* MMC */
+	at91_add_device_mmc(0, &ek_mmc_data);
+	/* SSC */
+	at91_add_device_ssc(AT91SAM9260_ID_SSC, (ATMEL_SSC_TF | ATMEL_SSC_TK | ATMEL_SSC_TD | ATMEL_SSC_RD));
+	/* LEDs */
+	at91_gpio_leds(cdu_leds, ARRAY_SIZE(cdu_leds));
+	// GPIO
+	cdu_add_gpio ();
+}
+
+MACHINE_START(AT91SAM9260EK, "CDU")
+	/* Maintainer: Atmel */
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91sam926x_timer,
+	.map_io		= cdu_map_io,
+	.init_irq	= cdu_init_irq,
+	.init_machine	= cdu_board_init,
+MACHINE_END
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/drivers/gpio/gpiolib.c b/linux-2.6.38/drivers/gpio/gpiolib.c
--- a/linux-2.6.38/drivers/gpio/gpiolib.c	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/drivers/gpio/gpiolib.c	2011-03-16 09:21:44.000000000 +0100
@@ -769,6 +769,85 @@
 	return dev_get_drvdata(dev) == data;
 }
 
+
+/**
+* gpio_export_name - export a GPIO through sysfs
+* @gpio: gpio to make available, already requested
+* @direction_may_change: true if userspace may change gpio direction
+* @name: name in sysfs
+* Context: arch_initcall or later
+*
+* When drivers want to make a GPIO accessible to userspace after they
+* have requested it -- perhaps while debugging, or as part of their
+* public interface -- they may use this routine.  If the GPIO can
+* change direction (some can't) and the caller allows it, userspace
+* will see "direction" sysfs attribute which may be used to change
+* the gpio's direction.  A "value" attribute will always be provided.
+*
+* Returns zero on success, else an error.
+*/
+int gpio_export_name (unsigned gpio, bool direction_may_change, const char * ioname)
+{
+  unsigned long		flags;
+  struct gpio_desc	*desc;
+  int			status = -EINVAL;
+
+  /* can't export until sysfs is available ... */
+  if (!gpio_class.p) {
+    pr_debug("%s: called too early!\n", __func__);
+    return -ENOENT;
+  }
+
+  if (!gpio_is_valid(gpio))
+    goto done;
+
+  mutex_lock(&sysfs_lock);
+
+  spin_lock_irqsave(&gpio_lock, flags);
+  desc = &gpio_desc[gpio];
+  if (test_bit(FLAG_REQUESTED, &desc->flags)
+    && !test_bit(FLAG_EXPORT, &desc->flags)) {
+    status = 0;
+  if (!desc->chip->direction_input
+    || !desc->chip->direction_output)
+    direction_may_change = false;
+  }
+  spin_unlock_irqrestore(&gpio_lock, flags);
+
+  if (status == 0) {
+    struct device	*dev;
+
+    dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
+                         desc, ioname ? ioname : "gpio%u", gpio);
+    if (!IS_ERR(dev)) {
+      status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
+
+      if (!status && direction_may_change)
+        status = device_create_file(dev, &dev_attr_direction);
+
+      if (!status && gpio_to_irq(gpio) >= 0 && (direction_may_change || !test_bit(FLAG_IS_OUT, &desc->flags)))
+        status = device_create_file(dev, &dev_attr_edge);
+
+      if (status != 0)
+        device_unregister(dev);
+      } else
+        status = PTR_ERR(dev);
+
+    if (status == 0)
+      set_bit(FLAG_EXPORT, &desc->flags);
+  }
+
+  mutex_unlock(&sysfs_lock);
+
+  done:
+  if (status)
+    pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+
+  return status;
+}
+EXPORT_SYMBOL_GPL(gpio_export_name);
+
+
 /**
  * gpio_export_link - create a sysfs link to an exported GPIO node
  * @dev: device under which to create symlink
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/drivers/mmc/host/at91_mci.c b/linux-2.6.38/drivers/mmc/host/at91_mci.c
--- a/linux-2.6.38/drivers/mmc/host/at91_mci.c	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/drivers/mmc/host/at91_mci.c	2011-03-23 12:47:15.000000000 +0100
@@ -724,6 +724,10 @@
 		else
 			clkdiv = (at91_master_clock / ios->clock) / 2;
 
+		/* set maximum divider */
+		if (clkdiv > 255)
+		  clkdiv = 255;
+
 		pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
 			at91_master_clock / (2 * (clkdiv + 1)));
 	}
@@ -944,7 +948,7 @@
 	}
 
 	mmc->ops = &at91_mci_ops;
-	mmc->f_min = 375000;
+	mmc->f_min = 200000; /* not all cards can run at 375kHz */
 	mmc->f_max = 25000000;
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 	mmc->caps = 0;
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/include/asm-generic/gpio.h b/linux-2.6.38/include/asm-generic/gpio.h
--- a/linux-2.6.38/include/asm-generic/gpio.h	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/include/asm-generic/gpio.h	2011-03-16 09:20:51.000000000 +0100
@@ -203,6 +203,7 @@
  * but more typically is configured entirely from userspace.
  */
 extern int gpio_export(unsigned gpio, bool direction_may_change);
+extern int gpio_export_name (unsigned gpio, bool direction_may_change, const char * ioname);
 extern int gpio_export_link(struct device *dev, const char *name,
 			unsigned gpio);
 extern int gpio_sysfs_set_active_low(unsigned gpio, int value);
@@ -252,6 +253,11 @@
 	return -ENOSYS;
 }
 
+static inline int gpio_export_name (unsigned gpio, bool direction_may_change, const char * ioname)
+{
+  return -ENOSYS;
+}
+
 static inline int gpio_export_link(struct device *dev, const char *name,
 				unsigned gpio)
 {
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/sound/soc/atmel/Kconfig b/linux-2.6.38/sound/soc/atmel/Kconfig
--- a/linux-2.6.38/sound/soc/atmel/Kconfig	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/sound/soc/atmel/Kconfig	2011-03-22 09:46:46.000000000 +0100
@@ -50,3 +50,11 @@
 	select SND_SOC_TLV320AIC23
 	help
 	  Say Y here to support sound on AFEB9260 board.
+
+config SND_AT91_SOC_CDU
+	tristate "SoC Audio support for CDU board"
+	depends on ARCH_AT91 && MACH_CDU && SND_ATMEL_SOC
+	select SND_ATMEL_SOC_SSC
+	select SND_SOC_TLV320AIC3X
+	help
+	  Say Y here to support sound on CDU board.
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/sound/soc/atmel/Makefile b/linux-2.6.38/sound/soc/atmel/Makefile
--- a/linux-2.6.38/sound/soc/atmel/Makefile	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/sound/soc/atmel/Makefile	2011-03-16 09:26:17.000000000 +0100
@@ -14,3 +14,4 @@
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
 obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
+obj-$(CONFIG_SND_AT91_SOC_CDU) += snd-soc-cdu.o
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/sound/soc/atmel/snd-soc-cdu.c b/linux-2.6.38/sound/soc/atmel/snd-soc-cdu.c
--- a/linux-2.6.38/sound/soc/atmel/snd-soc-cdu.c	1970-01-01 01:00:00.000000000 +0100
+++ b/linux-2.6.38/sound/soc/atmel/snd-soc-cdu.c	2011-03-22 14:00:32.000000000 +0100
@@ -0,0 +1,274 @@
+/*
+ * snd-soc-cdu  --  SoC audio for AT91SAM9260-based
+ * 			AKsignal CDU board.
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2008 Atmel
+ *  Copyright (C) 2011 AKsignal Brno
+ *
+ * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *                     Jiri Prchal <jiri.prchal@aksignal.cz>
+ *
+ * Based on ati_b1_wm8731.c by:
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Copyright 2006 Endrelia Technologies Inc.
+ * Based on corgi.c by:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <linux/atmel-ssc.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+
+#include "../codecs/tlv320aic3x.h"
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
+
+struct {
+	unsigned int channels;
+	snd_pcm_format_t format;
+	unsigned int rate;
+	unsigned int codecclk;
+	unsigned int cmrdiv;
+	unsigned int period;
+} cdu_audio[] = {
+	/* 16 bit stereo modes */
+	{2, SNDRV_PCM_FORMAT_S16_LE, 8000, 2096000, 25, 130,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 16000, 2496000, 21, 77,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 32000, 2496000, 21, 38,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 48000, 2016000, 26, 20,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 96000, 4032000, 13, 20,},
+
+	{2, SNDRV_PCM_FORMAT_S16_LE, 11025, 2381400, 22, 107,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 22050, 2381400, 22, 53,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 44100, 2381400, 22, 26,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 88200, 4762800, 11, 26,},
+
+	{2, SNDRV_PCM_FORMAT_S16_LE, 11520, 2626560, 20, 113,},
+	{2, SNDRV_PCM_FORMAT_S16_LE, 23040, 2626560, 20, 56,},
+
+};
+
+static int cdu_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;
+	int i, found = 0;
+	snd_pcm_format_t format = params_format(params);
+	unsigned int rate = params_rate(params);
+	unsigned int channels = params_channels(params);
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* find the correct audio parameters */
+	for (i = 0; i < ARRAY_SIZE(cdu_audio); i++) {
+		if (rate == cdu_audio[i].rate &&
+		    format == cdu_audio[i].format &&
+		    channels == cdu_audio[i].channels) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found)
+		return -EINVAL;
+
+	/* Set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, CLKIN_BCLK, cdu_audio[i].codecclk, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		printk(KERN_ERR "can't set codec system clock\n");
+	  return ret;
+	}
+
+	/* Set the cpu clock dividers to BCLK */
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cdu_audio[i].cmrdiv);
+	ret |= snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_TCMR_PERIOD, cdu_audio[i].period);
+	ret |= snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_RCMR_PERIOD, cdu_audio[i].period);
+	if (ret < 0) {
+		printk(KERN_ERR "can't set cpu system clock\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops cdu_ops = {
+	.hw_params = cdu_hw_params,
+};
+
+static const struct snd_soc_dapm_widget cdu_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line Out", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+  /* Headphone connected to HPLOUT, HPROUT */
+  {"Headphone Jack", NULL, "HPLOUT"},
+  {"Headphone Jack", NULL, "HPROUT"},
+
+  /* Line Out connected to LLOUT, RLOUT */
+  {"Line Out", NULL, "LLOUT"},
+  {"Line Out", NULL, "RLOUT"},
+
+  /* Mic connected to (MIC3L | MIC3R) */
+  {"MIC3L", NULL, "Mic Bias 2V"},
+  {"MIC3R", NULL, "Mic Bias 2V"},
+  {"Mic Bias 2V", NULL, "Mic Jack"},
+
+  /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
+  {"LINE1L", NULL, "Line In"},
+  {"LINE2L", NULL, "Line In"},
+  {"LINE1R", NULL, "Line In"},
+  {"LINE2R", NULL, "Line In"},
+};
+
+/*
+ * Logic for a aic3x as connected on a cdu board.
+ */
+static int cdu_aic3x_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret;
+
+	printk(KERN_DEBUG "cdu_aic3x: cdu_aic3x_init called\n");
+
+/*	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
+		MCLK_RATE, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
+		return ret;
+	}
+*/
+	/* Add specific widgets */
+	snd_soc_dapm_new_controls(dapm, cdu_dapm_widgets,
+				  ARRAY_SIZE(cdu_dapm_widgets));
+	/* Set up specific audio path interconnects */
+	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+
+	/* not connected */
+
+	/* always connected */
+	snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+	snd_soc_dapm_enable_pin(dapm, "Line Out");
+	snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+	snd_soc_dapm_enable_pin(dapm, "Line In");
+
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static struct snd_soc_dai_link cdu_dai = {
+	.name = "TLV320AIC3106",
+	.stream_name = "PCM",
+	.cpu_dai_name = "atmel-ssc-dai.0",
+	.codec_dai_name = "tlv320aic3x-hifi",
+	.init = cdu_aic3x_init,
+	.platform_name = "atmel-pcm-audio",
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+	.codec_name = "tlv320aic3x-codec.0-001b",
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	.codec_name = "spi1.3",
+#endif
+	.ops = &cdu_ops,
+};
+
+static struct snd_soc_card snd_soc_cdu = {
+	.name = "TLV320AIC3106",
+	.dai_link = &cdu_dai,
+	.num_links = 1,
+};
+
+static struct platform_device *cdu_snd_device;
+
+static int __init cdu_init(void)
+{
+	struct clk *pllb;
+	int ret;
+
+	ret = atmel_ssc_set_audio(0);
+	if (ret != 0) {
+		pr_err("Failed to set SSC 0 for audio: %d\n", ret);
+		return ret;
+	}
+
+	cdu_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!cdu_snd_device) {
+		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+		ret = -ENOMEM;
+	}
+
+	platform_set_drvdata(cdu_snd_device,
+			&snd_soc_cdu);
+
+	ret = platform_device_add(cdu_snd_device);
+	if (ret) {
+		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+		goto err_device_add;
+	}
+
+	return ret;
+
+err_device_add:
+	platform_device_put(cdu_snd_device);
+err:
+	return ret;
+}
+
+static void __exit cdu_exit(void)
+{
+	platform_device_unregister(cdu_snd_device);
+	cdu_snd_device = NULL;
+}
+
+module_init(cdu_init);
+module_exit(cdu_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jiri Prchal <jiri.prchal@aksignal.cz>");
+MODULE_DESCRIPTION("ALSA SoC CDU_AIC3X");
+MODULE_LICENSE("GPL");
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/sound/soc/codecs/Kconfig b/linux-2.6.38/sound/soc/codecs/Kconfig
--- a/linux-2.6.38/sound/soc/codecs/Kconfig	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/sound/soc/codecs/Kconfig	2011-03-17 08:37:14.000000000 +0100
@@ -37,7 +37,7 @@
 	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_TLV320AIC3X if I2C
+	select SND_SOC_TLV320AIC3X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_TPA6130A2 if I2C
 	select SND_SOC_TLV320DAC33 if I2C
 	select SND_SOC_TWL4030 if TWL4030_CORE
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/sound/soc/codecs/tlv320aic3x.c b/linux-2.6.38/sound/soc/codecs/tlv320aic3x.c
--- a/linux-2.6.38/sound/soc/codecs/tlv320aic3x.c	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/sound/soc/codecs/tlv320aic3x.c	2011-03-22 13:43:27.000000000 +0100
@@ -42,6 +42,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -984,6 +985,13 @@
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
 	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	u8 data;
+
+	/* set external clock on BCLK */
+	data = snd_soc_read(codec, AIC3X_CLKGEN_CTRL_REG);
+	data &= 0x0f;
+	data |= ((clk_id << PLLCLK_IN_SHIFT) | (clk_id << CLKDIV_IN_SHIFT));
+	snd_soc_write (codec, AIC3X_CLKGEN_CTRL_REG, data);
 
 	aic3x->sysclk = freq;
 	return 0;
@@ -1371,9 +1379,12 @@
 	aic3x->codec = codec;
 	codec->dapm.idle_bias_off = 1;
 
+	if (aic3x->control_type == SND_SOC_I2C)
 	ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
+	else
+		ret = snd_soc_codec_set_cache_io(codec, 7, 8, aic3x->control_type);
 	if (ret != 0) {
-		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
 		return ret;
 	}
 
@@ -1472,6 +1483,54 @@
 	.resume = aic3x_resume,
 };
 
+#if defined(CONFIG_SPI_MASTER)
+static int aic3x_spi_probe(struct spi_device *spi)
+{
+	struct aic3x_pdata *pdata = spi->dev.platform_data;
+	struct aic3x_priv *aic3x;
+	int ret;
+
+	aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
+	if (aic3x == NULL) {
+		dev_err(&spi->dev, "failed to create private data\n");
+		return -ENOMEM;
+	}
+
+	aic3x->control_type = SND_SOC_SPI;
+	spi_set_drvdata(spi, aic3x);
+
+	if (pdata) {
+		aic3x->gpio_reset = pdata->gpio_reset;
+		aic3x->setup = pdata->setup;
+	} else {
+		aic3x->gpio_reset = -1;
+	}
+
+	aic3x->model = AIC3X_MODEL_3X;
+
+	ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1);
+	if (ret < 0)
+		kfree(aic3x);
+	return ret;
+}
+
+static int __devexit aic3x_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
+}
+
+static struct spi_driver aic3x_spi_driver = {
+	.driver = {
+		.name	= "tlv320aic3x-codec",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= aic3x_spi_probe,
+	.remove		= __devexit_p(aic3x_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
  * AIC3X 2 wire address can be up to 4 devices with device addresses
@@ -1557,6 +1616,13 @@
 		       ret);
 	}
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&aic3x_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register AIC3X SPI driver: %d\n",
+			ret);
+	}
+#endif
 	return ret;
 }
 module_init(aic3x_modinit);
@@ -1566,6 +1632,9 @@
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&aic3x_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&aic3x_spi_driver);
+#endif
 }
 module_exit(aic3x_exit);
 
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/sound/soc/codecs/tlv320aic3x.h b/linux-2.6.38/sound/soc/codecs/tlv320aic3x.h
--- a/linux-2.6.38/sound/soc/codecs/tlv320aic3x.h	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/sound/soc/codecs/tlv320aic3x.h	2011-03-22 13:37:54.000000000 +0100
@@ -178,6 +178,13 @@
 #define PLL_CLKIN_SHIFT		4
 #define MCLK_SOURCE		0x0
 #define PLL_CLKDIV_SHIFT	0
+#define PLLCLK_IN_SHIFT		4
+#define CLKDIV_IN_SHIFT		6
+/* clock in source */
+#define CLKIN_MCLK		0
+#define CLKIN_GPIO2		1
+#define CLKIN_BCLK		2
+
 
 /* Software reset register bits */
 #define SOFT_RESET		0x80
diff -U 3 -H -b -w -B -E -d -r -N -- a/linux-2.6.38/sound/soc/soc-cache.c b/linux-2.6.38/sound/soc/soc-cache.c
--- a/linux-2.6.38/sound/soc/soc-cache.c	2011-03-15 02:20:32.000000000 +0100
+++ b/linux-2.6.38/sound/soc/soc-cache.c	2011-03-22 09:34:13.000000000 +0100
@@ -99,6 +99,58 @@
 #define snd_soc_4_12_spi_write NULL
 #endif
 
+/* special functions for codecs with 7 bit register address and LSB read/write */
+static unsigned int snd_soc_7_8_read(struct snd_soc_codec *codec,
+				     unsigned int reg)
+{
+	int ret;
+	unsigned int val;
+
+	if (reg >= codec->driver->reg_cache_size ||
+		snd_soc_codec_volatile_register(codec, reg)) {
+			if (codec->cache_only)
+				return -1;
+
+			BUG_ON(!codec->hw_read);
+			return codec->hw_read(codec, ((reg << 1) | 1));
+	}
+
+	ret = snd_soc_cache_read(codec, reg, &val);
+	if (ret < 0)
+		return -1;
+	return val;
+}
+
+static int snd_soc_7_8_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+	u8 data[2];
+	int ret;
+
+	data[0] = (reg << 1);
+	data[1] = value;
+
+	if (!snd_soc_codec_volatile_register(codec, reg) &&
+		reg < codec->driver->reg_cache_size) {
+		ret = snd_soc_cache_write(codec, reg, value);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (codec->cache_only) {
+		codec->cache_sync = 1;
+		return 0;
+	}
+
+	ret = codec->hw_write(codec->control_data, data, 2);
+	if (ret == 2)
+		return 0;
+	if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+
 static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
 				     unsigned int reg)
 {
@@ -661,6 +713,11 @@
 		.spi_write = snd_soc_4_12_spi_write,
 	},
 	{
+		.addr_bits = 7, .data_bits = 8,
+		.write = snd_soc_7_8_write, .read = snd_soc_7_8_read,
+		.spi_write = snd_soc_8_8_spi_write,
+	},
+	{
 		.addr_bits = 7, .data_bits = 9,
 		.write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
 		.spi_write = snd_soc_7_9_spi_write,

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

  parent reply	other threads:[~2011-03-23 13:53 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-03-11  8:58 PROBLEM: Asoc driver in 2.6.37.3 for AT91SAM9260 / TLV320AIC3X is broken Prchal Jiří
2011-03-11 15:05 ` Jarkko Nikula
2011-03-14  6:35   ` Prchal Jiří
2011-03-23 13:53 ` Prchal Jiří [this message]
2011-03-23 13:54   ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4D89FB52.60405@aksignal.cz \
    --to=jiri.prchal@aksignal.cz \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=lrg@slimlogic.co.uk \
    --cc=slapin@ossfans.org \
    --cc=support@atmel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).