summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOla Lilja <ola.o.lilja@stericsson.com>2011-12-07 13:29:06 +0100
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:05:03 +0200
commit89becb08b9dffd67d543c086254c53c1a98bb909 (patch)
treea560c7b756523ff8c0d7725901a1c7d2d5e400b8
parent600afc22730e30beda77fed6b16722b86b00908a (diff)
ASoC: Ux500: Move i2s into ASoC and remove old i2s-layer
The old multi-client i2s driver-layer located in drivers/misc/i2s is removed and the MSP-operation for i2s is moved into the file ux500_msp_i2s.c in the Ux500 ASoC-folder. ST-Ericsson ID: - ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I11c9021bb7b2385afba9a3e658b5bef7fe9fdb68 Signed-off-by: Ola Lilja <ola.o.lilja@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/41704
-rw-r--r--arch/arm/mach-ux500/board-mop500-msp.c27
-rw-r--r--arch/arm/mach-ux500/devices-common.h10
-rw-r--r--arch/arm/mach-ux500/include/mach/msp.h73
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/i2s/Kconfig19
-rwxr-xr-xdrivers/misc/i2s/Makefile7
-rwxr-xr-xdrivers/misc/i2s/i2s.c632
-rw-r--r--drivers/misc/i2s/msp_i2s.c2022
-rw-r--r--include/linux/i2s/i2s.h228
-rw-r--r--sound/soc/ux500/Kconfig2
-rw-r--r--sound/soc/ux500/Makefile35
-rwxr-xr-xsound/soc/ux500/u5500.c10
-rw-r--r--sound/soc/ux500/u8500.c12
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c141
-rw-r--r--[-rwxr-xr-x]sound/soc/ux500/ux500_msp_dai.h5
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.c1013
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.h41
-rw-r--r--sound/soc/ux500/ux500_pcm.c2
18 files changed, 1230 insertions, 3050 deletions
diff --git a/arch/arm/mach-ux500/board-mop500-msp.c b/arch/arm/mach-ux500/board-mop500-msp.c
index 35d8480143f..7a5a23baf87 100644
--- a/arch/arm/mach-ux500/board-mop500-msp.c
+++ b/arch/arm/mach-ux500/board-mop500-msp.c
@@ -5,7 +5,6 @@
*/
#include <linux/platform_device.h>
-#include <linux/i2s/i2s.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/gpio/nomadik.h>
@@ -185,36 +184,10 @@ static struct msp_i2s_platform_data msp3_platform_data = {
.msp_i2s_exit = msp13_i2s_exit,
};
-static struct i2s_board_info stm_i2s_board_info[] __initdata = {
- {
- .modalias = "i2s_device.0",
- .id = 0,
- .chip_select = 0,
- },
- {
- .modalias = "i2s_device.1",
- .id = 1,
- .chip_select = 1,
- },
- {
- .modalias = "i2s_device.2",
- .id = 2,
- .chip_select = 2,
- },
- {
- .modalias = "i2s_device.3",
- .id = 3,
- .chip_select = 3,
- },
-};
-
void __init mop500_msp_init(void)
{
db8500_add_msp0_i2s(&msp0_platform_data);
db8500_add_msp1_i2s(&msp1_platform_data);
db8500_add_msp2_i2s(&msp2_platform_data);
db8500_add_msp3_i2s(&msp3_platform_data);
-
- i2s_register_board_info(stm_i2s_board_info,
- ARRAY_SIZE(stm_i2s_board_info));
}
diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h
index 39c74ec82ad..c9c88132a52 100644
--- a/arch/arm/mach-ux500/devices-common.h
+++ b/arch/arm/mach-ux500/devices-common.h
@@ -82,6 +82,16 @@ dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq,
return platform_device_register_full(&pdevinfo);
}
+struct msp_i2s_platform_data;
+
+static inline struct platform_device *
+dbx500_add_msp_i2s(int id, resource_size_t base, int irq,
+ struct msp_i2s_platform_data *pdata)
+{
+ return dbx500_add_platform_device_4k1irq("ux500-msp-i2s", id, base, irq,
+ pdata);
+}
+
static inline struct amba_device *
dbx500_add_rtc(struct device *parent, resource_size_t base, int irq)
{
diff --git a/arch/arm/mach-ux500/include/mach/msp.h b/arch/arm/mach-ux500/include/mach/msp.h
index 09f6a98a8fc..6f42cca48c6 100644
--- a/arch/arm/mach-ux500/include/mach/msp.h
+++ b/arch/arm/mach-ux500/include/mach/msp.h
@@ -12,7 +12,6 @@
#include <linux/spinlock.h>
#include <linux/semaphore.h>
#include <linux/dmaengine.h>
-#include <linux/i2s/i2s.h>
#include <linux/irqreturn.h>
#include <linux/bitops.h>
#include <plat/ste_dma40.h>
@@ -131,6 +130,53 @@ struct msp_protocol_desc {
u32 total_clocks_for_one_frame;
};
+enum i2s_direction_t {
+ I2S_DIRECTION_TX = 0,
+ I2S_DIRECTION_RX = 1,
+ I2S_DIRECTION_BOTH = 2
+};
+
+enum i2s_transfer_mode_t {
+ I2S_TRANSFER_MODE_SINGLE_DMA = 0,
+ I2S_TRANSFER_MODE_CYCLIC_DMA = 1,
+ I2S_TRANSFER_MODE_INF_LOOPBACK = 2,
+ I2S_TRANSFER_MODE_NON_DMA = 4,
+};
+
+struct i2s_message {
+ enum i2s_direction_t i2s_direction;
+ void *txdata;
+ void *rxdata;
+ size_t txbytes;
+ size_t rxbytes;
+ int dma_flag;
+ int tx_offset;
+ int rx_offset;
+ /* cyclic dma */
+ bool cyclic_dma;
+ dma_addr_t buf_addr;
+ size_t buf_len;
+ size_t period_len;
+};
+
+enum i2s_flag {
+ DISABLE_ALL = 0,
+ DISABLE_TRANSMIT = 1,
+ DISABLE_RECEIVE = 2,
+};
+
+struct i2s_controller {
+ struct module *owner;
+ unsigned int id;
+ unsigned int class;
+ const struct i2s_algorithm *algo; /* the algorithm to access the bus */
+ void *data;
+ struct mutex bus_lock;
+ struct device dev; /* the controller device */
+ char name[48];
+};
+#define to_i2s_controller(d) container_of(d, struct i2s_controller, dev)
+
/**
* struct trans_data - MSP transfer data structure used during xfer.
* @message: i2s message.
@@ -645,15 +691,19 @@ enum msp_expand_mode {
#define TDMAE_SHIFT 1
/* Interrupt Register */
-#define RECEIVE_SERVICE_INT BIT(0)
-#define RECEIVE_OVERRUN_ERROR_INT BIT(1)
-#define RECEIVE_FRAME_SYNC_ERR_INT BIT(2)
-#define RECEIVE_FRAME_SYNC_INT BIT(3)
-#define TRANSMIT_SERVICE_INT BIT(4)
-#define TRANSMIT_UNDERRUN_ERR_INT BIT(5)
-#define TRANSMIT_FRAME_SYNC_ERR_INT BIT(6)
-#define TRANSMIT_FRAME_SYNC_INT BIT(7)
-#define ALL_INT 0x000000ff
+#define RECEIVE_SERVICE_INT BIT(0)
+#define RECEIVE_OVERRUN_ERROR_INT BIT(1)
+#define RECEIVE_FRAME_SYNC_ERR_INT BIT(2)
+#define RECEIVE_FRAME_SYNC_INT BIT(3)
+#define TRANSMIT_SERVICE_INT BIT(4)
+#define TRANSMIT_UNDERRUN_ERR_INT BIT(5)
+#define TRANSMIT_FRAME_SYNC_ERR_INT BIT(6)
+#define TRANSMIT_FRAME_SYNC_INT BIT(7)
+#define ALL_INT 0x000000ff
+
+/* MSP test control register */
+#define MSP_ITCR_ITEN BIT(0)
+#define MSP_ITCR_TESTFIFO BIT(1)
/*
* Protocol configuration values I2S:
@@ -879,7 +929,7 @@ enum msp_expand_mode {
#define MAX_MSP_BACKUP_REGS 36
enum enum_i2s_controller {
- MSP_0_I2S_CONTROLLER = 1,
+ MSP_0_I2S_CONTROLLER = 0,
MSP_1_I2S_CONTROLLER,
MSP_2_I2S_CONTROLLER,
MSP_3_I2S_CONTROLLER,
@@ -923,6 +973,7 @@ struct msp {
int msp_io_error;
void __iomem *registers;
enum msp_data_size actual_data_size;
+ struct device *dev;
int irq;
struct i2s_controller *i2s_cont;
struct semaphore lock;
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 366ff7f0ff1..3e1d80106f0 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -46,7 +46,6 @@ obj-y += ti-st/
obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
obj-y += lis3lv02d/
obj-y += carma/
-obj-$(CONFIG_STM_I2S) += i2s/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
diff --git a/drivers/misc/i2s/Kconfig b/drivers/misc/i2s/Kconfig
deleted file mode 100644
index 569818caa5d..00000000000
--- a/drivers/misc/i2s/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# U8500 I2S HW kernel configuration
-#
-config STM_I2S
- bool "U8500 I2S hardware driver"
- depends on ARCH_U8500 && STE_DMA40
- default y
- ---help---
- If you say Y here, you will enable the U8500 I2S hardware driver.
-
- If unsure, say N.
-config STM_MSP_I2S
- tristate "U8500 MSP_I2S hardware driver"
- depends on ARCH_U8500 && STE_DMA40 && STM_I2S
- default y
- ---help---
- If you say Y here, you will enable the U8500 MSP_I2S hardware driver.
-
- If unsure, say N.
diff --git a/drivers/misc/i2s/Makefile b/drivers/misc/i2s/Makefile
deleted file mode 100755
index 75d361d5deb..00000000000
--- a/drivers/misc/i2s/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for I2S drivers
-#
-
-nmdk_i2s-objs := i2s.o
-obj-$(CONFIG_STM_I2S) += nmdk_i2s.o
-obj-$(CONFIG_STM_MSP_I2S) += msp_i2s.o
diff --git a/drivers/misc/i2s/i2s.c b/drivers/misc/i2s/i2s.c
deleted file mode 100755
index 9d14088cebc..00000000000
--- a/drivers/misc/i2s/i2s.c
+++ /dev/null
@@ -1,632 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* copyright STMicroelectronics, 2007. */
-/* */
-/* 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.1 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, see <http://www.gnu.org/licenses/>. */
-/*----------------------------------------------------------------------------*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/cache.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/idr.h>
-#include <linux/i2s/i2s.h>
-#include <linux/platform_device.h>
-
-/*******************************************************************************/
-static DEFINE_MUTEX(core_lock);
-
-static void i2sdev_release(struct device *dev)
-{
- struct i2s_device *i2s = to_i2s_device(dev);
-
- if (i2s->controller)
- put_device(&(i2s->controller->dev));
- kfree(dev);
-}
-static ssize_t
-modalias_show(struct device *dev, struct device_attribute *a, char *buf)
-{
- const struct i2s_device *i2s = to_i2s_device(dev);
- return sprintf(buf, "%s\n", i2s->modalias);
-}
-
-static struct device_attribute i2s_dev_attrs[] = {
- __ATTR_RO(modalias),
- __ATTR_NULL,
-};
-
-/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
- * and the sysfs version makes coldplug work too.
- */
-static const struct i2s_device_id *i2s_match_id(const struct i2s_device_id *id,
- const struct i2s_device *device)
-{
- while (id->name[0]) {
- if (strcmp(device->modalias, id->name) == 0)
- return id;
- id++;
- }
- return NULL;
-}
-
-static int i2s_match_device(struct device *dev, struct device_driver *drv)
-{
- const struct i2s_device *device = to_i2s_device(dev);
- struct i2s_driver *driver = to_i2s_driver(drv);
- if (driver->id_table)
- return i2s_match_id(driver->id_table, device) != NULL;
- return 0;
-}
-
-static int i2s_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- const struct i2s_device *i2s = to_i2s_device(dev);
-
- add_uevent_var(env, "MODALIAS=%s", i2s->modalias);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int i2s_suspend(struct device *dev, pm_message_t message)
-{
- int value = 0;
- struct i2s_driver *drv = to_i2s_driver(dev->driver);
-
- /* suspend will stop irqs and dma; no more i/o */
- if (drv) {
- if (drv->suspend)
- value = drv->suspend(to_i2s_device(dev), message);
- else
- dev_dbg(dev, "... can't suspend\n");
- }
- return value;
-}
-
-static int i2s_resume(struct device *dev)
-{
- int value = 0;
- struct i2s_driver *drv = to_i2s_driver(dev->driver);
-
- /* resume may restart the i/o queue */
- if (drv) {
- if (drv->resume)
- value = drv->resume(to_i2s_device(dev));
- else
- dev_dbg(dev, "... can't resume\n");
- }
- return value;
-}
-
-#else
-#define i2s_suspend NULL
-#define i2s_resume NULL
-#endif
-
-/*This bus is designed to handle various protocols supported by the MSP- ARM Primecell IP
- * such as
- * I2s, PCM, AC97, TDM .... (refer to the data sheet for the complete list.
- * Current MSP driver has the above ones coded.
- * */
-struct bus_type i2s_bus_type = {
- .name = "i2s",
- .dev_attrs = i2s_dev_attrs,
- .match = i2s_match_device,
- .uevent = i2s_uevent,
- .suspend = i2s_suspend,
- .resume = i2s_resume,
-};
-
-EXPORT_SYMBOL_GPL(i2s_bus_type);
-
-static int i2s_drv_probe(struct device *dev)
-{
- const struct i2s_driver *sdrv = to_i2s_driver(dev->driver);
-
- return sdrv->probe(to_i2s_device(dev));
-}
-
-static int i2s_drv_remove(struct device *dev)
-{
- const struct i2s_driver *sdrv = to_i2s_driver(dev->driver);
-
- return sdrv->remove(to_i2s_device(dev));
-}
-
-static void i2s_drv_shutdown(struct device *dev)
-{
- const struct i2s_driver *sdrv = to_i2s_driver(dev->driver);
-
- sdrv->shutdown(to_i2s_device(dev));
-}
-
-/**
- * i2s_register_driver - register a I2S driver
- * @sdrv: the driver to register
- * Context: can sleep
- */
-int i2s_register_driver(struct i2s_driver *sdrv)
-{
- sdrv->driver.bus = &i2s_bus_type;
- if (sdrv->probe)
- sdrv->driver.probe = i2s_drv_probe;
- if (sdrv->remove)
- sdrv->driver.remove = i2s_drv_remove;
- if (sdrv->shutdown)
- sdrv->driver.shutdown = i2s_drv_shutdown;
- return driver_register(&sdrv->driver);
-}
-
-EXPORT_SYMBOL_GPL(i2s_register_driver);
-
-/******************************************************************************/
-struct board_i2s_combined_info {
- struct i2s_board_info board_info;
- struct i2s_device *i2s_dev_p;
-};
-struct boardinfo {
- struct list_head list;
- unsigned n_board_info;
- struct board_i2s_combined_info board_i2s_info[0];
-};
-
-static LIST_HEAD(board_list);
-static DEFINE_MUTEX(board_lock);
-
-/*
- * Get an i2s device. Used in MSP LTP tests.
- */
-struct i2s_device *i2s_get_device_from_boardinfo(int chip_select)
-{
- struct boardinfo *bi;
- struct i2s_device *i2s_dev_p = NULL;
-
- mutex_lock(&board_lock);
- list_for_each_entry(bi, &board_list, list) {
- struct board_i2s_combined_info *chip = bi->board_i2s_info;
- unsigned n;
-
- for (n = bi->n_board_info; n > 0; n--, chip++)
- if (chip->board_info.chip_select == chip_select) {
- i2s_dev_p = chip->i2s_dev_p;
- break;
- }
- if (i2s_dev_p != NULL)
- break;
- }
- mutex_unlock(&board_lock);
-
- return i2s_dev_p;
-}
-
-EXPORT_SYMBOL_GPL(i2s_get_device_from_boardinfo);
-
-/* I2S devices should normally not be created by I2S device drivers; that
- * would make them board-specific. Similarly with I2S master drivers.
- * Device registration normally goes into like arch/.../mach.../board-YYY.c
- * with other readonly (flashable) information about mainboard devices.
- */
-struct i2s_device *i2s_alloc_device(struct device *device)
-{
- struct i2s_device *i2s;
- struct device *dev = device->parent;
-
- get_device(device);
- i2s = kzalloc(sizeof *i2s, GFP_KERNEL);
- if (!i2s) {
- dev_err(dev, "cannot alloc i2s_device\n");
- return NULL;
- }
-
- i2s->dev.parent = dev;
- i2s->dev.bus = &i2s_bus_type;
- i2s->dev.release = i2sdev_release;
- device_initialize(&i2s->dev);
- return i2s;
-}
-
-EXPORT_SYMBOL_GPL(i2s_alloc_device);
-
-/**
- * i2s_add_device - Add i2s_device allocated with i2s_alloc_device
- * @i2s: i2s_device to register
- *
- * Companion function to i2s_alloc_device. Devices allocated with
- * i2s_alloc_device can be added onto the i2s bus with this function.
- *
- * Returns 0 on success; negative errno on failure
- */
-int i2s_add_device(struct i2s_device *i2s)
-{
- static DEFINE_MUTEX(i2s_add_lock);
- struct device *dev = i2s->dev.parent;
- int status;
-
- dev_set_name(&i2s->dev, "%s.%u", "i2s", i2s->chip_select);
-
- mutex_lock(&i2s_add_lock);
-
- if (bus_find_device_by_name(&i2s_bus_type, NULL, dev_name(&i2s->dev))
- != NULL) {
- dev_err(dev, "chipselect %d already in use\n",
- i2s->chip_select);
- status = -EBUSY;
- goto done;
- }
-
- /* Device may be bound to an active driver when this returns */
- status = device_add(&i2s->dev);
- if (status < 0)
- dev_err(dev, "can't %s %s, status %d\n",
- "add", dev_name(&i2s->dev), status);
- else
- dev_dbg(dev, "registered child %s\n", dev_name(&i2s->dev));
-
- done:
- mutex_unlock(&i2s_add_lock);
- return status;
-}
-
-EXPORT_SYMBOL_GPL(i2s_add_device);
-
-/**
- * i2s_new_device - instantiate one new I2S device
- * @i2s_cont: Controller to which device is connected
- * @chip: Describes the I2S device
- * Context: can sleep
- *
- * On typical mainboards, this is purely internal; and it's not needed
- * after board init creates the hard-wired devices. Some development
- * platforms may not be able to use i2s_register_board_info though, and
- * this is exported so that driver could add devices (which it would
- * learn about out-of-band).
- *
- * Returns the new device, or NULL.
- */
-struct i2s_device *i2s_new_device(struct i2s_controller *i2s_cont,
- struct i2s_board_info *chip)
-{
- struct i2s_device *proxy;
- int status;
-
- /* NOTE: caller did any chip->bus_num checks necessary.
- *
- * Also, unless we change the return value convention to use
- * error-or-pointer (not NULL-or-pointer), troubleshootability
- * suggests syslogged diagnostics are best here (ugh).
- */
-
- proxy = i2s_alloc_device(&i2s_cont->dev);
- if (!proxy)
- return NULL;
-
- WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
-
- proxy->chip_select = chip->chip_select;
- strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
- proxy->dev.platform_data = (void *)chip->platform_data;
- proxy->controller = i2s_cont;
-
- status = i2s_add_device(proxy);
- if (status < 0) {
- kfree(proxy);
- return NULL;
- }
-
- return proxy;
-}
-
-EXPORT_SYMBOL_GPL(i2s_new_device);
-
-/**
- * i2s_register_board_info - register I2S devices for a given board
- * @info: array of chip descriptors
- * @n: how many descriptors are provided
- * Context: can sleep
- *
- * Board-specific early init code calls this (probably during arch_initcall)
- * with segments of the I2S device table. Any device nodes are created later,
- * after the relevant parent I2S controller (id) is defined. We keep
- * this table of devices forever, so that reloading a controller driver will
- * not make Linux forget about these hard-wired devices.
- *
- */
-int __init
-i2s_register_board_info(struct i2s_board_info const *info, unsigned n)
-{
- int i;
- struct boardinfo *bi;
-
- bi = kmalloc(sizeof(*bi) + (n * sizeof(struct board_i2s_combined_info)), GFP_KERNEL);
- if (!bi)
- return -ENOMEM;
- bi->n_board_info = n;
-
- for (i = 0; i < n; i++)
- memcpy(&bi->board_i2s_info[i].board_info, &info[i], sizeof *info);
-
- mutex_lock(&board_lock);
- list_add_tail(&bi->list, &board_list);
- mutex_unlock(&board_lock);
- return 0;
-}
-
-/**
- * scan_boardinfo - Scan, creates and registered new i2s device structure.
- * @i2s_cont: i2s controller structure
- * Context: process
- *
- * It will scan the device list that may be registered statically using
- * register_board_info func in arch specific directory and call
- * i2s_new_device to create and registered i2s device over i2s bus. It is
- * called by i2s_add_controller function.
- *
- * Returns void.
- */
-static void scan_boardinfo(struct i2s_controller *i2s_cont)
-{
- struct boardinfo *bi;
-
- mutex_lock(&board_lock);
- list_for_each_entry(bi, &board_list, list) {
- struct board_i2s_combined_info *chip = bi->board_i2s_info;
- unsigned n;
-
- for (n = bi->n_board_info; n > 0; n--, chip++) {
- if (chip->board_info.chip_select != i2s_cont->id)
- continue;
- /* NOTE: this relies on i2s_new_device to
- * issue diagnostics when given bogus inputs
- */
- chip->i2s_dev_p = i2s_new_device(i2s_cont, &chip->board_info);
- }
- }
- mutex_unlock(&board_lock);
-}
-
-/******************************************************************************/
-/**I2S Controller inittialization*/
-static void i2s_controller_dev_release(struct device *dev)
-{
- struct i2s_controller *i2s_cont;
- i2s_cont = container_of(dev, struct i2s_controller, dev);
- kfree(i2s_cont);
-}
-
-static ssize_t
-show_controller_name(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct i2s_controller *cont = to_i2s_controller(dev);
- return sprintf(buf, "%s\n", cont->name);
-}
-
-static struct device_attribute i2s_controller_attrs[] = {
- __ATTR(name, S_IRUGO, show_controller_name, NULL),
- {},
-};
-
-static struct class i2s_controller_class = {
- .owner = THIS_MODULE,
- .name = "i2s-controller",
- .dev_attrs = i2s_controller_attrs,
-};
-
-static int i2s_register_controller(struct i2s_controller *cont)
-{
- int res = 0;
- mutex_init(&cont->bus_lock);
-
- mutex_lock(&core_lock);
-
- /* Add the controller to the driver core.
- * If the parent pointer is not set up,
- * we add this controller to the host bus.
- */
- if (cont->dev.parent == NULL) {
- cont->dev.parent = &platform_bus;
- pr_debug("I2S controller driver [%s] forgot to specify "
- "physical device\n", cont->name);
- }
- dev_set_name(&cont->dev, "I2Scrlr-%d", cont->id);
- cont->dev.release = &i2s_controller_dev_release;
- cont->dev.class = &i2s_controller_class;
- res = device_register(&cont->dev);
- if (res)
- goto out_unlock;
-
- dev_dbg(&cont->dev, "controller [%s] registered\n", cont->name);
- scan_boardinfo(cont);
- out_unlock:
- mutex_unlock(&core_lock);
- return res;
-}
-
-/**
- * i2s_add_controller - declare i2s controller, use dynamic bus number
- * @controller: the controller to add
- * Context: can sleep
- *
- */
-int i2s_add_controller(struct i2s_controller *controller)
-{
- return i2s_register_controller(controller);
-}
-
-EXPORT_SYMBOL(i2s_add_controller);
-
-static int __unregister(struct device *dev, void *controller_dev)
-{
- /* note: before about 2.6.14-rc1 this would corrupt memory: */
- if (dev != controller_dev)
- i2s_unregister_device(to_i2s_device(dev));
- return 0;
-}
-
-/**
- * i2s_del_controller - unregister I2S controller
- * @cont: the controller being unregistered
- * Context: can sleep
- *
- * This unregisters an I2S controller which was previously registered
- * by @i2s_add_controller.
- */
-int i2s_del_controller(struct i2s_controller *cont)
-{
- int res = 0;
- int dummy;
- mutex_lock(&core_lock);
-
- dummy = device_for_each_child(cont->dev.parent, &cont->dev,
- __unregister);
- device_unregister(&cont->dev);
- mutex_unlock(&core_lock);
- return res;
-}
-
-EXPORT_SYMBOL(i2s_del_controller);
-
-/******************************************************************************/
-/*I2S interface apis*/
-
-/**
- * i2s_transfer - Main i2s transfer function.
- * @i2s_cont: i2s controller structure passed by client driver.
- * @message: i2s message structure contains transceive info.
- * Context: process or interrupt.
- *
- * This API is called by client i2s driver as i2s_xfer funtion. It will handle
- * main i2s transfer over i2s bus. The controller should registered its own
- * functions using i2s algorithm structure.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-int i2s_transfer(struct i2s_controller *i2s_cont, struct i2s_message *message)
-{
- return i2s_cont->algo->cont_transfer(i2s_cont, message);
-
-}
-
-EXPORT_SYMBOL(i2s_transfer);
-
-/**
- * i2s_cleanup - Close the current i2s connection btw controller and client.
- * @i2s_cont: i2s controller structure
- * @flag: It indicates the functionality that needs to be disabled.
- * Context: process
- *
- * This API will disable and reset the controller's configuration. Reset the
- * controller so that i2s client driver can reconfigure with new configuration.
- * Controller should release all the necessary resources which was acquired
- * during setup.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-int i2s_cleanup(struct i2s_controller *i2s_cont, i2s_flag flag)
-{
- int status = 0;
- status = i2s_cont->algo->cont_cleanup(i2s_cont, flag);
- if (status)
- return -1;
- else
- return 0;
-}
-
-EXPORT_SYMBOL(i2s_cleanup);
-
-/**
- * i2s_setup - configures and enables the I2S controller.
- * @i2s_cont: i2s controller sent by i2s device.
- * @config: specifies the configuration parameters.
- *
- * This function configures the I2S controller with the client configuration.
- * Controller was already registered on I2S bus by some master controller
- * driver.
- *
- * Returns error(-1) in case of failure else success(0)
- */
-int i2s_setup(struct i2s_controller *i2s_cont, void *config)
-{
- return i2s_cont->algo->cont_setup(i2s_cont, config);
-}
-
-EXPORT_SYMBOL(i2s_setup);
-
-/**
- * i2s_hw_status - Get the current hw status for the i2s controller.
- * @i2s_cont: i2s controller structure passed by client driver.
- * Context: process or interrupt.
- *
- * This API is called by client i2s driver to find out current hw status.
- * The controller should registered its own functions using i2s algorithm structure.
- *
- * Returns current hw status register.
- */
-int i2s_hw_status(struct i2s_controller *i2s_cont)
-{
- return i2s_cont->algo->cont_hw_status(i2s_cont);
-}
-
-/**
- * i2s_get_pointer - Get the current dma_addr_t for the i2s controller.
- * @i2s_cont: i2s controller structure passed by client driver.
- * @i2s_direction: Specifies TX or RX direction.
- * Context: process or interrupt.
- *
- * This API is called by client i2s driver to return a dma_addr_t corresponding
- * to the position of the DMA-controller.
- * The controller should registered its own functions using i2s algorithm structure.
- *
- * Returns current hw status register.
- */
-dma_addr_t i2s_get_pointer(struct i2s_controller *i2s_cont,
- enum i2s_direction_t i2s_direction)
-{
- return i2s_cont->algo->cont_get_pointer(i2s_cont, i2s_direction);
-}
-
-/******************************************************************************/
-
-static int __init i2s_init(void)
-{
- int status;
-
- status = bus_register(&i2s_bus_type);
- if (status < 0)
- goto err0;
-
- status = class_register(&i2s_controller_class);
- if (status < 0)
- goto err1;
- return 0;
-
- err1:
- bus_unregister(&i2s_bus_type);
- err0:
- return status;
-}
-
-static void __exit i2s_exit(void)
-{
- class_unregister(&i2s_controller_class);
- bus_unregister(&i2s_bus_type);
-}
-
-subsys_initcall(i2s_init);
-module_exit(i2s_exit);
-
-MODULE_AUTHOR("Sandeep Kaushik, <sandeep-mmc.kaushik@st.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/i2s/msp_i2s.c b/drivers/misc/i2s/msp_i2s.c
deleted file mode 100644
index f5e3e00b894..00000000000
--- a/drivers/misc/i2s/msp_i2s.c
+++ /dev/null
@@ -1,2022 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License terms:
- *
- * 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.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/pfn.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/dbx500-prcmu.h>
-
-#include <mach/hardware.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/irq.h>
-#include <linux/dmaengine.h>
-
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <linux/i2s/i2s.h>
-#include <mach/msp.h>
-#include <linux/dma-mapping.h>
-
-struct regulator *msp_vape_supply;
-
-#define STM_MSP_NAME "STM_MSP"
-#define MSP_NAME "msp"
-#define DRIVER_DEBUG_PFX "MSP"
-#define DRIVER_DEBUG CONFIG_STM_MSP_DEBUG
-#define DRIVER_DBG "MSP"
-#define NMDK_DBG /* message level */
-
-extern struct driver_debug_st DBG_ST;
- /* Protocol desciptors */
-static const struct msp_protocol_desc protocol_desc_tab[] = {
- I2S_PROTOCOL_DESC,
- PCM_PROTOCOL_DESC,
- PCM_COMPAND_PROTOCOL_DESC,
- AC97_PROTOCOL_DESC,
- SPI_MASTER_PROTOCOL_DESC,
- SPI_SLAVE_PROTOCOL_DESC,
-};
-
-/* Local static functions */
-static int msp_dma_xfer(struct msp *msp, struct i2s_message *msg);
-static int msp_polling_xfer(struct msp *msp, struct i2s_message *msg);
-static int msp_interrupt_xfer(struct msp *msp, struct i2s_message *msg);
-static int msp_start_dma(struct msp *msp, int transmit, dma_addr_t data,
- size_t bytes);
-static int configure_protocol(struct msp *msp,
- struct msp_config *config);
-static int configure_clock(struct msp *msp,
- struct msp_config *config);
-static int configure_multichannel(struct msp *msp,
- struct msp_config *config);
-static int stm_msp_configure_enable(struct i2s_controller *i2s_cont,
- void *configuration);
-static int stm_msp_transceive_data(struct i2s_controller *i2s_cont,
- struct i2s_message *message);
-
-static int stm_msp_disable(struct msp *msp, int direction,
- i2s_flag flag);
-static int stm_msp_close(struct i2s_controller *i2s_cont, i2s_flag flag);
-static int stm_msp_hw_status(struct i2s_controller *i2s_cont);
-
-#define I2S_DEVICE "i2s_device"
-static struct i2s_algorithm i2s_algo = {
- .cont_setup = stm_msp_configure_enable,
- .cont_transfer = stm_msp_transceive_data,
- .cont_cleanup = stm_msp_close,
- .cont_hw_status = stm_msp_hw_status,
-};
-
-/**
- * stm_msp_write - writel a value to specified register
- * @value: value
- * @reg: pointer to register' address
- * Context: atomic(can be both process and interrupt)
- * Returns void.
- */
-static inline void stm_msp_write(u32 value, void __iomem *reg)
-{
- writel(value, reg);
-}
-
-/**
- * stm_msp_read - readl a value to specified register
- * @reg: pointer to register' address
- * Context: atomic(can be both process and interrupt)
- * Returns u32 register's value.
- */
-static inline u32 stm_msp_read(void __iomem *reg)
-{
- return readl(reg);
-}
-
-static void u8_msp_read(struct trans_data *xfer_data)
-{
- struct i2s_message *message = &xfer_data->message;
- while ((message->rx_offset < message->rxbytes) &&
- !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
- RX_FIFO_EMPTY)) {
- message->rx_offset += 1;
- *(u8 *) message->rxdata =
- (u8) stm_msp_read(xfer_data->msp->registers + MSP_DR);
- message->rxdata += 1;
- }
-}
-
-static void u16_msp_read(struct trans_data *xfer_data)
-{
- struct i2s_message *message = &xfer_data->message;
- while ((message->rx_offset < message->rxbytes) &&
- !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
- RX_FIFO_EMPTY)) {
- message->rx_offset += 2;
- *(u16 *) message->rxdata =
- (u16) stm_msp_read(xfer_data->msp->registers + MSP_DR);
- message->rxdata += 2;
- }
-}
-
-/**
- * u32_msp_read - Msp 32bit read function.
- * @xfer_data: transfer data structure.
- *
- * It reads 32bit data from msp receive fifo until it gets empty.
- *
- * Returns void.
- */
-static void u32_msp_read(struct trans_data *xfer_data)
-{
- struct i2s_message *message = &xfer_data->message;
- while ((message->rx_offset < message->rxbytes) &&
- !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
- RX_FIFO_EMPTY)) {
- *(u32 *) message->rxdata =
- (u32) stm_msp_read(xfer_data->msp->registers + MSP_DR);
- message->rx_offset += 4;
- message->rxdata += 4;
- }
-}
-static void u8_msp_write(struct trans_data *xfer_data)
-{
- struct i2s_message *message = &xfer_data->message;
- while ((message->tx_offset < message->txbytes) &&
- !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
- TX_FIFO_FULL)) {
- message->tx_offset += 1;
- stm_msp_write(*(u8 *) message->txdata,
- xfer_data->msp->registers + MSP_DR);
- message->txdata += 1;
- }
-}
-
-static void u16_msp_write(struct trans_data *xfer_data)
-{
- struct i2s_message *message = &xfer_data->message;
- while ((message->tx_offset < message->txbytes) &&
- !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
- TX_FIFO_FULL)) {
- message->tx_offset += 2;
- stm_msp_write(*(u16 *) message->txdata,
- xfer_data->msp->registers + MSP_DR);
- message->txdata += 2;
- }
-}
-
-/**
- * u32_msp_write - Msp 32bit write function.
- * @xfer_data: transfer data structure.
- *
- * It writes 32bit data to msp transmit fifo until it gets full.
- *
- * Returns void.
- */
-static void u32_msp_write(struct trans_data *xfer_data)
-{
- struct i2s_message *message = &xfer_data->message;
- while ((message->tx_offset < message->txbytes) &&
- !((stm_msp_read(xfer_data->msp->registers + MSP_FLR)) &
- TX_FIFO_FULL)) {
- message->tx_offset += 4;
- stm_msp_write(*(u32 *) message->txdata,
- xfer_data->msp->registers + MSP_DR);
- message->txdata += 4;
- }
-}
-
-/**
- * set_transmit_protocol_descriptor - Set the Transmit Configuration register.
- * @msp: main msp controller structure.
- * @protocol_desc: pointer to protocol descriptor structure.
- * @data_size: Run time configurable element length.
- *
- * It will setup transmit configuration register of msp.
- * Various values related to a particular protocol can be set like, elemnet
- * length, frame length, endianess etc.
- *
- * Returns void.
- */
-static void set_transmit_protocol_descriptor(struct msp *msp,
- struct msp_protocol_desc
- *protocol_desc,
- enum msp_data_size data_size)
-{
- u32 temp_reg = 0;
-
- temp_reg |= MSP_P2_ENABLE_BIT(protocol_desc->tx_phase_mode);
- temp_reg |= MSP_P2_START_MODE_BIT(protocol_desc->tx_phase2_start_mode);
- temp_reg |= MSP_P1_FRAME_LEN_BITS(protocol_desc->tx_frame_length_1);
- temp_reg |= MSP_P2_FRAME_LEN_BITS(protocol_desc->tx_frame_length_2);
- if (msp->def_elem_len) {
- temp_reg |=
- MSP_P1_ELEM_LEN_BITS(protocol_desc->tx_element_length_1);
- temp_reg |=
- MSP_P2_ELEM_LEN_BITS(protocol_desc->tx_element_length_2);
- if (protocol_desc->tx_element_length_1 ==
- protocol_desc->tx_element_length_2) {
- msp->actual_data_size =
- protocol_desc->tx_element_length_1;
- } else {
- msp->actual_data_size = data_size;
- }
- } else {
- temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
- temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
- msp->actual_data_size = data_size;
- }
- temp_reg |= MSP_DATA_DELAY_BITS(protocol_desc->tx_data_delay);
- temp_reg |=
- MSP_SET_ENDIANNES_BIT(protocol_desc->tx_bit_transfer_format);
- temp_reg |= MSP_FRAME_SYNC_POL(protocol_desc->tx_frame_sync_pol);
- temp_reg |= MSP_DATA_WORD_SWAP(protocol_desc->tx_half_word_swap);
- temp_reg |= MSP_SET_COMPANDING_MODE(protocol_desc->compression_mode);
- temp_reg |= MSP_SET_FRAME_SYNC_IGNORE(protocol_desc->frame_sync_ignore);
-
- stm_msp_write(temp_reg, msp->registers + MSP_TCF);
-}
-
-/**
- * set_receive_protocol_descriptor - Set the Receive Configuration register.
- * @msp: main msp controller structure.
- * @protocol_desc: pointer to protocol descriptor structure.
- * @data_size: Run time configurable element length.
- *
- * It will setup receive configuration register of msp.
- * Various values related to a particular protocol can be set like, elemnet
- * length, frame length, endianess etc.
- *
- * Returns void.
- */
-static void set_receive_protocol_descriptor(struct msp *msp,
- struct msp_protocol_desc
- *protocol_desc,
- enum msp_data_size
- data_size)
-{
- u32 temp_reg = 0;
-
- temp_reg |= MSP_P2_ENABLE_BIT(protocol_desc->rx_phase_mode);
- temp_reg |= MSP_P2_START_MODE_BIT(protocol_desc->rx_phase2_start_mode);
- temp_reg |= MSP_P1_FRAME_LEN_BITS(protocol_desc->rx_frame_length_1);
- temp_reg |= MSP_P2_FRAME_LEN_BITS(protocol_desc->rx_frame_length_2);
- if (msp->def_elem_len) {
- temp_reg |=
- MSP_P1_ELEM_LEN_BITS(protocol_desc->rx_element_length_1);
- temp_reg |=
- MSP_P2_ELEM_LEN_BITS(protocol_desc->rx_element_length_2);
- if (protocol_desc->rx_element_length_1 ==
- protocol_desc->rx_element_length_2) {
- msp->actual_data_size =
- protocol_desc->rx_element_length_1;
- } else {
- msp->actual_data_size = data_size;
- }
- } else {
- temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
- temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
- msp->actual_data_size = data_size;
- }
-
- temp_reg |= MSP_DATA_DELAY_BITS(protocol_desc->rx_data_delay);
- temp_reg |=
- MSP_SET_ENDIANNES_BIT(protocol_desc->rx_bit_transfer_format);
- temp_reg |= MSP_FRAME_SYNC_POL(protocol_desc->rx_frame_sync_pol);
- temp_reg |= MSP_DATA_WORD_SWAP(protocol_desc->rx_half_word_swap);
- temp_reg |= MSP_SET_COMPANDING_MODE(protocol_desc->expansion_mode);
- temp_reg |= MSP_SET_FRAME_SYNC_IGNORE(protocol_desc->frame_sync_ignore);
-
- stm_msp_write(temp_reg, msp->registers + MSP_RCF);
-
-}
-
-/**
- * configure_protocol - Configures transmit and receive protocol.
- * @msp: main msp controller structure.
- * @config: configuration structure passed by client driver
- *
- * This will configure transmit and receive protocol decriptors.
- *
- * Returns error(-1) on failure else success(0).
- */
-static int configure_protocol(struct msp *msp,
- struct msp_config *config)
-{
- int direction;
- struct msp_protocol_desc *protocol_desc;
- enum msp_data_size data_size;
- u32 temp_reg = 0;
-
- data_size = config->data_size;
- msp->def_elem_len = config->def_elem_len;
- direction = config->direction;
- if (config->default_protocol_desc == 1) {
- if (config->protocol >= MSP_INVALID_PROTOCOL) {
- printk(KERN_ERR
- "invalid protocol in configure_protocol()\n");
- return -EINVAL;
- }
- protocol_desc =
- (struct msp_protocol_desc *)&protocol_desc_tab[config->
- protocol];
- } else {
- protocol_desc =
- (struct msp_protocol_desc *)&config->protocol_desc;
- }
-
- if (data_size < MSP_DATA_BITS_DEFAULT
- || data_size > MSP_DATA_BITS_32) {
- printk(KERN_ERR
- "invalid data size requested in configure_protocol()\n");
- return -EINVAL;
- }
-
- switch (direction) {
- case MSP_TRANSMIT_MODE:
- set_transmit_protocol_descriptor(msp, protocol_desc, data_size);
- break;
- case MSP_RECEIVE_MODE:
- set_receive_protocol_descriptor(msp, protocol_desc, data_size);
- break;
- case MSP_BOTH_T_R_MODE:
- set_transmit_protocol_descriptor(msp, protocol_desc, data_size);
- set_receive_protocol_descriptor(msp, protocol_desc, data_size);
- break;
- default:
- printk(KERN_ERR "Invalid direction given\n");
- return -EINVAL;
- }
- /* The below code is needed for both Rx and Tx path can't separate
- * them.
- */
- temp_reg = stm_msp_read(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
- temp_reg |= MSP_TX_CLKPOL_BIT(~protocol_desc->tx_clock_pol);
- stm_msp_write(temp_reg, msp->registers + MSP_GCR);
- temp_reg = stm_msp_read(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
- temp_reg |= MSP_RX_CLKPOL_BIT(protocol_desc->rx_clock_pol);
- stm_msp_write(temp_reg, msp->registers + MSP_GCR);
-
- return 0;
-}
-
-/**
- * configure_clock - Set clock in sample rate generator.
- * @msp: main msp controller structure.
- * @config: configuration structure passed by client driver
- *
- * This will set the frame width and period. Also enable sample rate generator
- *
- * Returns error(-1) on failure else success(0).
- */
-static int configure_clock(struct msp *msp,
- struct msp_config *config)
-{
-
- u32 dummy;
- u32 frame_per = 0;
- u32 sck_div = 0;
- u32 frame_width = 0;
- u32 temp_reg = 0;
- u32 bit_clock = 0;
- struct msp_protocol_desc *protocol_desc = NULL;
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
- (~(SRG_ENABLE))), msp->registers + MSP_GCR);
-
- if (config->default_protocol_desc) {
- protocol_desc =
- (struct msp_protocol_desc *)&protocol_desc_tab[config->
- protocol];
- } else {
- protocol_desc =
- (struct msp_protocol_desc *)&config->protocol_desc;
- }
-
- switch (config->protocol) {
- case MSP_PCM_PROTOCOL:
- case MSP_PCM_COMPAND_PROTOCOL:
- frame_width = protocol_desc->frame_width;
- sck_div =
- config->input_clock_freq / (config->frame_freq *
- (protocol_desc->
- total_clocks_for_one_frame));
- frame_per = protocol_desc->frame_period;
- break;
- case MSP_I2S_PROTOCOL:
- frame_width = protocol_desc->frame_width;
- sck_div =
- config->input_clock_freq / (config->frame_freq *
- (protocol_desc->
- total_clocks_for_one_frame));
- frame_per = protocol_desc->frame_period;
-
- break;
- case MSP_AC97_PROTOCOL:
- /* Not supported */
- printk(KERN_WARNING "AC97 protocol not supported\n");
- return -ENOSYS;
- default:
- printk(KERN_ERR "Invalid mode attempted for setting clocks\n");
- return -EINVAL;
- }
-
- temp_reg = (sck_div - 1) & SCK_DIV_MASK;
- temp_reg |= FRAME_WIDTH_BITS(frame_width);
- temp_reg |= FRAME_PERIOD_BITS(frame_per);
- stm_msp_write(temp_reg, msp->registers + MSP_SRG);
-
- bit_clock = (config->input_clock_freq)/(sck_div + 1);
- /* If the bit clock is higher than 19.2MHz, Vape should be run in 100% OPP */
- /* Only consider OPP 100% when bit-clock is used, i.e. MSP master mode */
- if ((bit_clock > 19200000) && ((config->tx_clock_sel != 0) || (config->rx_clock_sel != 0))) {
- prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "msp_i2s", 100);
- msp->vape_opp_constraint = 1;
- } else {
- prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "msp_i2s", 50);
- msp->vape_opp_constraint = 0;
- }
-
- /* Wait a bit */
- dummy = ((stm_msp_read(msp->registers + MSP_SRG)) >> FRWID_SHIFT) & 0x0000003F;
-
- /* Enable clock */
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | ((SRG_ENABLE))),
- msp->registers + MSP_GCR);
-
- /* Another wait */
- dummy =
- ((stm_msp_read(msp->registers + MSP_SRG)) >> FRWID_SHIFT) &
- 0x0000003F;
- return 0;
-}
-
-/**
- * configure_multichannel - Enable multichannel support for transmit & receive.
- * @msp: main msp controller structure.
- * @config: configuration structure passed by client driver
- *
- * This will enable multichannel support for transmit and receive.
- * It will set Receive comparator also if configured.
- *
- * Returns error(-1) on failure else success(0).
- */
-static int configure_multichannel(struct msp *msp,
- struct msp_config *config)
-{
- struct msp_protocol_desc *protocol_desc;
- struct msp_multichannel_config *mult_config;
- if (config->default_protocol_desc == 1) {
- if (config->protocol >= MSP_INVALID_PROTOCOL) {
- printk(KERN_ERR
- "invalid protocol in configure_protocol()\n");
- return -EINVAL;
- }
- protocol_desc =
- (struct msp_protocol_desc *)&protocol_desc_tab[config->
- protocol];
- } else {
- protocol_desc =
- (struct msp_protocol_desc *)&config->protocol_desc;
- }
- mult_config = &config->multichannel_config;
- if (true == mult_config->tx_multichannel_enable) {
- if (MSP_SINGLE_PHASE == protocol_desc->tx_phase_mode) {
- stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) |
- ((mult_config->
- tx_multichannel_enable << TMCEN_BIT) &
- (0x0000020))),
- msp->registers + MSP_MCR);
- stm_msp_write(mult_config->tx_channel_0_enable,
- msp->registers + MSP_TCE0);
- stm_msp_write(mult_config->tx_channel_1_enable,
- msp->registers + MSP_TCE1);
- stm_msp_write(mult_config->tx_channel_2_enable,
- msp->registers + MSP_TCE2);
- stm_msp_write(mult_config->tx_channel_3_enable,
- msp->registers + MSP_TCE3);
- } else {
- printk(KERN_ERR "Not in authorised mode\n");
- return -1;
- }
- }
- if (true == mult_config->rx_multichannel_enable) {
- if (MSP_SINGLE_PHASE == protocol_desc->rx_phase_mode) {
- stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) |
- ((mult_config->
- rx_multichannel_enable << RMCEN_BIT) &
- (0x0000001))),
- msp->registers + MSP_MCR);
- stm_msp_write(mult_config->rx_channel_0_enable,
- msp->registers + MSP_RCE0);
- stm_msp_write(mult_config->rx_channel_1_enable,
- msp->registers + MSP_RCE1);
- stm_msp_write(mult_config->rx_channel_2_enable,
- msp->registers + MSP_RCE2);
- stm_msp_write(mult_config->rx_channel_3_enable,
- msp->registers + MSP_RCE3);
- } else {
- printk(KERN_ERR "Not in authorised mode\n");
- return -1;
- }
- if (mult_config->rx_comparison_enable_mode) {
- stm_msp_write((stm_msp_read(msp->registers + MSP_MCR) |
- ((mult_config->
- rx_comparison_enable_mode << RCMPM_BIT)
- & (0x0000018))),
- msp->registers + MSP_MCR);
-
- stm_msp_write(mult_config->comparison_mask,
- msp->registers + MSP_RCM);
- stm_msp_write(mult_config->comparison_value,
- msp->registers + MSP_RCV);
-
- }
- }
- return 0;
-
-}
-
-/**
- * configure_dma - configure dma channel for transmit or receive.
- * @msp: msp structure
- * @config: configuration structure.
- * Context: process
- *
- * It will configure dma channels and request them in Logical mode for both
- * transmit and recevie modes.It also register the respective callback handlers
- * for DMA.
- *
- * Returns void.
- */
-void configure_dma(struct msp *msp, struct msp_config *config)
-{
- struct stedma40_chan_cfg *rx_dma_info = msp->dma_cfg_rx;
- struct stedma40_chan_cfg *tx_dma_info = msp->dma_cfg_tx;
- dma_cap_mask_t mask;
-
- if (config->direction == MSP_TRANSMIT_MODE
- || config->direction == MSP_BOTH_T_R_MODE) {
-
- if (msp->tx_pipeid != NULL) {
- dma_release_channel(msp->tx_pipeid);
- msp->tx_pipeid = NULL;
- }
-
- if (config->data_size == MSP_DATA_BITS_32)
- tx_dma_info->src_info.data_width = STEDMA40_WORD_WIDTH;
- else if (config->data_size == MSP_DATA_BITS_16)
- tx_dma_info->src_info.data_width
- = STEDMA40_HALFWORD_WIDTH;
- else if (config->data_size == MSP_DATA_BITS_8)
- tx_dma_info->src_info.data_width
- = STEDMA40_BYTE_WIDTH;
- else
- printk(KERN_ERR "Wrong data size\n");
-
- if (config->data_size == MSP_DATA_BITS_32)
- tx_dma_info->dst_info.data_width = STEDMA40_WORD_WIDTH;
- else if (config->data_size == MSP_DATA_BITS_16)
- tx_dma_info->dst_info.data_width
- = STEDMA40_HALFWORD_WIDTH;
- else if (config->data_size == MSP_DATA_BITS_8)
- tx_dma_info->dst_info.data_width
- = STEDMA40_BYTE_WIDTH;
- else
- printk(KERN_ERR "Wrong data size\n");
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- msp->tx_pipeid = dma_request_channel(mask, stedma40_filter,
- tx_dma_info);
- }
- if (config->direction == MSP_RECEIVE_MODE
- || config->direction == MSP_BOTH_T_R_MODE) {
-
- if (msp->rx_pipeid != NULL) {
- dma_release_channel(msp->rx_pipeid);
- msp->rx_pipeid = NULL;
- }
-
- if (config->data_size == MSP_DATA_BITS_32)
- rx_dma_info->src_info.data_width = STEDMA40_WORD_WIDTH;
- else if (config->data_size == MSP_DATA_BITS_16)
- rx_dma_info->src_info.data_width
- = STEDMA40_HALFWORD_WIDTH;
- else if (config->data_size == MSP_DATA_BITS_8)
- rx_dma_info->src_info.data_width = STEDMA40_BYTE_WIDTH;
- else
- printk(KERN_ERR "Wrong data size\n");
-
- if (config->data_size == MSP_DATA_BITS_32)
- rx_dma_info->dst_info.data_width = STEDMA40_WORD_WIDTH;
- else if (config->data_size == MSP_DATA_BITS_16)
- rx_dma_info->dst_info.data_width
- = STEDMA40_HALFWORD_WIDTH;
- else if (config->data_size == MSP_DATA_BITS_8)
- rx_dma_info->dst_info.data_width = STEDMA40_BYTE_WIDTH;
- else
- printk(KERN_ERR "Wrong data size\n");
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- msp->rx_pipeid = dma_request_channel(mask, stedma40_filter,
- rx_dma_info);
- }
-
-}
-
-/**
- * msp_enable - Setup the msp configuration.
- * @msp: msp data contains main msp structure.
- * @config: configuration structure sent by i2s client driver.
- * Context: process
- *
- * Main msp configuring functions to configure msp in accordance with msp
- * protocol descriptor, configuring msp clock,setup transfer mode selected by
- * user like DMA, interrupt or polling and in the end enable RX and Tx path.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-static int msp_enable(struct msp *msp, struct msp_config *config)
-{
- int status = 0;
- int state;
-
- /* Check msp state whether in RUN or CONFIGURED Mode */
- state = msp->msp_state;
- if (state == MSP_STATE_IDLE) {
- if (msp->plat_init) {
- status = msp->plat_init();
- if (status) {
- printk(KERN_ERR "Error in msp_i2s_init,"
- " status is %d\n", status);
- return status;
- }
- }
- }
-
- /* Configure msp with protocol dependent settings */
- configure_protocol(msp, config);
- configure_clock(msp, config);
- if (config->multichannel_configured == 1) {
- status = configure_multichannel(msp, config);
- if (status)
- printk(KERN_ERR "multichannel can't be configured\n");
- }
- msp->work_mode = config->work_mode;
-
- if (msp->work_mode == MSP_DMA_MODE && !msp->dma_cfg_rx) {
- switch (config->direction) {
- case MSP_RECEIVE_MODE:
- case MSP_BOTH_T_R_MODE:
- dev_err(&msp->i2s_cont->dev, "RX DMA not available");
- return -EINVAL;
- }
- }
-
- if (msp->work_mode == MSP_DMA_MODE && !msp->dma_cfg_tx) {
- switch (config->direction) {
- case MSP_TRANSMIT_MODE:
- case MSP_BOTH_T_R_MODE:
- dev_err(&msp->i2s_cont->dev, "TX DMA not available");
- return -EINVAL;
- }
- }
-
- switch (config->direction) {
- case MSP_TRANSMIT_MODE:
- /*Currently they are ignored
- stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) |
- TRANSMIT_UNDERRUN_ERR_INT |
- TRANSMIT_FRAME_SYNC_ERR_INT),
- msp->registers + MSP_IMSC); */
- if (config->work_mode == MSP_DMA_MODE) {
- stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) |
- TX_DMA_ENABLE,
- msp->registers + MSP_DMACR);
-
- msp->xfer_data.tx_handler = config->handler;
- msp->xfer_data.tx_callback_data =
- config->tx_callback_data;
- configure_dma(msp, config);
- }
- if (config->work_mode == MSP_POLLING_MODE) {
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (TX_ENABLE)), msp->registers + MSP_GCR);
- }
- if (msp->work_mode != MSP_DMA_MODE) {
- switch (msp->actual_data_size) {
- case MSP_DATA_BITS_8:
- msp->write = u8_msp_write;
- break;
- case MSP_DATA_BITS_10:
- case MSP_DATA_BITS_12:
- case MSP_DATA_BITS_14:
- case MSP_DATA_BITS_16:
- msp->write = u16_msp_write;
- break;
- case MSP_DATA_BITS_20:
- case MSP_DATA_BITS_24:
- case MSP_DATA_BITS_32:
- default:
- msp->write = u32_msp_write;
- break;
- }
- msp->xfer_data.tx_handler = config->handler;
- msp->xfer_data.tx_callback_data =
- config->tx_callback_data;
- msp->xfer_data.rx_callback_data =
- config->rx_callback_data;
- msp->xfer_data.msp = msp;
- }
- break;
- case MSP_RECEIVE_MODE:
- /*Currently they are ignored
- stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) |
- RECEIVE_OVERRUN_ERROR_INT | RECEIVE_FRAME_SYNC_ERR_INT,
- msp->registers + MSP_IMSC); */
- if (config->work_mode == MSP_DMA_MODE) {
- stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) |
- RX_DMA_ENABLE,
- msp->registers + MSP_DMACR);
-
- msp->xfer_data.rx_handler = config->handler;
- msp->xfer_data.rx_callback_data =
- config->rx_callback_data;
-
- configure_dma(msp, config);
- }
- if (config->work_mode == MSP_POLLING_MODE) {
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (RX_ENABLE)), msp->registers + MSP_GCR);
- }
- if (msp->work_mode != MSP_DMA_MODE) {
- switch (msp->actual_data_size) {
- case MSP_DATA_BITS_8:
- msp->read = u8_msp_read;
- break;
- case MSP_DATA_BITS_10:
- case MSP_DATA_BITS_12:
- case MSP_DATA_BITS_14:
- case MSP_DATA_BITS_16:
- msp->read = u16_msp_read;
- break;
- case MSP_DATA_BITS_20:
- case MSP_DATA_BITS_24:
- case MSP_DATA_BITS_32:
- default:
- msp->read = u32_msp_read;
- break;
- }
- msp->xfer_data.rx_handler = config->handler;
- msp->xfer_data.tx_callback_data =
- config->tx_callback_data;
- msp->xfer_data.rx_callback_data =
- config->rx_callback_data;
- msp->xfer_data.msp = msp;
- }
-
- break;
- case MSP_BOTH_T_R_MODE:
- /*Currently they are ignored
- stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) |
- RECEIVE_OVERRUN_ERROR_INT | RECEIVE_FRAME_SYNC_ERR_INT |
- TRANSMIT_UNDERRUN_ERR_INT | TRANSMIT_FRAME_SYNC_ERR_INT ,
- msp->registers + MSP_IMSC); */
- if (config->work_mode == MSP_DMA_MODE) {
- stm_msp_write(stm_msp_read(msp->registers + MSP_DMACR) |
- RX_DMA_ENABLE | TX_DMA_ENABLE,
- msp->registers + MSP_DMACR);
-
- msp->xfer_data.tx_handler = config->handler;
- msp->xfer_data.rx_handler = config->handler;
- msp->xfer_data.tx_callback_data =
- config->tx_callback_data;
- msp->xfer_data.rx_callback_data =
- config->rx_callback_data;
-
- configure_dma(msp, config);
- }
- if (config->work_mode == MSP_POLLING_MODE) {
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (TX_ENABLE)), msp->registers + MSP_GCR);
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (RX_ENABLE)), msp->registers + MSP_GCR);
- }
- if (msp->work_mode != MSP_DMA_MODE) {
- switch (msp->actual_data_size) {
- case MSP_DATA_BITS_8:
- msp->read = u8_msp_read;
- msp->write = u8_msp_write;
- break;
- case MSP_DATA_BITS_10:
- case MSP_DATA_BITS_12:
- case MSP_DATA_BITS_14:
- case MSP_DATA_BITS_16:
- msp->read = u16_msp_read;
- msp->write = u16_msp_write;
- break;
- case MSP_DATA_BITS_20:
- case MSP_DATA_BITS_24:
- case MSP_DATA_BITS_32:
- default:
- msp->read = u32_msp_read;
- msp->write = u32_msp_write;
- break;
- }
- msp->xfer_data.tx_handler = config->handler;
- msp->xfer_data.rx_handler = config->handler;
- msp->xfer_data.tx_callback_data =
- config->tx_callback_data;
- msp->xfer_data.rx_callback_data =
- config->rx_callback_data;
- msp->xfer_data.msp = msp;
- }
-
- break;
- default:
- printk(KERN_ERR "Invalid direction parameter\n");
- if (msp->plat_exit)
- msp->plat_exit();
- status = -EINVAL;
- return status;
- }
-
- switch (config->work_mode) {
- case MSP_DMA_MODE:
- msp->transfer = msp_dma_xfer;
- break;
- case MSP_POLLING_MODE:
- msp->transfer = msp_polling_xfer;
- break;
- case MSP_INTERRUPT_MODE:
- msp->transfer = msp_interrupt_xfer;
- break;
- default:
- msp->transfer = NULL;
- }
-
- stm_msp_write(config->iodelay, msp->registers + MSP_IODLY);
-
- /* enable frame generation logic */
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (FRAME_GEN_ENABLE)), msp->registers + MSP_GCR);
-
- return status;
-}
-
-/**
- * flush_rx_fifo - Flush Rx fifo MSP controller.
- * @msp: msp structure.
- *
- * This function flush the rx fifo of msp controller.
- *
- * Returns error(-1) in case of failure else success(0)
- */
-static void flush_rx_fifo(struct msp *msp)
-{
- u32 dummy = 0;
- u32 limit = 32;
- u32 cur = stm_msp_read(msp->registers + MSP_GCR);
- stm_msp_write(cur | RX_ENABLE, msp->registers + MSP_GCR);
- while (!(stm_msp_read(msp->registers + MSP_FLR) & RX_FIFO_EMPTY)
- && limit--) {
- dummy = stm_msp_read(msp->registers + MSP_DR);
- }
- stm_msp_write(cur, msp->registers + MSP_GCR);
-}
-
-/**
- * flush_tx_fifo - Flush Tx fifo MSP controller.
- * @msp: msp structure.
- *
- * This function flush the tx fifo using test intergration register to read data
- * from tx fifo directly.
- *
- * Returns error(-1) in case of failure else success(0)
- */
-static void flush_tx_fifo(struct msp *msp)
-{
- u32 dummy = 0;
- u32 limit = 32;
- u32 cur = stm_msp_read(msp->registers + MSP_GCR);
- stm_msp_write(cur | TX_ENABLE, msp->registers + MSP_GCR);
- stm_msp_write(0x3, msp->registers + MSP_ITCR);
- while (!(stm_msp_read(msp->registers + MSP_FLR) & TX_FIFO_EMPTY)
- && limit--) {
- dummy = stm_msp_read(msp->registers + MSP_TSTDR);
- }
- stm_msp_write(0x0, msp->registers + MSP_ITCR);
- stm_msp_write(cur, msp->registers + MSP_GCR);
-}
-
-/**
- * stm_msp_configure_enable - configures and enables the MSP controller.
- * @i2s_cont: i2s controller sent by i2s device.
- * @configuration: specifies the configuration parameters.
- *
- * This function configures the msp controller with the client configuration.
- *
- * Returns error(-1) in case of failure else success(0)
- */
-static int stm_msp_configure_enable(struct i2s_controller *i2s_cont,
- void *configuration)
-{
- u32 old_reg;
- u32 new_reg;
- u32 mask;
- int res;
- struct msp_config *config =
- (struct msp_config *)configuration;
- struct msp *msp = (struct msp *)i2s_cont->data;
-
- if (in_interrupt()) {
- printk(KERN_ERR
- "can't call configure_enable in interrupt context\n");
- return -1;
- }
-
- /* Two simultanous configuring msp is avoidable */
- down(&msp->lock);
-
- /* Don't enable regulator if its msp1 or msp3 */
- if (!(msp->reg_enabled) && msp->id != MSP_1_I2S_CONTROLLER
- && msp->id != MSP_3_I2S_CONTROLLER) {
- res = regulator_enable(msp_vape_supply);
- if (res != 0) {
- dev_err(&msp->i2s_cont->dev,
- "Failed to enable regulator\n");
- up(&msp->lock);
- return res;
- }
- msp->reg_enabled = 1;
- }
-
- switch (msp->users) {
- case 0:
- clk_enable(msp->clk);
- msp->direction = config->direction;
- break;
- case 1:
- if (msp->direction == MSP_BOTH_T_R_MODE ||
- config->direction == msp->direction ||
- config->direction == MSP_BOTH_T_R_MODE) {
- dev_notice(&i2s_cont->dev, "%s: MSP in use in the "
- "desired direction.\n", __func__);
- up(&msp->lock);
- return -EBUSY;
- }
- msp->direction = MSP_BOTH_T_R_MODE;
- break;
- default:
- dev_notice(&i2s_cont->dev, "%s: MSP in use in both "
- "directions.\n", __func__);
- up(&msp->lock);
- return -EBUSY;
- }
- msp->users++;
-
- /* First do the global config register */
- mask =
- RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FRAME_SYNC_MASK |
- TX_FRAME_SYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
- RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
- LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
-
- new_reg =
- (config->tx_clock_sel | config->rx_clock_sel | config->
- rx_frame_sync_pol | config->tx_frame_sync_pol | config->
- rx_frame_sync_sel | config->tx_frame_sync_sel | config->
- rx_fifo_config | config->tx_fifo_config | config->
- srg_clock_sel | config->loopback_enable | config->tx_data_enable);
-
- old_reg = stm_msp_read(msp->registers + MSP_GCR);
- old_reg &= ~mask;
- new_reg |= old_reg;
- stm_msp_write(new_reg, msp->registers + MSP_GCR);
-
- if (msp_enable(msp, config) != 0) {
- printk(KERN_ERR "error enabling MSP\n");
- return -EBUSY;
- }
- if (config->loopback_enable & 0x80)
- msp->loopback_enable = 1;
-
- /* Flush MSP-FIFOs */
- flush_tx_fifo(msp);
- flush_rx_fifo(msp);
-
- msp->msp_state = MSP_STATE_CONFIGURED;
- up(&msp->lock);
- return 0;
-}
-
-static int msp_start_dma(struct msp *msp, int transmit, dma_addr_t data,
- size_t bytes)
-{
- struct dma_async_tx_descriptor *desc;
- struct scatterlist sg;
-
- sg_init_table(&sg, 1);
- sg_set_page(&sg, pfn_to_page(PFN_DOWN(data)), bytes,
- offset_in_page(data));
- sg_dma_address(&sg) = data;
- sg_dma_len(&sg) = bytes;
-
- if (transmit) {
- if (!msp->tx_pipeid)
- return -EINVAL;
- desc = msp->tx_pipeid->device->
- device_prep_slave_sg(msp->tx_pipeid,
- &sg, 1, DMA_TO_DEVICE,
- DMA_PREP_INTERRUPT
- | DMA_CTRL_ACK);
- if (!desc)
- return -ENOMEM;
-
- desc->callback = msp->xfer_data.tx_handler;
- desc->callback_param = msp->xfer_data.tx_callback_data;
- desc->tx_submit(desc);
- dma_async_issue_pending(msp->tx_pipeid);
- } else {
- if (!msp->rx_pipeid)
- return -EINVAL;
-
- desc = msp->rx_pipeid->device->
- device_prep_slave_sg(msp->rx_pipeid,
- &sg, 1, DMA_FROM_DEVICE,
- DMA_PREP_INTERRUPT
- | DMA_CTRL_ACK);
- if (!desc)
- return -EBUSY;
-
- desc->callback = msp->xfer_data.rx_handler;
- desc->callback_param = msp->xfer_data.rx_callback_data;
- desc->tx_submit(desc);
- dma_async_issue_pending(msp->rx_pipeid);
- }
-
- return 0;
-}
-
-static int msp_single_dma_tx(struct msp *msp, dma_addr_t data, size_t bytes)
-{
- int status;
- status = msp_start_dma(msp, 1, data, bytes);
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (TX_ENABLE)),
- msp->registers + MSP_GCR);
- return status;
-}
-
-static int msp_single_dma_rx(struct msp *msp, dma_addr_t data, size_t bytes)
-{
- int status;
- status = msp_start_dma(msp, 0, data, bytes);
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) | (RX_ENABLE)),
- msp->registers + MSP_GCR);
- return status;
-}
-
-static void msp_cyclic_dma_start(struct msp *msp,
- dma_addr_t buf_addr,
- size_t buf_len,
- size_t period_len,
- enum dma_data_direction direction)
-{
- int ret;
- struct dma_async_tx_descriptor *cdesc;
- struct dma_chan *pipeid = (direction == DMA_TO_DEVICE) ?
- msp->tx_pipeid :
- msp->rx_pipeid;
-
- pr_debug("%s: buf_addr = %p\n", __func__, (void *) buf_addr);
- pr_debug("%s: buf_len = %d\n", __func__, buf_len);
- pr_debug("%s: perios_len = %d\n", __func__, period_len);
-
- /* setup the cyclic description */
- cdesc = pipeid->device->device_prep_dma_cyclic(pipeid,
- buf_addr, /* reuse the sq list for the moment */
- buf_len,
- period_len,
- direction);
-
- if (IS_ERR(cdesc)) {
- pr_err("%s: Error: device_prep_dma_cyclic failed (%ld)!\n",
- __func__,
- PTR_ERR(cdesc));
- return;
- }
-
- cdesc->callback = (direction == DMA_TO_DEVICE) ?
- msp->xfer_data.tx_handler :
- msp->xfer_data.rx_handler;
- cdesc->callback_param = (direction == DMA_TO_DEVICE) ?
- msp->xfer_data.tx_callback_data :
- msp->xfer_data.rx_callback_data;
-
- /* submit to the dma */
- ret = dmaengine_submit(cdesc);
-
- /* start the dma */
- dma_async_issue_pending(pipeid);
-
- return;
-}
-
-/* Legacy function. Used by HATS driver. */
-static void msp_loopback_inf_start_dma(struct msp *msp,
- dma_addr_t data,
- size_t bytes)
-{
-#if 0
- struct stedma40_cyclic_desc *rxcdesc;
- struct stedma40_cyclic_desc *txcdesc;
- struct scatterlist rxsg[2];
- struct scatterlist txsg[2];
- size_t len = bytes >> 1;
- int ret;
-
- sg_init_table(rxsg, ARRAY_SIZE(rxsg));
- sg_init_table(txsg, ARRAY_SIZE(txsg));
-
- sg_dma_len(&rxsg[0]) = len;
- sg_dma_len(&rxsg[1]) = len;
- sg_dma_len(&txsg[0]) = len;
- sg_dma_len(&txsg[1]) = len;
-
- sg_dma_address(&rxsg[0]) = data;
- sg_dma_address(&rxsg[1]) = data + len;
-
- sg_dma_address(&txsg[0]) = data + len;
- sg_dma_address(&txsg[1]) = data;
-
- rxcdesc = stedma40_cyclic_prep_sg(msp->rx_pipeid,
- rxsg, ARRAY_SIZE(rxsg),
- DMA_FROM_DEVICE, 0);
- if (IS_ERR(rxcdesc))
- return;
-
- txcdesc = stedma40_cyclic_prep_sg(msp->tx_pipeid,
- txsg, ARRAY_SIZE(txsg),
- DMA_TO_DEVICE, 0);
- if (IS_ERR(txcdesc))
- goto free_rx;
-
- ret = stedma40_cyclic_start(msp->rx_pipeid);
- if (ret)
- goto free_tx;
-
- ret = stedma40_cyclic_start(msp->tx_pipeid);
- if (ret)
- goto stop_rx;
-
- msp->infinite = true;
-
- return;
-
-stop_rx:
- stedma40_cyclic_stop(msp->rx_pipeid);
-free_tx:
- stedma40_cyclic_free(msp->tx_pipeid);
-free_rx:
- stedma40_cyclic_free(msp->rx_pipeid);
-#endif
- return;
-}
-
-/**
- * msp_dma_xfer - Handles DMA transfers over i2s bus.
- * @msp: main msp structure.
- * @msg: i2s_message contains info about transmit and receive data.
- * Context: process
- *
- * This will first check whether data buffer is dmaable or not.
- * Call dma_map_single apis etc to make it dmaable dma. Starts the dma transfer
- * for TX and RX parallely and wait for it to get completed.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-static int msp_dma_xfer(struct msp *msp, struct i2s_message *msg)
-{
- int status = 0;
-
- switch (msg->i2s_transfer_mode) {
- default:
- case I2S_TRANSFER_MODE_SINGLE_DMA:
- if (msg->i2s_direction == I2S_DIRECTION_RX ||
- msg->i2s_direction == I2S_DIRECTION_BOTH)
- if (msg->rxdata && (msg->rxbytes > 0)) {
- if (!msg->dma_flag)
- msg->rxdata =
- (void *)dma_map_single(NULL,
- msg->rxdata,
- msg->rxbytes,
- DMA_FROM_DEVICE
- );
- status = msp_single_dma_rx(msp,
- (dma_addr_t)msg->rxdata,
- msg->rxbytes);
- }
- if (msg->i2s_direction == I2S_DIRECTION_TX ||
- msg->i2s_direction == I2S_DIRECTION_BOTH)
- if (msg->txdata && (msg->txbytes > 0)) {
- if (!msg->dma_flag)
- msg->txdata =
- (void *)dma_map_single(NULL,
- msg->txdata,
- msg->txbytes,
- DMA_TO_DEVICE);
- status = msp_single_dma_tx(msp,
- (dma_addr_t)msg->txdata,
- msg->txbytes);
- }
- break;
-
- case I2S_TRANSFER_MODE_CYCLIC_DMA:
- if (msg->i2s_direction == I2S_DIRECTION_TX) {
- msp_cyclic_dma_start(msp,
- msg->buf_addr,
- msg->buf_len,
- msg->period_len,
- DMA_TO_DEVICE);
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (TX_ENABLE)),
- msp->registers + MSP_GCR);
- } else {
- msp_cyclic_dma_start(msp,
- msg->buf_addr,
- msg->buf_len,
- msg->period_len,
- DMA_FROM_DEVICE);
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (RX_ENABLE)),
- msp->registers + MSP_GCR);
- }
- break;
-
- case I2S_TRANSFER_MODE_INF_LOOPBACK:
- msp_loopback_inf_start_dma(msp,
- (dma_addr_t)msg->rxdata,
- msg->rxbytes);
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (RX_ENABLE)),
- msp->registers + MSP_GCR);
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (TX_ENABLE)),
- msp->registers + MSP_GCR);
- break;
- }
-
- return status;
-}
-
-#if 0
-/**
- * msp_handle_irq - Interrupt handler routine.
- * @irq: irq no.
- * @dev_id: device structure registered in request irq.
- *
- * Returns error(-1) on failure else success(0).
- */
-static irqreturn_t msp_handle_irq(int irq, void *dev_id)
-{
- u32 irq_status;
- struct msp *msp = (struct msp *)dev_id;
- struct i2s_message *message = &msp->xfer_data.message;
- u32 irq_mask = 0;
- irq_status = stm_msp_read(msp->registers + MSP_MIS);
- irq_mask = stm_msp_read(msp->registers + MSP_IMSC);
-/* Disable the interrupt to prevent immediate recurrence */
- stm_msp_write(stm_msp_read(msp->registers + MSP_IMSC) & ~irq_status,
- msp->registers + MSP_IMSC);
-
-/* Clear the interrupt */
- stm_msp_write(irq_status, msp->registers + MSP_ICR);
-/* Check for an error condition */
- msp->msp_io_error = irq_status & (RECEIVE_OVERRUN_ERROR_INT |
- RECEIVE_FRAME_SYNC_ERR_INT |
- TRANSMIT_UNDERRUN_ERR_INT |
- TRANSMIT_FRAME_SYNC_ERR_INT);
-
- /*Currently they are ignored */
- if (irq_status & RECEIVE_OVERRUN_ERROR_INT)
- ;
- if (irq_status & TRANSMIT_UNDERRUN_ERR_INT)
- ;
-
- /* This code has been added basically to support loopback mode
- * Basically Transmit interrupt is not disabled even after its
- * completion so that receive fifo gets an additional interrupt
- */
- if (irq_mask & (RECEIVE_SERVICE_INT)
- && (irq_mask & (TRANSMIT_SERVICE_INT)) && (msp->loopback_enable)) {
- if (msp->read)
- msp->read(&msp->xfer_data);
- if (msp->write)
- msp->write(&msp->xfer_data);
- if (message->rx_offset >= message->rxbytes) {
- if (msp->xfer_data.rx_handler)
- msp->xfer_data.rx_handler(msp->
- xfer_data.
- rx_callback_data,
- message->rx_offset);
- msp->xfer_data.rx_handler = NULL;
- return IRQ_HANDLED;
- }
-
- if (message->tx_offset >= message->txbytes) {
- if (msp->xfer_data.tx_handler)
- msp->xfer_data.tx_handler(msp->xfer_data.
- tx_callback_data,
- message->tx_offset);
- msp->xfer_data.tx_handler = NULL;
- }
- stm_msp_write(irq_mask, msp->registers + MSP_IMSC);
- return IRQ_HANDLED;
- }
-
- if (irq_status & RECEIVE_SERVICE_INT) {
- if (msp->read)
- msp->read(&msp->xfer_data);
- if (message->rx_offset >= message->rxbytes) {
- irq_mask &= ~RECEIVE_SERVICE_INT;
- stm_msp_write(irq_mask, msp->registers + MSP_IMSC);
- if (msp->xfer_data.rx_handler)
- msp->xfer_data.rx_handler(msp->
- xfer_data.
- rx_callback_data,
- message->rx_offset);
- if (!(irq_status & TRANSMIT_SERVICE_INT))
- return IRQ_HANDLED;
- }
- }
- if (irq_status & TRANSMIT_SERVICE_INT) {
- if (msp->write)
- msp->write(&msp->xfer_data);
- if (message->tx_offset >= message->txbytes) {
- irq_mask &= ~TRANSMIT_SERVICE_INT;
- stm_msp_write(irq_mask, msp->registers + MSP_IMSC);
- if (msp->xfer_data.tx_handler)
- msp->xfer_data.tx_handler(msp->xfer_data.
- tx_callback_data,
- message->tx_offset);
- return IRQ_HANDLED;
- }
- }
- stm_msp_write(irq_mask, msp->registers + MSP_IMSC);
- return IRQ_HANDLED;
-
-}
-#endif
-
-/**
- * msp_interrupt_xfer - Handles Interrupt transfers over i2s bus.
- * @msp: main msp structure.
- * @msg: i2s_message contains info about transmit and receive data.
- * Context: Process or interrupt.
- *
- * This implements transfer and receive functions used in interrupt mode.
- * This can be used in interrupt context if a callback handler is registered
- * by client driver. This has been to improve performance in interrupt mode.
- * Hence can't use sleep in this function.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-static int msp_interrupt_xfer(struct msp *msp, struct i2s_message *msg)
-{
- struct i2s_message *message;
- u32 irq_mask = 0;
-
- if (msg->i2s_transfer_mode != I2S_TRANSFER_MODE_NON_DMA)
- return -EINVAL;
-
- if (msg->txbytes) {
- msp->xfer_data.message.txbytes = msg->txbytes;
- msp->xfer_data.message.txdata = msg->txdata;
- msp->xfer_data.message.tx_offset = 0;
- }
- if (msg->rxbytes) {
- msp->xfer_data.message.rxbytes = msg->rxbytes;
- msp->xfer_data.message.rxdata = msg->rxdata;
- msp->xfer_data.message.rx_offset = 0;
- }
- message = &msp->xfer_data.message;
- if ((message->txdata == NULL || message->txbytes == 0)
- && (message->rxdata == NULL || message->rxbytes == 0)) {
- printk(KERN_ERR
- "transmit_receive_data is NULL with bytes > 0\n");
- return -EINVAL;
- }
-
- msp->msp_io_error = 0;
-
- if (message->tx_offset < message->txbytes) {
- irq_mask |= TRANSMIT_SERVICE_INT;
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (TX_ENABLE)), msp->registers + MSP_GCR);
- }
- if (message->rx_offset < message->rxbytes) {
- irq_mask |= RECEIVE_SERVICE_INT;
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (RX_ENABLE)), msp->registers + MSP_GCR);
- }
- stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) |
- irq_mask), msp->registers + MSP_IMSC);
- return 0;
-}
-
-/**
- * func_notify_timer - Handles Polling hang issue over i2s bus.
- * @data: main msp data address
- * Context: Interrupt.
- *
- * This is used to handle error condition in transfer and receive function used
- * in polling mode.
- * Sometimes due to passing wrong protocol desc , polling transfer may hang.
- * To prevent this, timer is added.
- *
- * Returns void.
- */
-static void func_notify_timer(unsigned long data)
-{
- struct msp *msp = (struct msp *)data;
- if (msp->polling_flag) {
- msp->msp_io_error = 1;
- printk(KERN_ERR
- "Polling is taking two much time, may be it got hang\n");
- del_timer(&msp->notify_timer);
- }
-}
-
-/**
- * msp_polling_xfer - Handles Polling transfers over i2s bus.
- * @msp: main msp structure.
- * @msg: i2s_message contains info about transmit and receive data.
- * Context: Process.
- *
- * This implements transfer and receive functions used in polling mode. This is
- * blocking fucntion.
- * It is recommended to use interrupt or dma mode for better performance rather
- * than the polling mode.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-static int msp_polling_xfer(struct msp *msp, struct i2s_message *msg)
-{
- struct i2s_message *message;
- u32 time_expire = 0;
- u32 tr_ex = 0, rr_ex = 0;
- u32 msec_jiffies = 0;
-
- if (msg->i2s_transfer_mode != I2S_TRANSFER_MODE_NON_DMA)
- return -EINVAL;
-
- if (msg->txbytes) {
- msp->xfer_data.message.txbytes = msg->txbytes;
- msp->xfer_data.message.txdata = msg->txdata;
- msp->xfer_data.message.tx_offset = 0;
- tr_ex = msg->txbytes;
- }
- if (msg->rxbytes) {
- msp->xfer_data.message.rxbytes = msg->rxbytes;
- msp->xfer_data.message.rxdata = msg->rxdata;
- msp->xfer_data.message.rx_offset = 0;
- rr_ex = msg->rxbytes;
- }
- message = &msp->xfer_data.message;
- time_expire = (tr_ex + rr_ex) / 1024;
- if (!time_expire)
- msec_jiffies = 500;
- else
- msec_jiffies = time_expire * 500;
- msp->notify_timer.expires = jiffies + msecs_to_jiffies(msec_jiffies);
- down(&msp->lock);
- if (message->txdata == NULL && message->txbytes > 0) {
- printk(KERN_ERR
- "transmit_receive_data is NULL with bytes > 0\n");
- return -EINVAL;
- }
-
- if (message->rxdata == NULL && message->rxbytes > 0) {
- printk(KERN_ERR
- "transmit_receive_data is NULL with bytes > 0\n");
- return -EINVAL;
- }
- msp->msp_io_error = 0;
- msp->polling_flag = 1;
- add_timer(&msp->notify_timer);
- while (message->tx_offset < message->txbytes
- || message->rx_offset < message->rxbytes) {
- if (msp->msp_io_error)
- break;
- if (msp->read)
- msp->read(&msp->xfer_data);
- if (msp->write)
- msp->write(&msp->xfer_data);
- }
- msp->polling_flag = 0;
- del_timer(&msp->notify_timer);
- up(&msp->lock);
- return message->txbytes + message->rxbytes;
-}
-
-/**
- * stm_msp_transceive_data - Main i2s transfer function.
- * @i2s_cont: i2s controller structure passed by client driver.
- * @message: i2s message structure contains transceive info.
- * Context: process or interrupt.
- *
- * This function is registered over i2s_xfer funtions. It will handle main i2s
- * transfer over i2s bus in various modes.It call msp transfer function on which
- * suitable transfer function is already registered i.e dma ,interrupt or
- * polling function.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-static int stm_msp_transceive_data(struct i2s_controller *i2s_cont,
- struct i2s_message *message)
-{
- int status = 0;
- struct msp *msp = (struct msp *)i2s_cont->data;
-
- if (!message || (msp->msp_state == MSP_STATE_IDLE)) {
- printk(KERN_ERR "Message is NULL\n");
- return -EPERM;
- }
-
- msp->msp_state = MSP_STATE_RUN;
- if (msp->transfer)
- status = msp->transfer(msp, message);
-
- if (msp->msp_state == MSP_STATE_RUN)
- msp->msp_state = MSP_STATE_CONFIGURED;
-
- return status;
-}
-
-/**
- * msp_disable_receive - Disable receive functionality.
- * @msp: main msp structure.
- * Context: process.
- *
- * This function will disable msp controller's receive functionality like dma,
- * interrupt receive data buffer all are disabled.
- *
- * Returns void.
- */
-static void msp_disable_receive(struct msp *msp)
-{
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
- (~RX_ENABLE)), msp->registers + MSP_GCR);
- stm_msp_write((stm_msp_read(msp->registers + MSP_DMACR) &
- (~RX_DMA_ENABLE)), msp->registers + MSP_DMACR);
- stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) &
- (~
- (RECEIVE_SERVICE_INT |
- RECEIVE_OVERRUN_ERROR_INT))),
- msp->registers + MSP_IMSC);
- msp->xfer_data.message.rxbytes = 0;
- msp->xfer_data.message.rx_offset = 0;
- msp->xfer_data.message.rxdata = NULL;
- msp->read = NULL;
-
-}
-
-/**
- * msp_disable_transmit - Disable transmit functionality.
- * @msp: main msp structure.
- * Context: process.
- *
- * This function will disable msp controller's transmit functionality like dma,
- * interrupt transmit data buffer all are disabled.
- *
- * Returns void.
- */
-static void msp_disable_transmit(struct msp *msp)
-{
-
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
- (~TX_ENABLE)), msp->registers + MSP_GCR);
- stm_msp_write((stm_msp_read(msp->registers + MSP_DMACR) &
- (~TX_DMA_ENABLE)), msp->registers + MSP_DMACR);
- stm_msp_write((stm_msp_read(msp->registers + MSP_IMSC) &
- (~
- (TRANSMIT_SERVICE_INT |
- TRANSMIT_UNDERRUN_ERR_INT))),
- msp->registers + MSP_IMSC);
- msp->xfer_data.message.txbytes = 0;
- msp->xfer_data.message.tx_offset = 0;
- msp->xfer_data.message.txdata = NULL;
- msp->write = NULL;
-
-}
-
-/**
- * stm_msp_disable - disable the given msp controller
- * @msp: specifies the msp contoller data
- * @direction: specifies the transmit/receive direction
- * @flag: It indicates the functionality that needs to be disabled.
- *
- * Returns error(-1) in case of failure else success(0)
- */
-static int stm_msp_disable(struct msp *msp, int direction, i2s_flag flag)
-{
- int limit = 32;
- u32 dummy = 0;
- int status = 0;
- if (!
- (stm_msp_read(msp->registers + MSP_GCR) &
- ((TX_ENABLE | RX_ENABLE)))) {
- return 0;
- }
- if (msp->work_mode == MSP_DMA_MODE) {
- if (flag == DISABLE_ALL || flag == DISABLE_TRANSMIT) {
- if (msp->tx_pipeid != NULL) {
- dmaengine_terminate_all(msp->tx_pipeid);
- dma_release_channel(msp->tx_pipeid);
- msp->tx_pipeid = NULL;
- }
- }
- if ((flag == DISABLE_ALL || flag == DISABLE_RECEIVE)) {
- if (msp->rx_pipeid != NULL) {
- dmaengine_terminate_all(msp->rx_pipeid);
- dma_release_channel(msp->rx_pipeid);
- msp->rx_pipeid = NULL;
- }
- }
- }
- if (flag == DISABLE_TRANSMIT)
- msp_disable_transmit(msp);
- else if (flag == DISABLE_RECEIVE)
- msp_disable_receive(msp);
- else {
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) |
- (LOOPBACK_MASK)), msp->registers + MSP_GCR);
- /* Flush Tx fifo */
- while ((!
- (stm_msp_read(msp->registers + MSP_FLR) &
- TX_FIFO_EMPTY)) && limit--)
- dummy = stm_msp_read(msp->registers + MSP_DR);
-
- /* Disable Transmit channel */
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
- (~TX_ENABLE)), msp->registers + MSP_GCR);
- limit = 32;
- /* Flush Rx Fifo */
- while ((!
- (stm_msp_read(msp->registers + MSP_FLR) &
- RX_FIFO_EMPTY)) && limit--)
- dummy = stm_msp_read(msp->registers + MSP_DR);
- /* Disable Loopback and Receive channel */
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
- (~(RX_ENABLE | LOOPBACK_MASK))),
- msp->registers + MSP_GCR);
-
- msp_disable_transmit(msp);
- msp_disable_receive(msp);
-
- }
-
- /* disable sample rate and frame generators */
- if (flag == DISABLE_ALL) {
- msp->msp_state = MSP_STATE_IDLE;
- stm_msp_write((stm_msp_read(msp->registers + MSP_GCR) &
- (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
- msp->registers + MSP_GCR);
- memset(&msp->xfer_data, 0, sizeof(struct trans_data));
- if (msp->plat_exit)
- status = msp->plat_exit();
- if (status)
- printk(KERN_ERR "Error in msp_i2s_exit\n");
- if (msp->work_mode == MSP_POLLING_MODE
- && msp->msp_state == MSP_STATE_RUN) {
- up(&msp->lock);
- }
- msp->transfer = NULL;
- stm_msp_write(0, msp->registers + MSP_GCR);
- stm_msp_write(0, msp->registers + MSP_TCF);
- stm_msp_write(0, msp->registers + MSP_RCF);
- stm_msp_write(0, msp->registers + MSP_DMACR);
- stm_msp_write(0, msp->registers + MSP_SRG);
- stm_msp_write(0, msp->registers + MSP_MCR);
- stm_msp_write(0, msp->registers + MSP_RCM);
- stm_msp_write(0, msp->registers + MSP_RCV);
- stm_msp_write(0, msp->registers + MSP_TCE0);
- stm_msp_write(0, msp->registers + MSP_TCE1);
- stm_msp_write(0, msp->registers + MSP_TCE2);
- stm_msp_write(0, msp->registers + MSP_TCE3);
- stm_msp_write(0, msp->registers + MSP_RCE0);
- stm_msp_write(0, msp->registers + MSP_RCE1);
- stm_msp_write(0, msp->registers + MSP_RCE2);
- stm_msp_write(0, msp->registers + MSP_RCE3);
- }
- return status;
-}
-
-/**
- * stm_msp_close - Close the current i2s connection btw controller and client.
- * @i2s_cont: i2s controller structure
- * @flag: It indicates the functionality that needs to be disabled.
- * Context: process
- *
- * It will call msp_disable and reset the msp configuration. Disables Rx and Tx
- * channels, free gpio irqs and interrupt pins.
- * Called by i2s client driver to indicate the completion of use of i2s bus.
- * It is registered on i2s_close function.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-static int stm_msp_close(struct i2s_controller *i2s_cont, i2s_flag flag)
-{
- int status = 0;
- struct msp *msp = (struct msp *)i2s_cont->data;
- down(&msp->lock);
- if (msp->users == 0) {
- pr_err("MSP already closed!\n");
- status = -EINVAL;
- goto end;
- }
- dev_dbg(&i2s_cont->dev, "%s: users = %d, flag = %d.\n",
- __func__, msp->users, flag);
- /* We need to call it twice for DISABLE_ALL*/
- msp->users = flag == DISABLE_ALL ? 0 : msp->users - 1;
- if (msp->users)
- status = stm_msp_disable(msp, MSP_BOTH_T_R_MODE, flag);
- else {
- status = stm_msp_disable(msp, MSP_BOTH_T_R_MODE, DISABLE_ALL);
- clk_disable(msp->clk);
- if (msp->reg_enabled) {
- status = regulator_disable(msp_vape_supply);
- msp->reg_enabled = 0;
- }
- if (status != 0) {
- dev_err(&msp->i2s_cont->dev,
- "Failed to disable regulator\n");
- clk_enable(msp->clk);
- goto end;
- }
- }
- if (status)
- goto end;
- if (msp->users)
- msp->direction = flag == DISABLE_TRANSMIT ?
- MSP_RECEIVE_MODE : MSP_TRANSMIT_MODE;
-
- if (msp->vape_opp_constraint == 1) {
- prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "msp_i2s", 50);
- msp->vape_opp_constraint = 0;
- }
-end:
- up(&msp->lock);
- return status;
-
-}
-
-static int stm_msp_hw_status(struct i2s_controller *i2s_cont)
-{
- struct msp *msp = (struct msp *)i2s_cont->data;
-
- int status = stm_msp_read(msp->registers + MSP_RIS) & 0xee;
- if (status)
- stm_msp_write(status, msp->registers + MSP_ICR);
-
- return status;
-}
-
- /*Platform driver's functions */
-/**
- * msp_probe - Probe function
- * @pdev: platform device structure.
- * Context: process
- *
- * Probe function of msp platform driver.Handles allocation of memory and irq
- * resource. It creates i2s_controller and one i2s_device per msp controller.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-int msp_probe(struct platform_device *pdev)
-{
- int status = 0;
- struct device *dev;
- s16 platform_num = 0;
- struct resource *res = NULL;
- int irq;
- struct i2s_controller *i2s_cont;
- struct msp_i2s_platform_data *platform_data;
- struct msp *msp;
-
- if (!pdev)
- return -EPERM;
- msp = kzalloc(sizeof(*msp), GFP_KERNEL);
-
- platform_data = (struct msp_i2s_platform_data *)pdev->dev.platform_data;
-
- msp->id = platform_data->id;
- msp->plat_init = platform_data->msp_i2s_init;
- msp->plat_exit = platform_data->msp_i2s_exit;
-
- msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
- msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
-
- dev = &pdev->dev;
- platform_num = msp->id - 1;
-
- sema_init(&msp->lock, 1);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "probe - MEM resources not defined\n");
- status = -EINVAL;
- goto free_msp;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- status = -EINVAL;
- goto free_msp;
- }
- msp->irq = irq;
-
- msp->registers = ioremap(res->start, (res->end - res->start + 1));
- if (msp->registers == NULL) {
- status = -EINVAL;
- goto free_msp;
- }
-
- msp_vape_supply = regulator_get(NULL, "v-ape");
- if (IS_ERR(msp_vape_supply)) {
- status = PTR_ERR(msp_vape_supply);
- printk(KERN_WARNING "msp i2s : failed to get v-ape supply\n");
- goto free_irq;
- }
- prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, "msp_i2s", 50);
- msp->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(msp->clk)) {
- status = PTR_ERR(msp->clk);
- goto free_irq;
- }
-
- init_timer(&msp->notify_timer);
- msp->notify_timer.expires = jiffies + msecs_to_jiffies(1000);
- msp->notify_timer.function = func_notify_timer;
- msp->notify_timer.data = (unsigned long)msp;
-
- msp->rx_pipeid = NULL;
- msp->tx_pipeid = NULL;
- msp->read = NULL;
- msp->write = NULL;
- msp->transfer = NULL;
- msp->msp_state = MSP_STATE_IDLE;
- msp->loopback_enable = 0;
-
- dev_set_drvdata(&pdev->dev, msp);
- /* I2S Controller is allocated and added in I2S controller class. */
- i2s_cont =
- (struct i2s_controller *)kzalloc(sizeof(*i2s_cont), GFP_KERNEL);
- if (!i2s_cont) {
- dev_err(&pdev->dev, "i2s controller alloc failed \n");
- status = -EINVAL;
- goto del_timer;
- }
- i2s_cont->dev.parent = dev;
- i2s_cont->algo = &i2s_algo;
- i2s_cont->data = (void *)msp;
- i2s_cont->id = platform_num;
- snprintf(i2s_cont->name, sizeof(i2s_cont->name),
- "MSP_I2S.%04x", platform_num);
-
- status = i2s_add_controller(i2s_cont);
- if (status) {
- dev_err(&pdev->dev, "i2s add controller failed (%d)\n", status);
- goto free_cont;
- }
- msp->i2s_cont = i2s_cont;
- return status;
-free_cont:
- kfree(msp->i2s_cont);
-del_timer:
- del_timer_sync(&msp->notify_timer);
- clk_put(msp->clk);
-free_irq:
- iounmap(msp->registers);
-free_msp:
- kfree(msp);
- return status;
-}
-
-/**
- * msp_remove - remove function
- * @pdev: platform device structure.
- * Context: process
- *
- * remove function of msp platform driver.Handles dellocation of memory and irq
- * resource. It deletes i2s_controller and one i2s_device per msp controller
- * created in msp_probe.
- *
- * Returns error(-1) in case of failure or success(0).
- */
-static int msp_remove(struct platform_device *pdev)
-{
- struct msp *msp =
- (struct msp *)dev_get_drvdata(&pdev->dev);
- int status = 0;
- i2s_del_controller(msp->i2s_cont);
- del_timer_sync(&msp->notify_timer);
- clk_put(msp->clk);
- iounmap(msp->registers);
- prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "msp_i2s");
- regulator_put(msp_vape_supply);
- kfree(msp);
- return status;
-}
-#ifdef CONFIG_PM
-/**
- * msp_suspend - MSP suspend function registered with PM framework.
- * @pdev: Reference to platform device structure of the device
- * @state: power mgmt state.
- *
- * This function is invoked when the system is going into sleep, called
- * by the power management framework of the linux kernel.
- * Nothing is required as controller is configured with every transfer.
- * It is assumed that no active tranfer is in progress at this time.
- * Client driver should make sure of this.
- *
- */
-
-int msp_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct msp *msp =
- (struct msp *)dev_get_drvdata(&pdev->dev);
-
- down(&msp->lock);
- if (msp->users > 0) {
- up(&msp->lock);
- return -EBUSY;
- }
- up(&msp->lock);
-
- return 0;
-}
-/**
- * msp_resume - MSP Resume function registered with PM framework.
- * @pdev: Reference to platform device structure of the device
- *
- * This function is invoked when the system is coming out of sleep, called
- * by the power management framework of the linux kernel.
- * Nothing is required.
- *
- */
-
-int msp_resume(struct platform_device *pdev)
-{
- return 0;
-}
-#else
-#define msp_suspend NULL
-#define msp_resume NULL
-#endif
-
-static struct platform_driver msp_i2s_driver = {
- .probe = msp_probe,
- .remove = msp_remove,
- .suspend = msp_suspend,
- .resume = msp_resume,
- .driver = {
- .owner = THIS_MODULE,
- .name = "MSP_I2S",
- },
-};
-
-static int __init stm_msp_mod_init(void)
-{
- return platform_driver_register(&msp_i2s_driver);
-}
-
-static void __exit stm_msp_exit(void)
-{
- platform_driver_unregister(&msp_i2s_driver);
- return;
-}
-
-module_init(stm_msp_mod_init);
-module_exit(stm_msp_exit);
-
-MODULE_AUTHOR("Sandeep Kaushik");
-MODULE_DESCRIPTION("STM MSP driver");
-MODULE_LICENSE("GPL");
diff --git a/include/linux/i2s/i2s.h b/include/linux/i2s/i2s.h
deleted file mode 100644
index 79df549d6bd..00000000000
--- a/include/linux/i2s/i2s.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* copyright STMicroelectronics, 2007. */
-/* */
-/* 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.1 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 FITNES */
-/* 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, see <http://www.gnu.org/licenses/>. */
-/*----------------------------------------------------------------------------*/
-
-#ifndef __LINUX_I2S_H
-#define __LINUX_I2S_H
-
-/*
- * INTERFACES between I2S controller-side drivers and I2S infrastructure.
- */
-extern struct bus_type i2s_bus_type;
-#define I2S_NAME_SIZE 48
-/**
- * struct i2s_device - Controller side proxy for an I2S slave device
- * @dev: Driver model representation of the device.
- * @controller: I2S controller used with the device.
- * @chip_select: Chipselect, distinguishing chips handled by @controller.
- * @modalias: Name of the driver to use with this device, or an alias
- * for that name. This appears in the sysfs "modalias" attribute
- * for driver coldplugging, and in uevents used for hotplugging
- *
- * A @i2s_device is used to interchange data between an I2S slave
- *
- * In @dev, the platform_data is used to hold information about this
- * device that's meaningful to the device's protocol driver, but not
- * to its controller.
- */
-struct i2s_device {
- struct device dev;
- struct i2s_controller *controller;
- u8 chip_select;
- char modalias[32];
-};
-struct i2s_board_info {
- /* the device name and module name are coupled, like platform_bus;
- * "modalias" is normally the driver name.
- *
- * platform_data goes to i2s_device.dev.platform_data,
- */
- char modalias[32];
- const void *platform_data;
- u16 id;
- u16 chip_select;
-};
-
-#ifdef CONFIG_STM_I2S
-extern int
-i2s_register_board_info(struct i2s_board_info const *info, unsigned n);
-#else
-/* board init code may ignore whether I2S is configured or not */
-static inline int
-i2s_register_board_info(struct i2s_board_info const *info, unsigned n)
-{
- return 0;
-}
-#endif
-
-static inline struct i2s_device *to_i2s_device(struct device *dev)
-{
- return dev ? container_of(dev, struct i2s_device, dev) : NULL;
-}
-
-static inline struct i2s_device *i2s_dev_get(struct i2s_device *i2s)
-{
- return (i2s && get_device(&i2s->dev)) ? i2s : NULL;
-}
-
-static inline void i2s_dev_put(struct i2s_device *i2s)
-{
- if (i2s)
- put_device(&i2s->dev);
-}
-
-static inline void i2s_set_drvdata(struct i2s_device *i2s, void *data)
-{
- dev_set_drvdata(&i2s->dev, data);
-}
-
-static inline void *i2s_get_drvdata(struct i2s_device *i2s)
-{
- return dev_get_drvdata(&i2s->dev);
-}
-
-struct i2s_device_id {
- char name[I2S_NAME_SIZE];
- /*currently not used may be used in future */
- u32 device_id;
- u32 vendor_id;
-};
-
-/**
- * struct i2s_driver - Host side "protocol" driver
- */
-struct i2s_driver {
- int (*probe) (struct i2s_device *i2s);
- int (*remove) (struct i2s_device *i2s);
- void (*shutdown) (struct i2s_device *i2s);
- int (*suspend) (struct i2s_device *i2s, pm_message_t mesg);
- int (*resume) (struct i2s_device *i2s);
- struct device_driver driver;
- const struct i2s_device_id *id_table;
-
-};
-
-static inline struct i2s_driver *to_i2s_driver(struct device_driver *drv)
-{
- return drv ? container_of(drv, struct i2s_driver, driver) : NULL;
-}
-
-extern int i2s_register_driver(struct i2s_driver *sdrv);
-
-/**
- * i2s_unregister_driver - reverse effect of i2s_register_driver
- * @sdrv: the driver to unregister
- * Context: can sleep
- */
-static inline void i2s_unregister_driver(struct i2s_driver *sdrv)
-{
- if (sdrv)
- driver_unregister(&sdrv->driver);
-}
-
-/**I2S controller parameters*/
-
-enum i2s_direction_t {
- I2S_DIRECTION_TX = 0,
- I2S_DIRECTION_RX = 1,
- I2S_DIRECTION_BOTH = 2
-};
-
-enum i2s_transfer_mode_t {
- I2S_TRANSFER_MODE_SINGLE_DMA = 0,
- I2S_TRANSFER_MODE_CYCLIC_DMA = 1,
- I2S_TRANSFER_MODE_INF_LOOPBACK = 2,
- I2S_TRANSFER_MODE_NON_DMA = 4,
-};
-
-struct i2s_message {
- enum i2s_transfer_mode_t i2s_transfer_mode;
- enum i2s_direction_t i2s_direction;
- void *txdata;
- void *rxdata;
- size_t txbytes;
- size_t rxbytes;
- int dma_flag;
- int tx_offset;
- int rx_offset;
- /* cyclic dma */
- bool cyclic_dma;
- dma_addr_t buf_addr;
- size_t buf_len;
- size_t period_len;
-};
-
-typedef enum {
- DISABLE_ALL = 0,
- DISABLE_TRANSMIT = 1,
- DISABLE_RECEIVE = 2,
-} i2s_flag;
-
-struct i2s_algorithm {
- int (*cont_setup) (struct i2s_controller *i2s_cont, void *config);
- int (*cont_transfer) (struct i2s_controller *i2s_cont,
- struct i2s_message *message);
- int (*cont_cleanup) (struct i2s_controller *i2s_cont, i2s_flag flag);
- int (*cont_hw_status) (struct i2s_controller *i2s_cont);
- dma_addr_t (*cont_get_pointer) (struct i2s_controller *i2s_cont,
- enum i2s_direction_t i2s_direction);
-};
-
-struct i2s_controller {
- struct module *owner;
- unsigned int id;
- unsigned int class;
- const struct i2s_algorithm *algo; /* the algorithm to access the bus */
- void *data;
- struct mutex bus_lock;
- struct device dev; /* the controller device */
- char name[48];
-};
-#define to_i2s_controller(d) container_of(d, struct i2s_controller, dev)
-
-static inline void *i2s_get_contdata(struct i2s_controller *dev)
-{
- return dev_get_drvdata(&dev->dev);
-}
-
-static inline void i2s_set_contdata(struct i2s_controller *dev, void *data)
-{
- dev_set_drvdata(&dev->dev, data);
-}
-
-extern int i2s_add_controller(struct i2s_controller *controller);
-extern int i2s_del_controller(struct i2s_controller *controller);
-extern int i2s_setup(struct i2s_controller *i2s_cont, void *config);
-extern int i2s_transfer(struct i2s_controller *i2s_cont,
- struct i2s_message *message);
-extern int i2s_cleanup(struct i2s_controller *i2s_cont, i2s_flag flag);
-extern int i2s_hw_status(struct i2s_controller *i2s_cont);
-extern dma_addr_t i2s_get_pointer(struct i2s_controller *i2s_cont,
- enum i2s_direction_t i2s_direction);
-
-extern struct i2s_device *i2s_get_device_from_boardinfo(int chip_select); /* used in MSP LTP tests */
-extern struct i2s_device *i2s_alloc_device(struct device *dev);
-
-extern int i2s_add_device(struct i2s_device *i2s);
-
-static inline void i2s_unregister_device(struct i2s_device *i2s)
-{
- if (i2s)
- device_unregister(&i2s->dev);
-}
-
-#endif /* __LINUX_I2S_H */
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
index 0078beb72ec..1a25fb6a0d6 100644
--- a/sound/soc/ux500/Kconfig
+++ b/sound/soc/ux500/Kconfig
@@ -4,7 +4,7 @@
menuconfig SND_SOC_UX500
bool "SoC Audio support for Ux500 platform"
- depends on SND_SOC && STM_I2S && STM_MSP_I2S
+ depends on SND_SOC
default n
help
Say Y if you want to add support for the Ux500 platform.
diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile
index 255c0ecefdb..262e44a2812 100644
--- a/sound/soc/ux500/Makefile
+++ b/sound/soc/ux500/Makefile
@@ -1,47 +1,46 @@
# Ux500 Platform Support
ifdef CONFIG_SND_SOC_UX500_DEBUG
+CFLAGS_u8500.o := -DDEBUG
CFLAGS_ux500_pcm.o := -DDEBUG
CFLAGS_ux500_msp_dai.o := -DDEBUG
CFLAGS_ux500_ab3550.o := -DDEBUG
CFLAGS_ux500_ab8500.o := -DDEBUG
CFLAGS_ux500_av8100.o := -DDEBUG
CFLAGS_ux500_cg29xx.o := -DDEBUG
+CFLAGS_ux500_msp_i2s.o := -DDEBUG
endif
-ifdef CONFIG_SND_SOC_UX500_AB3550
-snd-soc-ux500-ab3550-objs := ux500_ab3550.o
-obj-$(CONFIG_SND_SOC_UX500_AB3550) += ux500_ab3550.o
-endif
-
-ifdef CONFIG_SND_SOC_UX500_AB5500
-snd-soc-ux500-ab5500-objs := ux500_ab5500.o
-obj-$(CONFIG_SND_SOC_UX500_AB5500) += ux500_ab5500.o
+ifdef CONFIG_UX500_SOC_DBX500
+snd-soc-ux500-platform-objs := ux500_pcm.o ux500_msp_dai.o ux500_msp_i2s.o
+obj-y += snd-soc-ux500-platform.o
endif
ifdef CONFIG_SND_SOC_UX500_AB8500
-snd-soc-ux500-ab8500-objs := ux500_ab8500.o
-obj-$(CONFIG_SND_SOC_UX500_AB8500) += ux500_ab8500.o
+snd-soc-ux500-machine-objs += ux500_ab8500.o
endif
ifdef CONFIG_SND_SOC_UX500_AV8100
-snd-soc-ux500-av8100-objs := ux500_av8100.o
-obj-$(CONFIG_SND_SOC_UX500_AV8100) += ux500_av8100.o
+snd-soc-ux500-machine-objs += ux500_av8100.o
endif
ifdef CONFIG_SND_SOC_UX500_CG29XX
-snd-soc-ux500-cg29xx-objs := ux500_cg29xx.o
-obj-$(CONFIG_SND_SOC_UX500_CG29XX) += ux500_cg29xx.o
+snd-soc-ux500-machine-objs += ux500_cg29xx.o
+endif
+
+ifdef CONFIG_SND_SOC_UX500_AB5500
+snd-soc-ux500-machine-objs += ux500_ab5500.o
endif
-snd-soc-ux500-objs := ux500_pcm.o ux500_msp_dai.o
+obj-y += snd-soc-ux500-machine.o
ifdef CONFIG_UX500_SOC_DB8500
-snd-soc-ux500-objs += u8500.o
+snd-soc-u8500-objs := u8500.o
+obj-y += snd-soc-u8500.o
endif
ifdef CONFIG_UX500_SOC_DB5500
-snd-soc-ux500-objs += u5500.o
+snd-soc-u5500-objs := u5500.o
+obj-y += snd-soc-u5500.o
endif
-obj-$(CONFIG_UX500_SOC_DBX500) += snd-soc-ux500.o
diff --git a/sound/soc/ux500/u5500.c b/sound/soc/ux500/u5500.c
index 1d17830c1c7..6787daa9de5 100755
--- a/sound/soc/ux500/u5500.c
+++ b/sound/soc/ux500/u5500.c
@@ -66,7 +66,7 @@ struct snd_soc_dai_link u5500_dai_links[] = {
{
.name = "ab5500_0",
.stream_name = "ab5500_0",
- .cpu_dai_name = "i2s.0",
+ .cpu_dai_name = "ux500-msp-i2s.0",
.codec_dai_name = "ab5500-codec-dai.0",
.platform_name = "ux500-pcm.0",
.codec_name = "ab5500-codec.0",
@@ -83,7 +83,7 @@ struct snd_soc_dai_link u5500_dai_links[] = {
{
.name = "cg29xx_0",
.stream_name = "cg29xx_0",
- .cpu_dai_name = "i2s.1",
+ .cpu_dai_name = "ux500-msp-i2s.1",
.codec_dai_name = "cg29xx-codec-dai.0",
.platform_name = "ux500-pcm.0",
.codec_name = "cg29xx-codec.0",
@@ -93,7 +93,7 @@ struct snd_soc_dai_link u5500_dai_links[] = {
{
.name = "cg29xx_1",
.stream_name = "cg29xx_1",
- .cpu_dai_name = "i2s.0",
+ .cpu_dai_name = "ux500-msp-i2s.0",
.codec_dai_name = "cg29xx-codec-dai.1",
.platform_name = "ux500-pcm.0",
.codec_name = "cg29xx-codec.0",
@@ -104,7 +104,7 @@ struct snd_soc_dai_link u5500_dai_links[] = {
{
.name = "ab5500_1",
.stream_name = "ab5500_1",
- .cpu_dai_name = "i2s.1",
+ .cpu_dai_name = "ux500-msp-i2s.1",
.codec_dai_name = "ab5500-codec-dai.1",
.platform_name = "ux500-pcm.0",
.codec_name = "ab5500-codec.0",
@@ -121,7 +121,7 @@ struct snd_soc_dai_link u5500_dai_links[] = {
{
.name = "hdmi",
.stream_name = "hdmi",
- .cpu_dai_name = "i2s.2",
+ .cpu_dai_name = "ux500-msp-i2s.2",
.codec_dai_name = "av8100-codec-dai",
.platform_name = "ux500-pcm.0",
.codec_name = "av8100-codec.0",
diff --git a/sound/soc/ux500/u8500.c b/sound/soc/ux500/u8500.c
index c27409f1009..516008fcc6a 100644
--- a/sound/soc/ux500/u8500.c
+++ b/sound/soc/ux500/u8500.c
@@ -77,7 +77,7 @@ struct snd_soc_dai_link u8500_dai_links[] = {
{
.name = "hdmi",
.stream_name = "hdmi",
- .cpu_dai_name = "i2s.2",
+ .cpu_dai_name = "ux500-msp-i2s.2",
.codec_dai_name = "av8100-codec-dai",
.platform_name = "ux500-pcm.0",
.codec_name = "av8100-codec.0",
@@ -89,7 +89,7 @@ struct snd_soc_dai_link u8500_dai_links[] = {
{
.name = "ab3550_0",
.stream_name = "ab3550_0",
- .cpu_dai_name = "i2s.0",
+ .cpu_dai_name = "ux500-msp-i2s.0",
.codec_dai_name = "ab3550-codec-dai.0",
.platform_name = "ux500-pcm.0",
.codec_name = "ab3550-codec.11",
@@ -99,7 +99,7 @@ struct snd_soc_dai_link u8500_dai_links[] = {
{
.name = "ab3550_1",
.stream_name = "ab3550_1",
- .cpu_dai_name = "i2s.1",
+ .cpu_dai_name = "ux500-msp-i2s.1",
.codec_dai_name = "ab3550-codec-dai.1",
.platform_name = "ux500-pcm.0",
.codec_name = "ab3550-codec.11",
@@ -111,7 +111,7 @@ struct snd_soc_dai_link u8500_dai_links[] = {
{
.name = "ab8500_0",
.stream_name = "ab8500_0",
- .cpu_dai_name = "i2s.1",
+ .cpu_dai_name = "ux500-msp-i2s.1",
.codec_dai_name = "ab8500-codec-dai.0",
.platform_name = "ux500-pcm.0",
.codec_name = "ab8500-codec.0",
@@ -121,7 +121,7 @@ struct snd_soc_dai_link u8500_dai_links[] = {
{
.name = "ab8500_1",
.stream_name = "ab8500_1",
- .cpu_dai_name = "i2s.3",
+ .cpu_dai_name = "ux500-msp-i2s.3",
.codec_dai_name = "ab8500-codec-dai.1",
.platform_name = "ux500-pcm.0",
.codec_name = "ab8500-codec.0",
@@ -133,7 +133,7 @@ struct snd_soc_dai_link u8500_dai_links[] = {
{
.name = "cg29xx_0",
.stream_name = "cg29xx_0",
- .cpu_dai_name = "i2s.0",
+ .cpu_dai_name = "ux500-msp-i2s.0",
.codec_dai_name = "cg29xx-codec-dai.1",
.platform_name = "ux500-pcm.0",
.codec_name = "cg29xx-codec.0",
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 6cdc96734ed..2af5bf14193 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) ST-Ericsson SA 2010
+ * Copyright (C) ST-Ericsson SA 2011
*
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* Roger Nilsson <roger.xr.nilsson@stericsson.com>
@@ -14,21 +14,22 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/dma.h>
#include <linux/bitops.h>
+#include <linux/platform_device.h>
+
#include <mach/hardware.h>
#include <mach/msp.h>
-#include <linux/i2s/i2s.h>
-#include <asm/mach-types.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
+
+#include "ux500_msp_i2s.h"
#include "ux500_msp_dai.h"
#include "ux500_pcm.h"
static struct ux500_platform_drvdata platform_drvdata[UX500_NBR_OF_DAI] = {
{
- .i2s = NULL,
+ .msp_i2s_drvdata = NULL,
.fmt = 0,
.slots = 1,
.tx_mask = 0x01,
@@ -41,7 +42,7 @@ static struct ux500_platform_drvdata platform_drvdata[UX500_NBR_OF_DAI] = {
.master_clk = UX500_MSP_INTERNAL_CLOCK_FREQ,
},
{
- .i2s = NULL,
+ .msp_i2s_drvdata = NULL,
.fmt = 0,
.slots = 1,
.tx_mask = 0x01,
@@ -54,7 +55,7 @@ static struct ux500_platform_drvdata platform_drvdata[UX500_NBR_OF_DAI] = {
.master_clk = UX500_MSP1_INTERNAL_CLOCK_FREQ,
},
{
- .i2s = NULL,
+ .msp_i2s_drvdata = NULL,
.fmt = 0,
.slots = 1,
.tx_mask = 0x01,
@@ -67,7 +68,7 @@ static struct ux500_platform_drvdata platform_drvdata[UX500_NBR_OF_DAI] = {
.master_clk = UX500_MSP_INTERNAL_CLOCK_FREQ,
},
{
- .i2s = NULL,
+ .msp_i2s_drvdata = NULL,
.fmt = 0,
.slots = 1,
.tx_mask = 0x01,
@@ -84,14 +85,14 @@ static struct ux500_platform_drvdata platform_drvdata[UX500_NBR_OF_DAI] = {
bool ux500_msp_dai_i2s_get_underrun_status(int dai_idx)
{
struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx];
- int status = i2s_hw_status(drvdata->i2s->controller);
+ int status = ux500_msp_i2s_hw_status(drvdata->msp_i2s_drvdata);
return (bool)(status & TRANSMIT_UNDERRUN_ERR_INT);
}
dma_addr_t ux500_msp_dai_i2s_get_pointer(int dai_idx, int stream_id)
{
struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx];
- return i2s_get_pointer(drvdata->i2s->controller,
+ return ux500_msp_i2s_get_pointer(drvdata->msp_i2s_drvdata,
(stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
I2S_DIRECTION_TX :
I2S_DIRECTION_RX);
@@ -105,7 +106,6 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr,
{
struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai_idx];
struct i2s_message message;
- struct i2s_device *i2s_dev;
int ret = 0;
bool playback_req_valid =
(drvdata->playback_active &&
@@ -128,9 +128,6 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr,
return ret;
}
- i2s_dev = drvdata->i2s;
-
- message.i2s_transfer_mode = I2S_TRANSFER_MODE_CYCLIC_DMA;
message.i2s_direction = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
I2S_DIRECTION_TX :
I2S_DIRECTION_RX;
@@ -138,7 +135,7 @@ int ux500_msp_dai_i2s_configure_sg(dma_addr_t dma_addr,
message.buf_len = period_cnt * period_len;
message.period_len = period_len;
- ret = i2s_transfer(i2s_dev->controller, &message);
+ ret = ux500_msp_i2s_transfer(drvdata->msp_i2s_drvdata, &message);
if (ret < 0) {
pr_err("%s: Error: i2s_transfer failed. MSP index: %d\n",
__func__,
@@ -197,7 +194,7 @@ static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
else
drvdata->capture_active = false;
- if (i2s_cleanup(drvdata->i2s->controller,
+ if (ux500_msp_i2s_close(drvdata->msp_i2s_drvdata,
mode_playback ? DISABLE_TRANSMIT : DISABLE_RECEIVE)) {
pr_err("%s: Error: MSP %d (%s): Unable to close i2s.\n",
__func__,
@@ -468,7 +465,7 @@ static void ux500_msp_dai_compile_msp_config(struct snd_pcm_substream *substream
msp_config->work_mode = MSP_DMA_MODE;
msp_config->frame_freq = rate;
- printk(KERN_INFO "%s: input_clock_freq = %u, frame_freq = %u.\n",
+ pr_debug("%s: input_clock_freq = %u, frame_freq = %u.\n",
__func__, msp_config->input_clock_freq, msp_config->frame_freq);
/* To avoid division by zero in I2S-driver (i2s_setup) */
prot_desc->total_clocks_for_one_frame = 1;
@@ -548,9 +545,9 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
runtime->rate,
&msp_config);
- ret = i2s_setup(drvdata->i2s->controller, &msp_config);
+ ret = ux500_msp_i2s_open(drvdata->msp_i2s_drvdata, &msp_config);
if (ret < 0) {
- pr_err("%s: Error: i2s_setup failed (ret = %d)!\n", __func__, ret);
+ pr_err("%s: Error: msp_setup failed (ret = %d)!\n", __func__, ret);
goto cleanup;
}
@@ -764,11 +761,11 @@ static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
int ret = 0;
struct ux500_platform_drvdata *drvdata = &platform_drvdata[dai->id];
- pr_debug("%s: MSP %d (%s): Enter (chip_select = %d, cmd = %d).\n",
+ pr_debug("%s: MSP %d (%s): Enter (msp->id = %d, cmd = %d).\n",
__func__,
dai->id,
stream_str(substream),
- (int)drvdata->i2s->chip_select,
+ (int)drvdata->msp_i2s_drvdata->id,
cmd);
switch (cmd) {
@@ -796,7 +793,7 @@ static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
{
- .name = "ux500-msp.0",
+ .name = "ux500-msp-i2s.0",
.id = 0,
.suspend = NULL,
.resume = NULL,
@@ -826,7 +823,7 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
},
},
{
- .name = "ux500-msp.1",
+ .name = "ux500-msp-i2s.1",
.id = 1,
.suspend = NULL,
.resume = NULL,
@@ -856,7 +853,7 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
},
},
{
- .name = "ux500-msp.2",
+ .name = "ux500-msp-i2s.2",
.id = 2,
.suspend = NULL,
.resume = NULL,
@@ -886,7 +883,7 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
},
},
{
- .name = "ux500-msp.3",
+ .name = "ux500-msp-i2s.3",
.id = 3,
.suspend = NULL,
.resume = NULL,
@@ -918,84 +915,90 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
};
EXPORT_SYMBOL(ux500_msp_dai_drv);
-static int ux500_msp_drv_probe(struct i2s_device *i2s_dev)
+static int ux500_msp_drv_probe(struct platform_device *pdev)
{
- int ret = 0;
+ struct ux500_msp_i2s_drvdata *msp_i2s_drvdata;
struct ux500_platform_drvdata *drvdata;
- int msp_idx = i2s_dev->chip_select;
+ struct msp_i2s_platform_data *platform_data;
+ int id;
+ int ret = 0;
- pr_info("%s: Enter (idx: %d, dev-name: %s, drv-name: %s).\n",
- __func__,
- msp_idx,
- dev_name(&i2s_dev->dev),
- i2s_dev->dev.driver->name);
+ pr_err("%s: Enter (pdev->name = %s).\n", __func__, pdev->name);
- drvdata = &platform_drvdata[msp_idx];
- drvdata->i2s = i2s_dev;
+ platform_data = (struct msp_i2s_platform_data *)pdev->dev.platform_data;
+ msp_i2s_drvdata = ux500_msp_i2s_init(pdev, platform_data);
+ if (!msp_i2s_drvdata) {
+ pr_err("%s: ERROR: ux500_msp_i2s_init failed!", __func__);
+ return -EINVAL;
+ }
- try_module_get(i2s_dev->controller->dev.parent->driver->owner);
- i2s_set_drvdata(i2s_dev, drvdata);
+ id = msp_i2s_drvdata->id;
+ drvdata = &platform_drvdata[id];
+ drvdata->msp_i2s_drvdata = msp_i2s_drvdata;
- pr_debug("%s: Register MSP %d.\n", __func__, msp_idx);
- ret = snd_soc_register_dai(&i2s_dev->dev, &ux500_msp_dai_drv[msp_idx]);
+ pr_info("%s: Registering ux500-msp-dai SoC CPU-DAI.\n", __func__);
+ ret = snd_soc_register_dai(&pdev->dev, &ux500_msp_dai_drv[id]);
if (ret < 0) {
- pr_err("Error: %s: Failed to register MSP %d.\n", __func__, msp_idx);
+ pr_err("Error: %s: Failed to register MSP %d.\n", __func__, id);
return ret;
}
return ret;
}
-static int ux500_msp_drv_remove(struct i2s_device *i2s_dev)
+static int ux500_msp_drv_remove(struct platform_device *pdev)
{
- struct ux500_platform_drvdata *drvdata = i2s_get_drvdata(i2s_dev);
- int msp_idx = i2s_dev->chip_select;
+ struct ux500_msp_i2s_drvdata *msp_i2s_drvdata = dev_get_drvdata(&pdev->dev);
+ struct ux500_platform_drvdata *drvdata = &platform_drvdata[msp_i2s_drvdata->id];
- pr_info("%s: Enter (idx: %d, dev-name: %s, drv-name: %s).\n",
- __func__,
- msp_idx,
- dev_name(&i2s_dev->dev),
- i2s_dev->dev.driver->name);
+ pr_info("%s: Unregister ux500-msp-dai ASoC CPU-DAI.\n", __func__);
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
- drvdata->i2s = NULL;
- i2s_set_drvdata(i2s_dev, NULL);
+ ux500_msp_i2s_exit(msp_i2s_drvdata);
+ drvdata->msp_i2s_drvdata = NULL;
- pr_debug("%s: Calling module_put.\n", __func__);
- module_put(i2s_dev->controller->dev.parent->driver->owner);
+ return 0;
+}
- pr_debug("%s: Unregister ux500-pcm SoC platform driver.\n", __func__);
- snd_soc_unregister_dais(&i2s_dev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+int ux500_msp_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ux500_msp_i2s_drvdata *msp_i2s_drvdata = dev_get_drvdata(&pdev->dev);
- return 0;
+ pr_debug("%s: Enter (pdev->name = %s).\n", __func__, pdev->name);
+
+ return ux500_msp_i2s_suspend(msp_i2s_drvdata);
}
-static const struct i2s_device_id dev_id_table[] = {
- { "i2s_device.0", 0, 0 },
- { "i2s_device.1", 1, 0 },
- { "i2s_device.2", 2, 0 },
- { "i2s_device.3", 3, 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2s, dev_id_table);
+int ux500_msp_drv_resume(struct platform_device *pdev)
+{
+ struct ux500_msp_i2s_drvdata *msp_i2s_drvdata = dev_get_drvdata(&pdev->dev);
+
+ pr_debug("%s: Enter (pdev->name = %s).\n", __func__, pdev->name);
+
+ return ux500_msp_i2s_resume(msp_i2s_drvdata);
+}
-static struct i2s_driver i2sdrv_i2s = {
+static struct platform_driver msp_i2s_driver = {
.driver = {
- .name = "i2s",
+ .name = "ux500-msp-i2s",
.owner = THIS_MODULE,
},
.probe = ux500_msp_drv_probe,
- .remove = __devexit_p(ux500_msp_drv_remove),
- .id_table = dev_id_table,
+ .remove = ux500_msp_drv_remove,
+ .suspend = ux500_msp_drv_suspend,
+ .resume = ux500_msp_drv_resume,
};
static int __init ux500_msp_init(void)
{
- return i2s_register_driver(&i2sdrv_i2s);
+ pr_info("%s: Register ux500-msp-dai platform driver.\n", __func__);
+ return platform_driver_register(&msp_i2s_driver);
}
static void __exit ux500_msp_exit(void)
{
- i2s_unregister_driver(&i2sdrv_i2s);
+ pr_info("%s: Unregister ux500-msp-dai platform driver.\n", __func__);
+ platform_driver_unregister(&msp_i2s_driver);
}
module_init(ux500_msp_init);
diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h
index cff6749760d..c44894526f2 100755..100644
--- a/sound/soc/ux500/ux500_msp_dai.h
+++ b/sound/soc/ux500/ux500_msp_dai.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) ST-Ericsson SA 2010
+ * Copyright (C) ST-Ericsson SA 2011
*
* Author: Ola Lilja <ola.o.lilja@stericsson.com>,
* Roger Nilsson <roger.xr.nilsson@stericsson.com>
@@ -17,7 +17,6 @@
#include <linux/types.h>
#include <linux/spinlock.h>
-#include <linux/i2s/i2s.h>
#include <mach/msp.h>
#define UX500_NBR_OF_DAI 4
@@ -54,7 +53,7 @@ enum ux500_msp_clock_id {
};
struct ux500_platform_drvdata {
- struct i2s_device *i2s;
+ struct ux500_msp_i2s_drvdata *msp_i2s_drvdata;
unsigned int fmt;
unsigned int tx_mask;
unsigned int rx_mask;
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
new file mode 100644
index 00000000000..1fa7a947fe1
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -0,0 +1,1013 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ * Sandeep Kaushik <sandeep.kaushik@st.com>
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include <mach/hardware.h>
+#include <mach/msp.h>
+
+#include "ux500_msp_i2s.h"
+
+ /* Protocol desciptors */
+static const struct msp_protocol_desc prot_descs[] = {
+ I2S_PROTOCOL_DESC,
+ PCM_PROTOCOL_DESC,
+ PCM_COMPAND_PROTOCOL_DESC,
+ AC97_PROTOCOL_DESC,
+ SPI_MASTER_PROTOCOL_DESC,
+ SPI_SLAVE_PROTOCOL_DESC,
+};
+
+static void ux500_msp_i2s_set_prot_desc_tx(struct msp *msp,
+ struct msp_protocol_desc *protocol_desc,
+ enum msp_data_size data_size)
+{
+ u32 temp_reg = 0;
+
+ temp_reg |= MSP_P2_ENABLE_BIT(protocol_desc->tx_phase_mode);
+ temp_reg |= MSP_P2_START_MODE_BIT(protocol_desc->tx_phase2_start_mode);
+ temp_reg |= MSP_P1_FRAME_LEN_BITS(protocol_desc->tx_frame_length_1);
+ temp_reg |= MSP_P2_FRAME_LEN_BITS(protocol_desc->tx_frame_length_2);
+ if (msp->def_elem_len) {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(protocol_desc->tx_element_length_1);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(protocol_desc->tx_element_length_2);
+ if (protocol_desc->tx_element_length_1 ==
+ protocol_desc->tx_element_length_2) {
+ msp->actual_data_size = protocol_desc->tx_element_length_1;
+ } else {
+ msp->actual_data_size = data_size;
+ }
+ } else {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+ msp->actual_data_size = data_size;
+ }
+ temp_reg |= MSP_DATA_DELAY_BITS(protocol_desc->tx_data_delay);
+ temp_reg |= MSP_SET_ENDIANNES_BIT(protocol_desc->tx_bit_transfer_format);
+ temp_reg |= MSP_FRAME_SYNC_POL(protocol_desc->tx_frame_sync_pol);
+ temp_reg |= MSP_DATA_WORD_SWAP(protocol_desc->tx_half_word_swap);
+ temp_reg |= MSP_SET_COMPANDING_MODE(protocol_desc->compression_mode);
+ temp_reg |= MSP_SET_FRAME_SYNC_IGNORE(protocol_desc->frame_sync_ignore);
+
+ writel(temp_reg, msp->registers + MSP_TCF);
+}
+
+static void ux500_msp_i2s_set_prot_desc_rx(struct msp *msp,
+ struct msp_protocol_desc *protocol_desc,
+ enum msp_data_size data_size)
+{
+ u32 temp_reg = 0;
+
+ temp_reg |= MSP_P2_ENABLE_BIT(protocol_desc->rx_phase_mode);
+ temp_reg |= MSP_P2_START_MODE_BIT(protocol_desc->rx_phase2_start_mode);
+ temp_reg |= MSP_P1_FRAME_LEN_BITS(protocol_desc->rx_frame_length_1);
+ temp_reg |= MSP_P2_FRAME_LEN_BITS(protocol_desc->rx_frame_length_2);
+ if (msp->def_elem_len) {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(protocol_desc->rx_element_length_1);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(protocol_desc->rx_element_length_2);
+ if (protocol_desc->rx_element_length_1 ==
+ protocol_desc->rx_element_length_2) {
+ msp->actual_data_size = protocol_desc->rx_element_length_1;
+ } else {
+ msp->actual_data_size = data_size;
+ }
+ } else {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+ msp->actual_data_size = data_size;
+ }
+
+ temp_reg |= MSP_DATA_DELAY_BITS(protocol_desc->rx_data_delay);
+ temp_reg |= MSP_SET_ENDIANNES_BIT(protocol_desc->rx_bit_transfer_format);
+ temp_reg |= MSP_FRAME_SYNC_POL(protocol_desc->rx_frame_sync_pol);
+ temp_reg |= MSP_DATA_WORD_SWAP(protocol_desc->rx_half_word_swap);
+ temp_reg |= MSP_SET_COMPANDING_MODE(protocol_desc->expansion_mode);
+ temp_reg |= MSP_SET_FRAME_SYNC_IGNORE(protocol_desc->frame_sync_ignore);
+
+ writel(temp_reg, msp->registers + MSP_RCF);
+
+}
+
+static int ux500_msp_i2s_configure_protocol(struct msp *msp,
+ struct msp_config *config)
+{
+ int direction;
+ struct msp_protocol_desc *protocol_desc;
+ enum msp_data_size data_size;
+ u32 temp_reg = 0;
+
+ data_size = config->data_size;
+ msp->def_elem_len = config->def_elem_len;
+ direction = config->direction;
+ if (config->default_protocol_desc == 1) {
+ if (config->protocol >= MSP_INVALID_PROTOCOL) {
+ pr_err("%s: ERROR: Invalid protocol!\n", __func__);
+ return -EINVAL;
+ }
+ protocol_desc =
+ (struct msp_protocol_desc *)&prot_descs[config->protocol];
+ } else {
+ protocol_desc = (struct msp_protocol_desc *)&config->protocol_desc;
+ }
+
+ if (data_size < MSP_DATA_BITS_DEFAULT || data_size > MSP_DATA_BITS_32) {
+ pr_err("%s: ERROR: Invalid data-size requested (data_size = %d)!\n",
+ __func__, data_size);
+ return -EINVAL;
+ }
+
+ switch (direction) {
+ case MSP_TRANSMIT_MODE:
+ ux500_msp_i2s_set_prot_desc_tx(msp, protocol_desc, data_size);
+ break;
+ case MSP_RECEIVE_MODE:
+ ux500_msp_i2s_set_prot_desc_rx(msp, protocol_desc, data_size);
+ break;
+ case MSP_BOTH_T_R_MODE:
+ ux500_msp_i2s_set_prot_desc_tx(msp, protocol_desc, data_size);
+ ux500_msp_i2s_set_prot_desc_rx(msp, protocol_desc, data_size);
+ break;
+ default:
+ pr_err("%s: ERROR: Invalid direction requested (direction = %d)!\n",
+ __func__, direction);
+ return -EINVAL;
+ }
+
+ /* The below code is needed for both Rx and Tx path. Can't separate them. */
+ temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
+ temp_reg |= MSP_TX_CLKPOL_BIT(~protocol_desc->tx_clock_pol);
+ writel(temp_reg, msp->registers + MSP_GCR);
+ temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
+ temp_reg |= MSP_RX_CLKPOL_BIT(protocol_desc->rx_clock_pol);
+ writel(temp_reg, msp->registers + MSP_GCR);
+
+ return 0;
+}
+
+static int ux500_msp_i2s_configure_clock(struct msp *msp, struct msp_config *config)
+{
+ u32 reg_val_GCR;
+ u32 frame_per = 0;
+ u32 sck_div = 0;
+ u32 frame_width = 0;
+ u32 temp_reg = 0;
+ u32 bit_clock = 0;
+ struct msp_protocol_desc *protocol_desc = NULL;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR);
+
+ if (config->default_protocol_desc)
+ protocol_desc =
+ (struct msp_protocol_desc *)&prot_descs[config->protocol];
+ else
+ protocol_desc = (struct msp_protocol_desc *)&config->protocol_desc;
+
+ switch (config->protocol) {
+ case MSP_PCM_PROTOCOL:
+ case MSP_PCM_COMPAND_PROTOCOL:
+ frame_width = protocol_desc->frame_width;
+ sck_div = config->input_clock_freq / (config->frame_freq *
+ (protocol_desc->total_clocks_for_one_frame));
+ frame_per = protocol_desc->frame_period;
+ break;
+ case MSP_I2S_PROTOCOL:
+ frame_width = protocol_desc->frame_width;
+ sck_div = config->input_clock_freq / (config->frame_freq *
+ (protocol_desc->total_clocks_for_one_frame));
+ frame_per = protocol_desc->frame_period;
+ break;
+ case MSP_AC97_PROTOCOL:
+ /* Not supported */
+ pr_err("%s: ERROR: AC97 protocol not supported!\n", __func__);
+ return -ENOSYS;
+ default:
+ pr_err("%s: ERROR: Unknown protocol (%d)!\n",
+ __func__,
+ config->protocol);
+ return -EINVAL;
+ }
+
+ temp_reg = (sck_div - 1) & SCK_DIV_MASK;
+ temp_reg |= FRAME_WIDTH_BITS(frame_width);
+ temp_reg |= FRAME_PERIOD_BITS(frame_per);
+ writel(temp_reg, msp->registers + MSP_SRG);
+
+ bit_clock = (config->input_clock_freq)/(sck_div + 1);
+ /* If the bit clock is higher than 19.2MHz, Vape should be run in 100% OPP
+ * Only consider OPP 100% when bit-clock is used, i.e. MSP master mode
+ */
+ if ((bit_clock > 19200000) && ((config->tx_clock_sel != 0) || (config->rx_clock_sel != 0))) {
+ prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "ux500-msp-i2s", 100);
+ msp->vape_opp_constraint = 1;
+ } else {
+ prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "ux500-msp-i2s", 50);
+ msp->vape_opp_constraint = 0;
+ }
+
+ /* Enable clock */
+ udelay(100);
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | SRG_ENABLE, msp->registers + MSP_GCR);
+ udelay(100);
+
+ return 0;
+}
+
+static int ux500_msp_i2s_configure_multichannel(struct msp *msp, struct msp_config *config)
+{
+ struct msp_protocol_desc *protocol_desc;
+ struct msp_multichannel_config *mcfg;
+ u32 reg_val_MCR;
+
+ if (config->default_protocol_desc == 1) {
+ if (config->protocol >= MSP_INVALID_PROTOCOL) {
+ pr_err("%s: ERROR: Invalid protocol (%d)!\n",
+ __func__,
+ config->protocol);
+ return -EINVAL;
+ }
+ protocol_desc = (struct msp_protocol_desc *)
+ &prot_descs[config->protocol];
+ } else {
+ protocol_desc = (struct msp_protocol_desc *)&config->protocol_desc;
+ }
+
+ mcfg = &config->multichannel_config;
+ if (mcfg->tx_multichannel_enable) {
+ if (protocol_desc->tx_phase_mode == MSP_SINGLE_PHASE) {
+ reg_val_MCR = readl(msp->registers + MSP_MCR);
+ writel(reg_val_MCR |
+ (mcfg->tx_multichannel_enable ? 1 << TMCEN_BIT : 0),
+ msp->registers + MSP_MCR);
+ writel(mcfg->tx_channel_0_enable,
+ msp->registers + MSP_TCE0);
+ writel(mcfg->tx_channel_1_enable,
+ msp->registers + MSP_TCE1);
+ writel(mcfg->tx_channel_2_enable,
+ msp->registers + MSP_TCE2);
+ writel(mcfg->tx_channel_3_enable,
+ msp->registers + MSP_TCE3);
+ } else {
+ pr_err("%s: ERROR: Only single-phase supported (TX-mode: %d)!\n",
+ __func__, protocol_desc->tx_phase_mode);
+ return -EINVAL;
+ }
+ }
+ if (mcfg->rx_multichannel_enable) {
+ if (protocol_desc->rx_phase_mode == MSP_SINGLE_PHASE) {
+ reg_val_MCR = readl(msp->registers + MSP_MCR);
+ writel(reg_val_MCR |
+ (mcfg->rx_multichannel_enable ? 1 << RMCEN_BIT : 0),
+ msp->registers + MSP_MCR);
+ writel(mcfg->rx_channel_0_enable,
+ msp->registers + MSP_RCE0);
+ writel(mcfg->rx_channel_1_enable,
+ msp->registers + MSP_RCE1);
+ writel(mcfg->rx_channel_2_enable,
+ msp->registers + MSP_RCE2);
+ writel(mcfg->rx_channel_3_enable,
+ msp->registers + MSP_RCE3);
+ } else {
+ pr_err("%s: ERROR: Only single-phase supported (RX-mode: %d)!\n",
+ __func__, protocol_desc->rx_phase_mode);
+ return -EINVAL;
+ }
+ if (mcfg->rx_comparison_enable_mode) {
+ reg_val_MCR = readl(msp->registers + MSP_MCR);
+ writel(reg_val_MCR |
+ (mcfg->rx_comparison_enable_mode << RCMPM_BIT),
+ msp->registers + MSP_MCR);
+
+ writel(mcfg->comparison_mask,
+ msp->registers + MSP_RCM);
+ writel(mcfg->comparison_value,
+ msp->registers + MSP_RCV);
+
+ }
+ }
+
+ return 0;
+}
+
+void ux500_msp_i2s_configure_dma(struct msp *msp, struct msp_config *config)
+{
+ struct stedma40_chan_cfg *rx_dma_info = msp->dma_cfg_rx;
+ struct stedma40_chan_cfg *tx_dma_info = msp->dma_cfg_tx;
+ dma_cap_mask_t mask;
+ u16 word_width;
+ bool rx_active, tx_active;
+
+ if (msp->tx_pipeid != NULL) {
+ dma_release_channel(msp->tx_pipeid);
+ msp->tx_pipeid = NULL;
+ }
+
+ switch (config->data_size) {
+ case MSP_DATA_BITS_32:
+ word_width = STEDMA40_WORD_WIDTH;
+ break;
+ case MSP_DATA_BITS_16:
+ word_width = STEDMA40_HALFWORD_WIDTH;
+ break;
+ case MSP_DATA_BITS_8:
+ word_width = STEDMA40_BYTE_WIDTH;
+ break;
+ default:
+ word_width = STEDMA40_WORD_WIDTH;
+ pr_warn("%s: Unknown data-size (%d)! Assuming 32 bits.\n",
+ __func__, config->data_size);
+ }
+
+ rx_active = (config->direction == MSP_RECEIVE_MODE ||
+ config->direction == MSP_BOTH_T_R_MODE);
+ tx_active = (config->direction == MSP_TRANSMIT_MODE ||
+ config->direction == MSP_BOTH_T_R_MODE);
+
+ if (rx_active) {
+ rx_dma_info->src_info.data_width = word_width;
+ rx_dma_info->dst_info.data_width = word_width;
+ }
+ if (tx_active) {
+ tx_dma_info->src_info.data_width = word_width;
+ tx_dma_info->dst_info.data_width = word_width;
+ }
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ if (rx_active)
+ msp->rx_pipeid = dma_request_channel(mask, stedma40_filter, rx_dma_info);
+
+ if (tx_active)
+ msp->tx_pipeid = dma_request_channel(mask, stedma40_filter, tx_dma_info);
+}
+
+static int ux500_msp_i2s_dma_xfer(struct msp *msp, struct i2s_message *msg)
+{
+ dma_cookie_t status_submit;
+ int direction, enable_bit;
+ u32 reg_val_GCR;
+ struct dma_chan *pipeid;
+ struct dma_async_tx_descriptor *cdesc;
+
+ if (msg->i2s_direction == I2S_DIRECTION_TX) {
+ direction = DMA_TO_DEVICE;
+ pipeid = msp->tx_pipeid;
+ enable_bit = TX_ENABLE;
+ pr_debug("%s: Direction: TX\n", __func__);
+ } else {
+ direction = DMA_FROM_DEVICE;
+ pipeid = msp->rx_pipeid;
+ enable_bit = RX_ENABLE;
+ pr_debug("%s: Direction: RX\n", __func__);
+ }
+
+ pr_debug("%s: msg->buf_addr = %p\n", __func__, (void *)msg->buf_addr);
+ pr_debug("%s: buf_len = %d\n", __func__, msg->buf_len);
+ pr_debug("%s: perios_len = %d\n", __func__, msg->period_len);
+
+ /* setup the cyclic description */
+ cdesc = pipeid->device->device_prep_dma_cyclic(pipeid,
+ msg->buf_addr,
+ msg->buf_len,
+ msg->period_len,
+ direction);
+ if (IS_ERR(cdesc)) {
+ pr_err("%s: ERROR: device_prep_dma_cyclic failed (%ld)!\n",
+ __func__,
+ PTR_ERR(cdesc));
+ return -EINVAL;
+ }
+
+ /* Submit to the dma */
+ if (msg->i2s_direction == I2S_DIRECTION_TX) {
+ cdesc->callback = msp->xfer_data.tx_handler;
+ cdesc->callback_param = msp->xfer_data.tx_callback_data;
+ } else {
+ cdesc->callback = msp->xfer_data.rx_handler;
+ cdesc->callback_param = msp->xfer_data.rx_callback_data;
+ }
+ status_submit = dmaengine_submit(cdesc);
+ if (dma_submit_error(status_submit)) {
+ pr_err("%s: ERROR: dmaengine_submit failed!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Start the dma */
+ dma_async_issue_pending(pipeid);
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR);
+
+ return 0;
+}
+
+static int ux500_msp_i2s_enable(struct msp *msp, struct msp_config *config)
+{
+ int status = 0;
+ u32 reg_val_DMACR, reg_val_GCR;
+
+ if (config->work_mode != MSP_DMA_MODE) {
+ pr_err("%s: ERROR: Only DMA-mode is supported (msp->work_mode = %d)\n",
+ __func__,
+ msp->work_mode);
+ return -EINVAL;
+ }
+ msp->work_mode = config->work_mode;
+
+ /* Check msp state whether in RUN or CONFIGURED Mode */
+ if (msp->msp_state == MSP_STATE_IDLE) {
+ if (msp->plat_init) {
+ status = msp->plat_init();
+ if (status) {
+ pr_err("%s: ERROR: Failed to init MSP (%d)!\n",
+ __func__,
+ status);
+ return status;
+ }
+ }
+ }
+
+ /* Configure msp with protocol dependent settings */
+ ux500_msp_i2s_configure_protocol(msp, config);
+ ux500_msp_i2s_configure_clock(msp, config);
+ if (config->multichannel_configured == 1) {
+ status = ux500_msp_i2s_configure_multichannel(msp, config);
+ if (status)
+ pr_warn("%s: WARN: ux500_msp_i2s_configure_multichannel failed (%d)!\n",
+ __func__, status);
+ }
+
+ /* Make sure the correct DMA-directions are configured */
+ if ((config->direction == MSP_RECEIVE_MODE) ||
+ (config->direction == MSP_BOTH_T_R_MODE))
+ if (!msp->dma_cfg_rx) {
+ pr_err("%s: ERROR: MSP RX-mode is not configured!", __func__);
+ return -EINVAL;
+ }
+ if ((config->direction == MSP_TRANSMIT_MODE) ||
+ (config->direction == MSP_BOTH_T_R_MODE))
+ if (!msp->dma_cfg_tx) {
+ pr_err("%s: ERROR: MSP TX-mode is not configured!", __func__);
+ return -EINVAL;
+ }
+
+ reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+ switch (config->direction) {
+ case MSP_TRANSMIT_MODE:
+ writel(reg_val_DMACR | TX_DMA_ENABLE,
+ msp->registers + MSP_DMACR);
+
+ msp->xfer_data.tx_handler = config->handler;
+ msp->xfer_data.tx_callback_data = config->tx_callback_data;
+
+ break;
+ case MSP_RECEIVE_MODE:
+ writel(reg_val_DMACR | RX_DMA_ENABLE,
+ msp->registers + MSP_DMACR);
+
+ msp->xfer_data.rx_handler = config->handler;
+ msp->xfer_data.rx_callback_data = config->rx_callback_data;
+
+ break;
+ case MSP_BOTH_T_R_MODE:
+ writel(reg_val_DMACR | RX_DMA_ENABLE | TX_DMA_ENABLE,
+ msp->registers + MSP_DMACR);
+
+ msp->xfer_data.tx_handler = config->handler;
+ msp->xfer_data.rx_handler = config->handler;
+ msp->xfer_data.tx_callback_data = config->tx_callback_data;
+ msp->xfer_data.rx_callback_data = config->rx_callback_data;
+
+ break;
+ default:
+ pr_err("%s: ERROR: Illegal MSP direction (config->direction = %d)!",
+ __func__,
+ config->direction);
+ if (msp->plat_exit)
+ msp->plat_exit();
+ return -EINVAL;
+ }
+ ux500_msp_i2s_configure_dma(msp, config);
+
+ msp->transfer = ux500_msp_i2s_dma_xfer;
+
+ writel(config->iodelay, msp->registers + MSP_IODLY);
+
+ /* Enable frame generation logic */
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR);
+
+ return status;
+}
+
+static void flush_fifo_rx(struct msp *msp)
+{
+ u32 reg_val_DR, reg_val_GCR, reg_val_FLR;
+ u32 limit = 32;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | RX_ENABLE, msp->registers + MSP_GCR);
+
+ reg_val_FLR = readl(msp->registers + MSP_FLR);
+ while (!(reg_val_FLR & RX_FIFO_EMPTY) && limit--) {
+ reg_val_DR = readl(msp->registers + MSP_DR);
+ reg_val_FLR = readl(msp->registers + MSP_FLR);
+ }
+
+ writel(reg_val_GCR, msp->registers + MSP_GCR);
+}
+
+static void flush_fifo_tx(struct msp *msp)
+{
+ u32 reg_val_TSTDR, reg_val_GCR, reg_val_FLR;
+ u32 limit = 32;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | TX_ENABLE, msp->registers + MSP_GCR);
+ writel(MSP_ITCR_ITEN | MSP_ITCR_TESTFIFO, msp->registers + MSP_ITCR);
+
+ reg_val_FLR = readl(msp->registers + MSP_FLR);
+ while (!(reg_val_FLR & TX_FIFO_EMPTY) && limit--) {
+ reg_val_TSTDR = readl(msp->registers + MSP_TSTDR);
+ reg_val_FLR = readl(msp->registers + MSP_FLR);
+ }
+ writel(0x0, msp->registers + MSP_ITCR);
+ writel(reg_val_GCR, msp->registers + MSP_GCR);
+}
+
+int ux500_msp_i2s_open(struct ux500_msp_i2s_drvdata *drvdata, struct msp_config *msp_config)
+{
+ struct msp *msp = drvdata->msp;
+ u32 old_reg, new_reg, mask;
+ int res;
+
+ if (in_interrupt()) {
+ pr_err("%s: ERROR: Open called in interrupt context!\n", __func__);
+ return -1;
+ }
+
+ /* Two simultanous configuring msp is avoidable */
+ down(&msp->lock);
+
+ /* Don't enable regulator if its msp1 or msp3 */
+ if (!(msp->reg_enabled) && msp->id != MSP_1_I2S_CONTROLLER
+ && msp->id != MSP_3_I2S_CONTROLLER) {
+ res = regulator_enable(drvdata->reg_vape);
+ if (res != 0) {
+ pr_err("%s: Failed to enable regulator!\n", __func__);
+ up(&msp->lock);
+ return res;
+ }
+ msp->reg_enabled = 1;
+ }
+
+ switch (msp->users) {
+ case 0:
+ clk_enable(msp->clk);
+ msp->direction = msp_config->direction;
+ break;
+ case 1:
+ if (msp->direction == MSP_BOTH_T_R_MODE ||
+ msp_config->direction == msp->direction ||
+ msp_config->direction == MSP_BOTH_T_R_MODE) {
+ pr_warn("%s: WARN: MSP is in use (direction = %d)!\n",
+ __func__, msp_config->direction);
+ up(&msp->lock);
+ return -EBUSY;
+ }
+ msp->direction = MSP_BOTH_T_R_MODE;
+ break;
+ default:
+ pr_warn("%s: MSP in use in (both directions)!\n", __func__);
+ up(&msp->lock);
+ return -EBUSY;
+ }
+ msp->users++;
+
+ /* First do the global config register */
+ mask =
+ RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FRAME_SYNC_MASK |
+ TX_FRAME_SYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
+ RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
+ LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
+
+ new_reg = (msp_config->tx_clock_sel | msp_config->rx_clock_sel |
+ msp_config->rx_frame_sync_pol | msp_config->tx_frame_sync_pol |
+ msp_config->rx_frame_sync_sel | msp_config->tx_frame_sync_sel |
+ msp_config->rx_fifo_config | msp_config->tx_fifo_config |
+ msp_config->srg_clock_sel | msp_config->loopback_enable |
+ msp_config->tx_data_enable);
+
+ old_reg = readl(msp->registers + MSP_GCR);
+ old_reg &= ~mask;
+ new_reg |= old_reg;
+ writel(new_reg, msp->registers + MSP_GCR);
+
+ if (ux500_msp_i2s_enable(msp, msp_config) != 0) {
+ pr_err("%s: ERROR: ux500_msp_i2s_enable failed!\n", __func__);
+ return -EBUSY;
+ }
+ if (msp_config->loopback_enable & 0x80)
+ msp->loopback_enable = 1;
+
+ /* Flush FIFOs */
+ flush_fifo_tx(msp);
+ flush_fifo_rx(msp);
+
+ msp->msp_state = MSP_STATE_CONFIGURED;
+ up(&msp->lock);
+ return 0;
+}
+
+static void func_notify_timer(unsigned long data)
+{
+ struct msp *msp = (struct msp *)data;
+ if (msp->polling_flag) {
+ msp->msp_io_error = 1;
+ pr_err("%s: ERROR: Polling timeout!\n", __func__);
+ del_timer(&msp->notify_timer);
+ }
+}
+
+int ux500_msp_i2s_transfer(struct ux500_msp_i2s_drvdata *drvdata, struct i2s_message *message)
+{
+ struct msp *msp = drvdata->msp;
+ int status = 0;
+
+ if (!message || (msp->msp_state == MSP_STATE_IDLE)) {
+ pr_err("%s: ERROR: i2s_message == NULL!\n", __func__);
+ return -EINVAL;
+ }
+ if (msp->msp_state == MSP_STATE_IDLE) {
+ pr_err("%s: ERROR: MSP in idle-state!\n", __func__);
+ return -EPERM;
+ }
+
+ msp->msp_state = MSP_STATE_RUN;
+ if (msp->transfer)
+ status = msp->transfer(msp, message);
+
+ if (msp->msp_state == MSP_STATE_RUN)
+ msp->msp_state = MSP_STATE_CONFIGURED;
+
+ return status;
+}
+
+static void ux500_msp_i2s_disable_rx(struct msp *msp)
+{
+ u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR & ~RX_ENABLE, msp->registers + MSP_GCR);
+ reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+ writel(reg_val_DMACR & ~RX_DMA_ENABLE, msp->registers + MSP_DMACR);
+ reg_val_IMSC = readl(msp->registers + MSP_IMSC);
+ writel(reg_val_IMSC &
+ ~(RECEIVE_SERVICE_INT | RECEIVE_OVERRUN_ERROR_INT),
+ msp->registers + MSP_IMSC);
+ msp->xfer_data.message.rxbytes = 0;
+ msp->xfer_data.message.rx_offset = 0;
+ msp->xfer_data.message.rxdata = NULL;
+ msp->read = NULL;
+}
+
+static void ux500_msp_i2s_disable_tx(struct msp *msp)
+{
+ u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR & ~TX_ENABLE, msp->registers + MSP_GCR);
+ reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+ writel(reg_val_DMACR & ~TX_DMA_ENABLE, msp->registers + MSP_DMACR);
+ reg_val_IMSC = readl(msp->registers + MSP_IMSC);
+ writel(reg_val_IMSC &
+ ~(TRANSMIT_SERVICE_INT | TRANSMIT_UNDERRUN_ERR_INT),
+ msp->registers + MSP_IMSC);
+ msp->xfer_data.message.txbytes = 0;
+ msp->xfer_data.message.tx_offset = 0;
+ msp->xfer_data.message.txdata = NULL;
+ msp->write = NULL;
+}
+
+static int ux500_msp_i2s_disable(struct msp *msp, int direction, enum i2s_flag flag)
+{
+ u32 reg_val_GCR;
+ int status = 0;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ if (!(reg_val_GCR & (TX_ENABLE | RX_ENABLE)))
+ return 0;
+
+ if (flag == DISABLE_ALL || flag == DISABLE_TRANSMIT) {
+ if (msp->tx_pipeid != NULL) {
+ dmaengine_terminate_all(msp->tx_pipeid);
+ dma_release_channel(msp->tx_pipeid);
+ msp->tx_pipeid = NULL;
+ }
+ }
+ if ((flag == DISABLE_ALL || flag == DISABLE_RECEIVE)) {
+ if (msp->rx_pipeid != NULL) {
+ dmaengine_terminate_all(msp->rx_pipeid);
+ dma_release_channel(msp->rx_pipeid);
+ msp->rx_pipeid = NULL;
+ }
+ }
+
+ if (flag == DISABLE_TRANSMIT)
+ ux500_msp_i2s_disable_tx(msp);
+ else if (flag == DISABLE_RECEIVE)
+ ux500_msp_i2s_disable_rx(msp);
+ else {
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | LOOPBACK_MASK,
+ msp->registers + MSP_GCR);
+
+ /* Flush TX-FIFO */
+ flush_fifo_tx(msp);
+
+ /* Disable TX-channel */
+ writel((readl(msp->registers + MSP_GCR) &
+ (~TX_ENABLE)), msp->registers + MSP_GCR);
+
+ /* Flush RX-FIFO */
+ flush_fifo_rx(msp);
+
+ /* Disable Loopback and Receive channel */
+ writel((readl(msp->registers + MSP_GCR) &
+ (~(RX_ENABLE | LOOPBACK_MASK))),
+ msp->registers + MSP_GCR);
+
+ ux500_msp_i2s_disable_tx(msp);
+ ux500_msp_i2s_disable_rx(msp);
+
+ }
+
+ /* disable sample rate and frame generators */
+ if (flag == DISABLE_ALL) {
+ msp->msp_state = MSP_STATE_IDLE;
+ writel((readl(msp->registers + MSP_GCR) &
+ (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
+ msp->registers + MSP_GCR);
+ memset(&msp->xfer_data, 0, sizeof(struct trans_data));
+ if (msp->plat_exit)
+ status = msp->plat_exit();
+ if (status)
+ pr_warn("%s: WARN: ux500_msp_i2s_exit failed (%d)!\n",
+ __func__, status);
+ msp->transfer = NULL;
+ writel(0, msp->registers + MSP_GCR);
+ writel(0, msp->registers + MSP_TCF);
+ writel(0, msp->registers + MSP_RCF);
+ writel(0, msp->registers + MSP_DMACR);
+ writel(0, msp->registers + MSP_SRG);
+ writel(0, msp->registers + MSP_MCR);
+ writel(0, msp->registers + MSP_RCM);
+ writel(0, msp->registers + MSP_RCV);
+ writel(0, msp->registers + MSP_TCE0);
+ writel(0, msp->registers + MSP_TCE1);
+ writel(0, msp->registers + MSP_TCE2);
+ writel(0, msp->registers + MSP_TCE3);
+ writel(0, msp->registers + MSP_RCE0);
+ writel(0, msp->registers + MSP_RCE1);
+ writel(0, msp->registers + MSP_RCE2);
+ writel(0, msp->registers + MSP_RCE3);
+ }
+
+ return status;
+}
+
+int ux500_msp_i2s_close(struct ux500_msp_i2s_drvdata *drvdata, enum i2s_flag flag)
+{
+ struct msp *msp = drvdata->msp;
+ int status = 0;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ down(&msp->lock);
+
+ if (msp->users == 0) {
+ pr_err("%s: ERROR: MSP already closed!\n", __func__);
+ status = -EINVAL;
+ goto end;
+ }
+ pr_debug("%s: msp->users = %d, flag = %d\n", __func__, msp->users, flag);
+
+ /* We need to call it twice for DISABLE_ALL*/
+ msp->users = flag == DISABLE_ALL ? 0 : msp->users - 1;
+ if (msp->users)
+ status = ux500_msp_i2s_disable(msp, MSP_BOTH_T_R_MODE, flag);
+ else {
+ status = ux500_msp_i2s_disable(msp, MSP_BOTH_T_R_MODE, DISABLE_ALL);
+ clk_disable(msp->clk);
+ if (msp->reg_enabled) {
+ status = regulator_disable(drvdata->reg_vape);
+ msp->reg_enabled = 0;
+ }
+ if (status != 0) {
+ pr_err("%s: ERROR: Failed to disable regulator (%d)!\n",
+ __func__, status);
+ clk_enable(msp->clk);
+ goto end;
+ }
+ }
+ if (status)
+ goto end;
+ if (msp->users)
+ msp->direction = flag == DISABLE_TRANSMIT ?
+ MSP_RECEIVE_MODE : MSP_TRANSMIT_MODE;
+
+ if (msp->vape_opp_constraint == 1) {
+ prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s", 50);
+ msp->vape_opp_constraint = 0;
+ }
+end:
+ up(&msp->lock);
+ return status;
+
+}
+
+int ux500_msp_i2s_hw_status(struct ux500_msp_i2s_drvdata *drvdata)
+{
+ struct msp *msp = drvdata->msp;
+ int status;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ status = readl(msp->registers + MSP_RIS) & 0xee;
+ if (status)
+ writel(status, msp->registers + MSP_ICR);
+
+ return status;
+}
+
+dma_addr_t ux500_msp_i2s_get_pointer(struct ux500_msp_i2s_drvdata *drvdata,
+ enum i2s_direction_t i2s_direction)
+{
+ struct msp *msp = drvdata->msp;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ return (i2s_direction == I2S_DIRECTION_TX) ?
+ stedma40_get_src_addr(msp->tx_pipeid) :
+ stedma40_get_dst_addr(msp->rx_pipeid);
+}
+
+struct ux500_msp_i2s_drvdata *ux500_msp_i2s_init(struct platform_device *pdev,
+ struct msp_i2s_platform_data *platform_data)
+{
+ struct ux500_msp_i2s_drvdata *msp_i2s_drvdata;
+ int irq;
+ struct resource *res = NULL;
+ struct i2s_controller *i2s_cont;
+ struct msp *msp;
+
+ pr_debug("%s: Enter (pdev->name = %s).\n", __func__, pdev->name);
+
+ msp_i2s_drvdata = kzalloc(sizeof(struct ux500_msp_i2s_drvdata), GFP_KERNEL);
+ msp_i2s_drvdata->msp = kzalloc(sizeof(struct msp), GFP_KERNEL);
+ msp = msp_i2s_drvdata->msp;
+
+ msp->id = platform_data->id;
+ msp_i2s_drvdata->id = msp->id;
+ pr_debug("msp_i2s_drvdata->id = %d\n", msp_i2s_drvdata->id);
+
+ msp->plat_init = platform_data->msp_i2s_init;
+ msp->plat_exit = platform_data->msp_i2s_exit;
+ msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
+ msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
+
+ sema_init(&msp->lock, 1);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ pr_err("%s: ERROR: Unable to get resource!\n", __func__);
+ goto free_msp;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ goto free_msp;
+ msp->irq = irq;
+
+ msp->registers = ioremap(res->start, (res->end - res->start + 1));
+ if (msp->registers == NULL)
+ goto free_msp;
+
+ msp_i2s_drvdata->reg_vape = regulator_get(NULL, "v-ape");
+ if (IS_ERR(msp_i2s_drvdata->reg_vape)) {
+ pr_err("%s: ERROR: Failed to get Vape supply (%d)!\n",
+ __func__, (int)PTR_ERR(msp_i2s_drvdata->reg_vape));
+ goto free_irq;
+ }
+ dev_set_drvdata(&pdev->dev, msp_i2s_drvdata);
+
+ prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
+ msp->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(msp->clk)) {
+ pr_err("%s: ERROR: clk_get failed (%d)!\n",
+ __func__, (int)PTR_ERR(msp->clk));
+ goto free_irq;
+ }
+
+ init_timer(&msp->notify_timer);
+ msp->notify_timer.expires = jiffies + msecs_to_jiffies(1000);
+ msp->notify_timer.function = func_notify_timer;
+ msp->notify_timer.data = (unsigned long)msp;
+
+ msp->rx_pipeid = NULL;
+ msp->tx_pipeid = NULL;
+ msp->read = NULL;
+ msp->write = NULL;
+ msp->transfer = NULL;
+ msp->msp_state = MSP_STATE_IDLE;
+ msp->loopback_enable = 0;
+
+ /* I2S Controller is allocated and added in I2S controller class. */
+ i2s_cont = kzalloc(sizeof(*i2s_cont), GFP_KERNEL);
+ if (!i2s_cont) {
+ pr_err("%s: ERROR: Failed to allocate struct i2s_cont (kzalloc)!\n",
+ __func__);
+ goto del_timer;
+ }
+ i2s_cont->dev.parent = &pdev->dev;
+ i2s_cont->data = (void *)msp;
+ i2s_cont->id = (s16)msp->id;
+ snprintf(i2s_cont->name,
+ sizeof(i2s_cont->name),
+ "ux500-msp-i2s.%04x",
+ msp->id);
+ pr_debug("I2S device-name :%s\n", i2s_cont->name);
+ msp->i2s_cont = i2s_cont;
+
+ return msp_i2s_drvdata;
+
+del_timer:
+ del_timer_sync(&msp->notify_timer);
+ clk_put(msp->clk);
+free_irq:
+ iounmap(msp->registers);
+free_msp:
+ kfree(msp);
+ return NULL;
+}
+
+int ux500_msp_i2s_exit(struct ux500_msp_i2s_drvdata *drvdata)
+{
+ struct msp *msp = drvdata->msp;
+ int status = 0;
+
+ pr_debug("%s: Enter (drvdata->id = %d).\n", __func__, drvdata->id);
+
+ device_unregister(&msp->i2s_cont->dev);
+ del_timer_sync(&msp->notify_timer);
+ clk_put(msp->clk);
+ iounmap(msp->registers);
+ prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
+ regulator_put(drvdata->reg_vape);
+ kfree(msp);
+
+ return status;
+}
+
+int ux500_msp_i2s_suspend(struct ux500_msp_i2s_drvdata *drvdata)
+{
+ struct msp *msp = drvdata->msp;
+
+ pr_debug("%s: Enter (drvdata->id = %d).\n", __func__, drvdata->id);
+
+ down(&msp->lock);
+ if (msp->users > 0) {
+ up(&msp->lock);
+ return -EBUSY;
+ }
+ up(&msp->lock);
+
+ return 0;
+}
+
+int ux500_msp_i2s_resume(struct ux500_msp_i2s_drvdata *drvdata)
+{
+ pr_debug("%s: Enter (drvdata->id = %d).\n", __func__, drvdata->id);
+
+ return 0;
+}
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
new file mode 100644
index 00000000000..db88d0ca5de
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_i2s.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 UX500_MSP_I2S_H
+#define UX500_MSP_I2S_H
+
+#include <linux/platform_device.h>
+#include <mach/msp.h>
+
+struct ux500_msp_i2s_drvdata {
+ int id;
+ struct msp *msp;
+ struct regulator *reg_vape;
+};
+
+struct ux500_msp_i2s_drvdata *ux500_msp_i2s_init(struct platform_device *pdev,
+ struct msp_i2s_platform_data *platform_data);
+int ux500_msp_i2s_exit(struct ux500_msp_i2s_drvdata *drvdata);
+int ux500_msp_i2s_open(struct ux500_msp_i2s_drvdata *drvdata, struct msp_config *msp_config);
+int ux500_msp_i2s_close(struct ux500_msp_i2s_drvdata *drvdata, enum i2s_flag flag);
+int ux500_msp_i2s_transfer(struct ux500_msp_i2s_drvdata *drvdata, struct i2s_message *message);
+int ux500_msp_i2s_hw_status(struct ux500_msp_i2s_drvdata *drvdata);
+dma_addr_t ux500_msp_i2s_get_pointer(struct ux500_msp_i2s_drvdata *drvdata,
+ enum i2s_direction_t i2s_direction);
+
+int ux500_msp_i2s_suspend(struct ux500_msp_i2s_drvdata *drvdata);
+int ux500_msp_i2s_resume(struct ux500_msp_i2s_drvdata *drvdata);
+
+#endif
+
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
index 0161ffdf3f4..29b3f5e0ffb 100644
--- a/sound/soc/ux500/ux500_pcm.c
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -272,7 +272,7 @@ static int ux500_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
private->msp_id,
stream_id);
if (ret) {
- pr_err("%s: Failed to configure sg-list!\n", __func__);
+ pr_err("%s: Failed to configure I2S!\n", __func__);
return -EINVAL;
}
break;