From f0c4205b54113463ccb93c9ab064fc630c5c50bd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Jun 2011 19:42:56 +0100 Subject: ASoC: Factor out redundant read() functions We've got a whole bunch of functions which just call straight through to do_hw_read(). Simplify this situation by removing them and using hw_read() directly. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-cache.c | 52 ++++++++------------------------------------------- 1 file changed, 8 insertions(+), 44 deletions(-) diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 9a88a276a0ab..b88a61fd6de0 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -61,7 +61,7 @@ static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, return -EIO; } -static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg) +static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) { int ret; unsigned int val; @@ -82,12 +82,6 @@ static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg) return val; } -static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return do_hw_read(codec, reg); -} - static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -98,12 +92,6 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, return do_hw_write(codec, reg, value, &data, 2); } -static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return do_hw_read(codec, reg); -} - static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -126,12 +114,6 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, return do_hw_write(codec, reg, value, data, 2); } -static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return do_hw_read(codec, reg); -} - static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -144,12 +126,6 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, return do_hw_write(codec, reg, value, data, 3); } -static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return do_hw_read(codec, reg); -} - #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) static unsigned int do_i2c_read(struct snd_soc_codec *codec, void *reg, int reglen, @@ -232,12 +208,6 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, #define snd_soc_16_8_read_i2c NULL #endif -static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return do_hw_read(codec, reg); -} - static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -267,12 +237,6 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, #define snd_soc_16_16_read_i2c NULL #endif -static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return do_hw_read(codec, reg); -} - static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -337,30 +301,30 @@ static struct { } io_types[] = { { .addr_bits = 4, .data_bits = 12, - .write = snd_soc_4_12_write, .read = snd_soc_4_12_read, + .write = snd_soc_4_12_write, }, { .addr_bits = 7, .data_bits = 9, - .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, + .write = snd_soc_7_9_write, }, { .addr_bits = 8, .data_bits = 8, - .write = snd_soc_8_8_write, .read = snd_soc_8_8_read, + .write = snd_soc_8_8_write, .i2c_read = snd_soc_8_8_read_i2c, }, { .addr_bits = 8, .data_bits = 16, - .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, + .write = snd_soc_8_16_write, .i2c_read = snd_soc_8_16_read_i2c, }, { .addr_bits = 16, .data_bits = 8, - .write = snd_soc_16_8_write, .read = snd_soc_16_8_read, + .write = snd_soc_16_8_write, .i2c_read = snd_soc_16_8_read_i2c, }, { .addr_bits = 16, .data_bits = 16, - .write = snd_soc_16_16_write, .read = snd_soc_16_16_read, + .write = snd_soc_16_16_write, .i2c_read = snd_soc_16_16_read_i2c, }, }; @@ -402,7 +366,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, } codec->write = io_types[i].write; - codec->read = io_types[i].read; + codec->read = hw_read; codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; switch (control) { -- cgit v1.2.3 From 5bef44f9b4849d1c3af4ed2ea93061ff56e68cd7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jun 2011 17:49:55 +0100 Subject: ASoC: Move register I/O code into a separate file For clarity and to help ongoing refactoring in this area create a new file to contain the physical I/O functions, separating them out from the cache operations. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/Makefile | 3 +- sound/soc/soc-cache.c | 380 ----------------------------------------------- sound/soc/soc-io.c | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 401 insertions(+), 381 deletions(-) create mode 100644 sound/soc/soc-io.c diff --git a/sound/soc/Makefile b/sound/soc/Makefile index adb5719cb7d2..4f913876f332 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,4 +1,5 @@ -snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o soc-pcm.o +snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o +snd-soc-core-objs += soc-pcm.o soc-io.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index b88a61fd6de0..d9f8aded51f3 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -20,386 +20,6 @@ #include -#ifdef CONFIG_SPI_MASTER -static int do_spi_write(void *control, const char *data, int len) -{ - struct spi_device *spi = control; - int ret; - - ret = spi_write(spi, data, len); - if (ret < 0) - return ret; - - return len; -} -#endif - -static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value, const void *data, int len) -{ - int ret; - - if (!snd_soc_codec_volatile_register(codec, reg) && - reg < codec->driver->reg_cache_size && - !codec->cache_bypass) { - ret = snd_soc_cache_write(codec, reg, value); - if (ret < 0) - return -1; - } - - if (codec->cache_only) { - codec->cache_sync = 1; - return 0; - } - - ret = codec->hw_write(codec->control_data, data, len); - if (ret == len) - return 0; - if (ret < 0) - return ret; - else - return -EIO; -} - -static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) -{ - int ret; - unsigned int val; - - if (reg >= codec->driver->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg) || - codec->cache_bypass) { - if (codec->cache_only) - return -1; - - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); - } - - ret = snd_soc_cache_read(codec, reg, &val); - if (ret < 0) - return -1; - return val; -} - -static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 data; - - data = cpu_to_be16((reg << 12) | (value & 0xffffff)); - - return do_hw_write(codec, reg, value, &data, 2); -} - -static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 data; - - data = cpu_to_be16((reg << 9) | (value & 0x1ff)); - - return do_hw_write(codec, reg, value, &data, 2); -} - -static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - reg &= 0xff; - data[0] = reg; - data[1] = value & 0xff; - - return do_hw_write(codec, reg, value, data, 2); -} - -static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - u16 val = cpu_to_be16(value); - - data[0] = reg; - memcpy(&data[1], &val, sizeof(val)); - - return do_hw_write(codec, reg, value, data, 3); -} - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int do_i2c_read(struct snd_soc_codec *codec, - void *reg, int reglen, - void *data, int datalen) -{ - struct i2c_msg xfer[2]; - int ret; - struct i2c_client *client = codec->control_data; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = reglen; - xfer[0].buf = reg; - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = datalen; - xfer[1].buf = data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret == 2) - return 0; - else if (ret < 0) - return ret; - else - return -EIO; -} -#endif - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - u8 reg = r; - u8 data; - int ret; - - ret = do_i2c_read(codec, ®, 1, &data, 1); - if (ret < 0) - return 0; - return data; -} -#else -#define snd_soc_8_8_read_i2c NULL -#endif - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - u8 reg = r; - u16 data; - int ret; - - ret = do_i2c_read(codec, ®, 1, &data, 2); - if (ret < 0) - return 0; - return (data >> 8) | ((data & 0xff) << 8); -} -#else -#define snd_soc_8_16_read_i2c NULL -#endif - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - u16 reg = r; - u8 data; - int ret; - - ret = do_i2c_read(codec, ®, 2, &data, 1); - if (ret < 0) - return 0; - return data; -} -#else -#define snd_soc_16_8_read_i2c NULL -#endif - -static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - u16 rval = cpu_to_be16(reg); - - memcpy(data, &rval, sizeof(rval)); - data[2] = value; - - return do_hw_write(codec, reg, value, data, 3); -} - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - u16 reg = cpu_to_be16(r); - u16 data; - int ret; - - ret = do_i2c_read(codec, ®, 2, &data, 2); - if (ret < 0) - return 0; - return be16_to_cpu(data); -} -#else -#define snd_soc_16_16_read_i2c NULL -#endif - -static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 data[2]; - - data[0] = cpu_to_be16(reg); - data[1] = cpu_to_be16(value); - - return do_hw_write(codec, reg, value, data, sizeof(data)); -} - -/* Primitive bulk write support for soc-cache. The data pointed to by - * `data' needs to already be in the form the hardware expects - * including any leading register specific data. Any data written - * through this function will not go through the cache as it only - * handles writing to volatile or out of bounds registers. - */ -static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg, - const void *data, size_t len) -{ - int ret; - - /* To ensure that we don't get out of sync with the cache, check - * whether the base register is volatile or if we've directly asked - * to bypass the cache. Out of bounds registers are considered - * volatile. - */ - if (!codec->cache_bypass - && !snd_soc_codec_volatile_register(codec, reg) - && reg < codec->driver->reg_cache_size) - return -EINVAL; - - switch (codec->control_type) { -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) - case SND_SOC_I2C: - ret = i2c_master_send(codec->control_data, data, len); - break; -#endif -#if defined(CONFIG_SPI_MASTER) - case SND_SOC_SPI: - ret = spi_write(codec->control_data, data, len); - break; -#endif - default: - BUG(); - } - - if (ret == len) - return 0; - if (ret < 0) - return ret; - else - return -EIO; -} - -static struct { - int addr_bits; - int data_bits; - int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); - unsigned int (*read)(struct snd_soc_codec *, unsigned int); - unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); -} io_types[] = { - { - .addr_bits = 4, .data_bits = 12, - .write = snd_soc_4_12_write, - }, - { - .addr_bits = 7, .data_bits = 9, - .write = snd_soc_7_9_write, - }, - { - .addr_bits = 8, .data_bits = 8, - .write = snd_soc_8_8_write, - .i2c_read = snd_soc_8_8_read_i2c, - }, - { - .addr_bits = 8, .data_bits = 16, - .write = snd_soc_8_16_write, - .i2c_read = snd_soc_8_16_read_i2c, - }, - { - .addr_bits = 16, .data_bits = 8, - .write = snd_soc_16_8_write, - .i2c_read = snd_soc_16_8_read_i2c, - }, - { - .addr_bits = 16, .data_bits = 16, - .write = snd_soc_16_16_write, - .i2c_read = snd_soc_16_16_read_i2c, - }, -}; - -/** - * snd_soc_codec_set_cache_io: Set up standard I/O functions. - * - * @codec: CODEC to configure. - * @addr_bits: Number of bits of register address data. - * @data_bits: Number of bits of data per register. - * @control: Control bus used. - * - * Register formats are frequently shared between many I2C and SPI - * devices. In order to promote code reuse the ASoC core provides - * some standard implementations of CODEC read and write operations - * which can be set up using this function. - * - * The caller is responsible for allocating and initialising the - * actual cache. - * - * Note that at present this code cannot be used by CODECs with - * volatile registers. - */ -int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, - int addr_bits, int data_bits, - enum snd_soc_control_type control) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(io_types); i++) - if (io_types[i].addr_bits == addr_bits && - io_types[i].data_bits == data_bits) - break; - if (i == ARRAY_SIZE(io_types)) { - printk(KERN_ERR - "No I/O functions for %d bit address %d bit data\n", - addr_bits, data_bits); - return -EINVAL; - } - - codec->write = io_types[i].write; - codec->read = hw_read; - codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; - - switch (control) { - case SND_SOC_CUSTOM: - break; - - case SND_SOC_I2C: -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) - codec->hw_write = (hw_write_t)i2c_master_send; -#endif - if (io_types[i].i2c_read) - codec->hw_read = io_types[i].i2c_read; - - codec->control_data = container_of(codec->dev, - struct i2c_client, - dev); - break; - - case SND_SOC_SPI: -#ifdef CONFIG_SPI_MASTER - codec->hw_write = do_spi_write; -#endif - - codec->control_data = container_of(codec->dev, - struct spi_device, - dev); - break; - } - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); - static bool snd_soc_set_cache_val(void *base, unsigned int idx, unsigned int val, unsigned int word_size) { diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c new file mode 100644 index 000000000000..855e5cde2793 --- /dev/null +++ b/sound/soc/soc-io.c @@ -0,0 +1,399 @@ +/* + * soc-io.c -- ASoC register I/O helpers + * + * Copyright 2009-2011 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include + +#ifdef CONFIG_SPI_MASTER +static int do_spi_write(void *control, const char *data, int len) +{ + struct spi_device *spi = control; + int ret; + + ret = spi_write(spi, data, len); + if (ret < 0) + return ret; + + return len; +} +#endif + +static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value, const void *data, int len) +{ + int ret; + + if (!snd_soc_codec_volatile_register(codec, reg) && + reg < codec->driver->reg_cache_size && + !codec->cache_bypass) { + ret = snd_soc_cache_write(codec, reg, value); + if (ret < 0) + return -1; + } + + if (codec->cache_only) { + codec->cache_sync = 1; + return 0; + } + + ret = codec->hw_write(codec->control_data, data, len); + if (ret == len) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + +static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) +{ + int ret; + unsigned int val; + + if (reg >= codec->driver->reg_cache_size || + snd_soc_codec_volatile_register(codec, reg) || + codec->cache_bypass) { + if (codec->cache_only) + return -1; + + BUG_ON(!codec->hw_read); + return codec->hw_read(codec, reg); + } + + ret = snd_soc_cache_read(codec, reg, &val); + if (ret < 0) + return -1; + return val; +} + +static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 data; + + data = cpu_to_be16((reg << 12) | (value & 0xffffff)); + + return do_hw_write(codec, reg, value, &data, 2); +} + +static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 data; + + data = cpu_to_be16((reg << 9) | (value & 0x1ff)); + + return do_hw_write(codec, reg, value, &data, 2); +} + +static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + reg &= 0xff; + data[0] = reg; + data[1] = value & 0xff; + + return do_hw_write(codec, reg, value, data, 2); +} + +static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[3]; + u16 val = cpu_to_be16(value); + + data[0] = reg; + memcpy(&data[1], &val, sizeof(val)); + + return do_hw_write(codec, reg, value, data, 3); +} + +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +static unsigned int do_i2c_read(struct snd_soc_codec *codec, + void *reg, int reglen, + void *data, int datalen) +{ + struct i2c_msg xfer[2]; + int ret; + struct i2c_client *client = codec->control_data; + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = reglen; + xfer[0].buf = reg; + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = datalen; + xfer[1].buf = data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret == 2) + return 0; + else if (ret < 0) + return ret; + else + return -EIO; +} +#endif + +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, + unsigned int r) +{ + u8 reg = r; + u8 data; + int ret; + + ret = do_i2c_read(codec, ®, 1, &data, 1); + if (ret < 0) + return 0; + return data; +} +#else +#define snd_soc_8_8_read_i2c NULL +#endif + +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, + unsigned int r) +{ + u8 reg = r; + u16 data; + int ret; + + ret = do_i2c_read(codec, ®, 1, &data, 2); + if (ret < 0) + return 0; + return (data >> 8) | ((data & 0xff) << 8); +} +#else +#define snd_soc_8_16_read_i2c NULL +#endif + +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, + unsigned int r) +{ + u16 reg = r; + u8 data; + int ret; + + ret = do_i2c_read(codec, ®, 2, &data, 1); + if (ret < 0) + return 0; + return data; +} +#else +#define snd_soc_16_8_read_i2c NULL +#endif + +static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[3]; + u16 rval = cpu_to_be16(reg); + + memcpy(data, &rval, sizeof(rval)); + data[2] = value; + + return do_hw_write(codec, reg, value, data, 3); +} + +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, + unsigned int r) +{ + u16 reg = cpu_to_be16(r); + u16 data; + int ret; + + ret = do_i2c_read(codec, ®, 2, &data, 2); + if (ret < 0) + return 0; + return be16_to_cpu(data); +} +#else +#define snd_soc_16_16_read_i2c NULL +#endif + +static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 data[2]; + + data[0] = cpu_to_be16(reg); + data[1] = cpu_to_be16(value); + + return do_hw_write(codec, reg, value, data, sizeof(data)); +} + +/* Primitive bulk write support for soc-cache. The data pointed to by + * `data' needs to already be in the form the hardware expects + * including any leading register specific data. Any data written + * through this function will not go through the cache as it only + * handles writing to volatile or out of bounds registers. + */ +static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg, + const void *data, size_t len) +{ + int ret; + + /* To ensure that we don't get out of sync with the cache, check + * whether the base register is volatile or if we've directly asked + * to bypass the cache. Out of bounds registers are considered + * volatile. + */ + if (!codec->cache_bypass + && !snd_soc_codec_volatile_register(codec, reg) + && reg < codec->driver->reg_cache_size) + return -EINVAL; + + switch (codec->control_type) { +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) + case SND_SOC_I2C: + ret = i2c_master_send(codec->control_data, data, len); + break; +#endif +#if defined(CONFIG_SPI_MASTER) + case SND_SOC_SPI: + ret = spi_write(codec->control_data, data, len); + break; +#endif + default: + BUG(); + } + + if (ret == len) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + +static struct { + int addr_bits; + int data_bits; + int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); + unsigned int (*read)(struct snd_soc_codec *, unsigned int); + unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); +} io_types[] = { + { + .addr_bits = 4, .data_bits = 12, + .write = snd_soc_4_12_write, + }, + { + .addr_bits = 7, .data_bits = 9, + .write = snd_soc_7_9_write, + }, + { + .addr_bits = 8, .data_bits = 8, + .write = snd_soc_8_8_write, + .i2c_read = snd_soc_8_8_read_i2c, + }, + { + .addr_bits = 8, .data_bits = 16, + .write = snd_soc_8_16_write, + .i2c_read = snd_soc_8_16_read_i2c, + }, + { + .addr_bits = 16, .data_bits = 8, + .write = snd_soc_16_8_write, + .i2c_read = snd_soc_16_8_read_i2c, + }, + { + .addr_bits = 16, .data_bits = 16, + .write = snd_soc_16_16_write, + .i2c_read = snd_soc_16_16_read_i2c, + }, +}; + +/** + * snd_soc_codec_set_cache_io: Set up standard I/O functions. + * + * @codec: CODEC to configure. + * @addr_bits: Number of bits of register address data. + * @data_bits: Number of bits of data per register. + * @control: Control bus used. + * + * Register formats are frequently shared between many I2C and SPI + * devices. In order to promote code reuse the ASoC core provides + * some standard implementations of CODEC read and write operations + * which can be set up using this function. + * + * The caller is responsible for allocating and initialising the + * actual cache. + * + * Note that at present this code cannot be used by CODECs with + * volatile registers. + */ +int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, + int addr_bits, int data_bits, + enum snd_soc_control_type control) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(io_types); i++) + if (io_types[i].addr_bits == addr_bits && + io_types[i].data_bits == data_bits) + break; + if (i == ARRAY_SIZE(io_types)) { + printk(KERN_ERR + "No I/O functions for %d bit address %d bit data\n", + addr_bits, data_bits); + return -EINVAL; + } + + codec->write = io_types[i].write; + codec->read = hw_read; + codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; + + switch (control) { + case SND_SOC_CUSTOM: + break; + + case SND_SOC_I2C: +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) + codec->hw_write = (hw_write_t)i2c_master_send; +#endif + if (io_types[i].i2c_read) + codec->hw_read = io_types[i].i2c_read; + + codec->control_data = container_of(codec->dev, + struct i2c_client, + dev); + break; + + case SND_SOC_SPI: +#ifdef CONFIG_SPI_MASTER + codec->hw_write = do_spi_write; +#endif + + codec->control_data = container_of(codec->dev, + struct spi_device, + dev); + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); + -- cgit v1.2.3 From bf3a9e137cf1a1c664f44acfa36a487f0437f6aa Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jun 2011 16:42:29 +0100 Subject: ASoC: Add weak routes for sidetone style paths Normally DAPM will power up any connected audio path. This is not ideal for sidetone paths as with sidetone paths the audio path is not wanted in itself, it is only desired if the two paths it provides a sidetone between are both active. If the sidetone path causes a power up then it can be hard to minimise pops as we first power up either the sidetone or the main output path and then power the other, with the second power up potentially introducing a DC offset. Address this by introducing the concept of a weak path. If a path is marked as weak then DAPM will ignore that path when walking the graph, though all the relevant controls are still available to the application layer to allow these paths to be configured. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/soc-dapm.h | 2 ++ sound/soc/soc-dapm.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 7415878c8b37..7c5465b14d33 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -348,6 +348,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); +int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_route *route, int num); /* dapm events */ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index fd2d774797bb..746349faf2db 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -593,6 +593,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) } list_for_each_entry(path, &widget->sinks, list_source) { + if (path->weak) + continue; + if (path->walked) continue; @@ -643,6 +646,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) } list_for_each_entry(path, &widget->sources, list_sink) { + if (path->weak) + continue; + if (path->walked) continue; @@ -724,6 +730,9 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) /* Check if one of our outputs is connected */ list_for_each_entry(path, &w->sinks, list_source) { + if (path->weak) + continue; + if (path->connected && !path->connected(path->source, path->sink)) continue; @@ -1806,6 +1815,84 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); +static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_route *route) +{ + struct snd_soc_dapm_widget *source = dapm_find_widget(dapm, + route->source, + true); + struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm, + route->sink, + true); + struct snd_soc_dapm_path *path; + int count = 0; + + if (!source) { + dev_err(dapm->dev, "Unable to find source %s for weak route\n", + route->source); + return -ENODEV; + } + + if (!sink) { + dev_err(dapm->dev, "Unable to find sink %s for weak route\n", + route->sink); + return -ENODEV; + } + + if (route->control || route->connected) + dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n", + route->source, route->sink); + + list_for_each_entry(path, &source->sinks, list_source) { + if (path->sink == sink) { + path->weak = 1; + count++; + } + } + + if (count == 0) + dev_err(dapm->dev, "No path found for weak route %s->%s\n", + route->source, route->sink); + if (count > 1) + dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n", + count, route->source, route->sink); + + return 0; +} + +/** + * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak + * @dapm: DAPM context + * @route: audio routes + * @num: number of routes + * + * Mark existing routes matching those specified in the passed array + * as being weak, meaning that they are ignored for the purpose of + * power decisions. The main intended use case is for sidetone paths + * which couple audio between other independent paths if they are both + * active in order to make the combination work better at the user + * level but which aren't intended to be "used". + * + * Note that CODEC drivers should not use this as sidetone type paths + * can frequently also be used as bypass paths. + */ +int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_route *route, int num) +{ + int i, err; + int ret = 0; + + for (i = 0; i < num; i++) { + err = snd_soc_dapm_weak_route(dapm, route); + if (err) + ret = err; + route++; + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); + /** * snd_soc_dapm_new_widgets - add new dapm widgets * @dapm: DAPM context -- cgit v1.2.3 From 223157121404a7ca4deaf2aa31a57cad8d133d07 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jun 2011 18:44:52 +0100 Subject: ASoC: Don't use codec->control_data in bulk write In order to facilitate merging with the register map I/O replace the use of control_data for the bulk writes with direct lookup of the client data from the device. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 855e5cde2793..df9338aa1a52 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -269,12 +269,12 @@ static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int r switch (codec->control_type) { #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) case SND_SOC_I2C: - ret = i2c_master_send(codec->control_data, data, len); + ret = i2c_master_send(to_i2c_client(codec->dev), data, len); break; #endif #if defined(CONFIG_SPI_MASTER) case SND_SOC_SPI: - ret = spi_write(codec->control_data, data, len); + ret = spi_write(to_spi_device(codec->dev), data, len); break; #endif default: -- cgit v1.2.3 From e9c039052be59753e6bcc7c8b59763899dc1161c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jun 2011 19:05:58 +0100 Subject: ASoC: Remove unused and about to be broken SND_SOC_CUSTOM I/O bus This will be removed in -next so let's drop it from mainline as soon as we can in order to minimise surprises. Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +-- sound/soc/soc-cache.c | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index f1de3e0c75bc..3a4bd3a3c68d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -248,8 +248,7 @@ typedef int (*hw_write_t)(void *,const char* ,int); extern struct snd_ac97_bus_ops soc_ac97_ops; enum snd_soc_control_type { - SND_SOC_CUSTOM = 1, - SND_SOC_I2C, + SND_SOC_I2C = 1, SND_SOC_SPI, }; diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index c005ceb70c9d..039b9532b270 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -409,9 +409,6 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; switch (control) { - case SND_SOC_CUSTOM: - break; - case SND_SOC_I2C: #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) codec->hw_write = (hw_write_t)i2c_master_send; -- cgit v1.2.3 From 169d5a83f687c37104d51cbaa639bdffca8a1cd3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 14 Jun 2011 09:51:50 +0100 Subject: ASoC: Fix mismerge with release branch Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 7c5465b14d33..602024d4c459 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -431,6 +431,7 @@ struct snd_soc_dapm_path { /* status */ u32 connect:1; /* source and sink widgets are connected */ u32 walked:1; /* path has been walked */ + u32 weak:1; /* path ignored for power management */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); -- cgit v1.2.3 From 0445bdf4ae2a1a3f4ac71ba6c298f3517b9ed238 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 13 Jun 2011 19:37:36 +0100 Subject: ASoC: dapm - Refactor widget IO functions in preparation for platform widgets. This time with soc_widget_update_bits reflecting recent soc_update_bits changes. Currently widget IO is tightly coupled to the CODEC drivers. Future platform DSP devices have mixer components that can alter power usage and hence require full DAPM support. This provides a generic widget IO operation wrapper in preparation for future patches that implement platform driver DAPM. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 746349faf2db..605c225c709a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -124,6 +124,43 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); } +static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) +{ + if (w->codec) + return snd_soc_read(w->codec, reg); + return 0; +} + +static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) +{ + if (w->codec) + return snd_soc_write(w->codec, reg, val); + return 0; +} + +static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, + unsigned short reg, unsigned int mask, unsigned int value) +{ + int change; + unsigned int old, new; + int ret; + + ret = soc_widget_read(w, reg); + if (ret < 0) + return ret; + + old = ret; + new = (old & ~mask) | (value & mask); + change = old != new; + if (change) { + ret = soc_widget_write(w, reg, new); + if (ret < 0) + return ret; + } + + return change; +} + /** * snd_soc_dapm_set_bias_level - set the bias level for the system * @dapm: DAPM context @@ -181,7 +218,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - val = snd_soc_read(w->codec, reg); + val = soc_widget_read(w, reg); val = (val >> shift) & mask; if ((invert && !val) || (!invert && val)) @@ -197,7 +234,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, for (bitmask = 1; bitmask < e->max; bitmask <<= 1) ; - val = snd_soc_read(w->codec, e->reg); + val = soc_widget_read(w, e->reg); item = (val >> e->shift_l) & (bitmask - 1); p->connect = 0; @@ -227,7 +264,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, w->kcontrol_news[i].private_value; int val, item; - val = snd_soc_read(w->codec, e->reg); + val = soc_widget_read(w, e->reg); val = (val >> e->shift_l) & e->mask; for (item = 0; item < e->max; item++) { if (val == e->values[item]) @@ -674,7 +711,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, else val = w->off_val; - snd_soc_update_bits(w->codec, -(w->reg + 1), + soc_widget_update_bits(w, -(w->reg + 1), w->mask << w->shift, val << w->shift); return 0; @@ -885,7 +922,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, "pop test : Applying 0x%x/0x%x to %x in %dms\n", value, mask, reg, card->pop_time); pop_wait(card->pop_time); - snd_soc_update_bits(dapm->codec, reg, mask, value); + soc_widget_update_bits(w, reg, mask, value); } list_for_each_entry(w, pending, power_list) { @@ -1964,7 +2001,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) /* Read the initial power state from the device */ if (w->reg >= 0) { - val = snd_soc_read(w->codec, w->reg); + val = soc_widget_read(w, w->reg); val &= 1 << w->shift; if (w->invert) val = !val; -- cgit v1.2.3 From b83e60c000d6e6fbc602cfbf6788e65f1e2c0c7e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jun 2011 17:50:18 +0100 Subject: ASoC: Clean up some coding style nits in the bf5xx-i2s-pcm driver Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/blackfin/bf5xx-i2s-pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 96d0d9060768..4a805a859723 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -159,7 +159,7 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); - ret = snd_pcm_hw_constraint_integer(runtime, \ + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; @@ -297,8 +297,8 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev) static struct platform_driver bfin_i2s_pcm_driver = { .driver = { - .name = "bfin-i2s-pcm-audio", - .owner = THIS_MODULE, + .name = "bfin-i2s-pcm-audio", + .owner = THIS_MODULE, }, .probe = bfin_i2s_soc_platform_probe, -- cgit v1.2.3 From 631ed8a2134dae17d9e17f3c35c7290720f85199 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jun 2011 15:26:20 +0200 Subject: ASoC: Add ADAU1701 codec driver This patch adds support for the Analog Devices ADAU1701 SigmaDSP. Signed-off-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 +- sound/soc/codecs/Makefile | 2 + sound/soc/codecs/adau1701.c | 548 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/adau1701.h | 17 ++ 4 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/adau1701.c create mode 100644 sound/soc/codecs/adau1701.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 98175a096df2..f745e557831e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI select SND_SOC_AD1980 if SND_SOC_AC97_BUS select SND_SOC_AD73311 + select SND_SOC_ADAU1701 if I2C select SND_SOC_ADS117X select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C @@ -130,7 +131,11 @@ config SND_SOC_AD1980 config SND_SOC_AD73311 tristate - + +config SND_SOC_ADAU1701 + select SIGMA + tristate + config SND_SOC_ADS117X tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fd8558406ef0..30a4c631aef4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -4,6 +4,7 @@ snd-soc-ad1836-objs := ad1836.o snd-soc-ad193x-objs := ad193x.o snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o +snd-soc-adau1701-objs := adau1701.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o @@ -95,6 +96,7 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o +obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c new file mode 100644 index 000000000000..6c01bb649123 --- /dev/null +++ b/sound/soc/codecs/adau1701.c @@ -0,0 +1,548 @@ +/* + * Driver for ADAU1701 SigmaDSP processor + * + * Copyright 2011 Analog Devices Inc. + * Author: Lars-Peter Clausen + * based on an inital version by Cliff Cai + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adau1701.h" + +#define ADAU1701_DSPCTRL 0x1c +#define ADAU1701_SEROCTL 0x1e +#define ADAU1701_SERICTL 0x1f + +#define ADAU1701_AUXNPOW 0x22 + +#define ADAU1701_OSCIPOW 0x26 +#define ADAU1701_DACSET 0x27 + +#define ADAU1701_NUM_REGS 0x28 + +#define ADAU1701_DSPCTRL_CR (1 << 2) +#define ADAU1701_DSPCTRL_DAM (1 << 3) +#define ADAU1701_DSPCTRL_ADM (1 << 4) +#define ADAU1701_DSPCTRL_SR_48 0x00 +#define ADAU1701_DSPCTRL_SR_96 0x01 +#define ADAU1701_DSPCTRL_SR_192 0x02 +#define ADAU1701_DSPCTRL_SR_MASK 0x03 + +#define ADAU1701_SEROCTL_INV_LRCLK 0x2000 +#define ADAU1701_SEROCTL_INV_BCLK 0x1000 +#define ADAU1701_SEROCTL_MASTER 0x0800 + +#define ADAU1701_SEROCTL_OBF16 0x0000 +#define ADAU1701_SEROCTL_OBF8 0x0200 +#define ADAU1701_SEROCTL_OBF4 0x0400 +#define ADAU1701_SEROCTL_OBF2 0x0600 +#define ADAU1701_SEROCTL_OBF_MASK 0x0600 + +#define ADAU1701_SEROCTL_OLF1024 0x0000 +#define ADAU1701_SEROCTL_OLF512 0x0080 +#define ADAU1701_SEROCTL_OLF256 0x0100 +#define ADAU1701_SEROCTL_OLF_MASK 0x0180 + +#define ADAU1701_SEROCTL_MSB_DEALY1 0x0000 +#define ADAU1701_SEROCTL_MSB_DEALY0 0x0004 +#define ADAU1701_SEROCTL_MSB_DEALY8 0x0008 +#define ADAU1701_SEROCTL_MSB_DEALY12 0x000c +#define ADAU1701_SEROCTL_MSB_DEALY16 0x0010 +#define ADAU1701_SEROCTL_MSB_DEALY_MASK 0x001c + +#define ADAU1701_SEROCTL_WORD_LEN_24 0x0000 +#define ADAU1701_SEROCTL_WORD_LEN_20 0x0001 +#define ADAU1701_SEROCTL_WORD_LEN_16 0x0010 +#define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003 + +#define ADAU1701_AUXNPOW_VBPD 0x40 +#define ADAU1701_AUXNPOW_VRPD 0x20 + +#define ADAU1701_SERICTL_I2S 0 +#define ADAU1701_SERICTL_LEFTJ 1 +#define ADAU1701_SERICTL_TDM 2 +#define ADAU1701_SERICTL_RIGHTJ_24 3 +#define ADAU1701_SERICTL_RIGHTJ_20 4 +#define ADAU1701_SERICTL_RIGHTJ_18 5 +#define ADAU1701_SERICTL_RIGHTJ_16 6 +#define ADAU1701_SERICTL_MODE_MASK 7 +#define ADAU1701_SERICTL_INV_BCLK BIT(3) +#define ADAU1701_SERICTL_INV_LRCLK BIT(4) + +#define ADAU1701_OSCIPOW_OPD 0x04 +#define ADAU1701_DACSET_DACINIT 1 + +#define ADAU1701_FIRMWARE "adau1701.bin" + +struct adau1701 { + unsigned int dai_fmt; +}; + +static const struct snd_kcontrol_new adau1701_controls[] = { + SOC_SINGLE("Master Capture Switch", ADAU1701_DSPCTRL, 4, 1, 0), +}; + +static const struct snd_soc_dapm_widget adau1701_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC0", "Playback", ADAU1701_AUXNPOW, 3, 1), + SND_SOC_DAPM_DAC("DAC1", "Playback", ADAU1701_AUXNPOW, 2, 1), + SND_SOC_DAPM_DAC("DAC2", "Playback", ADAU1701_AUXNPOW, 1, 1), + SND_SOC_DAPM_DAC("DAC3", "Playback", ADAU1701_AUXNPOW, 0, 1), + SND_SOC_DAPM_ADC("ADC", "Capture", ADAU1701_AUXNPOW, 7, 1), + + SND_SOC_DAPM_OUTPUT("OUT0"), + SND_SOC_DAPM_OUTPUT("OUT1"), + SND_SOC_DAPM_OUTPUT("OUT2"), + SND_SOC_DAPM_OUTPUT("OUT3"), + SND_SOC_DAPM_INPUT("IN0"), + SND_SOC_DAPM_INPUT("IN1"), +}; + +static const struct snd_soc_dapm_route adau1701_dapm_routes[] = { + { "OUT0", NULL, "DAC0" }, + { "OUT1", NULL, "DAC1" }, + { "OUT2", NULL, "DAC2" }, + { "OUT3", NULL, "DAC3" }, + + { "ADC", NULL, "IN0" }, + { "ADC", NULL, "IN1" }, +}; + +static unsigned int adau1701_register_size(struct snd_soc_codec *codec, + unsigned int reg) +{ + switch (reg) { + case ADAU1701_DSPCTRL: + case ADAU1701_SEROCTL: + case ADAU1701_AUXNPOW: + case ADAU1701_OSCIPOW: + case ADAU1701_DACSET: + return 2; + case ADAU1701_SERICTL: + return 1; + } + + dev_err(codec->dev, "Unsupported register address: %d\n", reg); + return 0; +} + +static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + unsigned int i, ret; + unsigned int size; + uint8_t buf[4]; + + size = adau1701_register_size(codec, reg); + if (size == 0) + return -EINVAL; + + snd_soc_cache_write(codec, reg, value); + + buf[0] = 0x08; + buf[1] = reg; + + for (i = size + 1; i >= 2; --i) { + buf[i] = value; + value >>= 8; + } + + ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2); + if (ret == size + 2) + return 0; + else if (ret < 0) + return ret; + else + return -EIO; +} + +static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg) +{ + unsigned int value; + unsigned int ret; + + ret = snd_soc_cache_read(codec, reg, &value); + if (ret) + return ret; + + return value; +} + +static int adau1701_load_firmware(struct snd_soc_codec *codec) +{ + return process_sigma_firmware(codec->control_data, ADAU1701_FIRMWARE); +} + +static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec, + snd_pcm_format_t format) +{ + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK; + unsigned int val; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + val = ADAU1701_SEROCTL_WORD_LEN_16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val = ADAU1701_SEROCTL_WORD_LEN_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val = ADAU1701_SEROCTL_WORD_LEN_24; + break; + default: + return -EINVAL; + } + + if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) { + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + val |= ADAU1701_SEROCTL_MSB_DEALY16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val |= ADAU1701_SEROCTL_MSB_DEALY12; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val |= ADAU1701_SEROCTL_MSB_DEALY8; + break; + } + mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK; + } + + snd_soc_update_bits(codec, ADAU1701_SEROCTL, mask, val); + + return 0; +} + +static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec, + snd_pcm_format_t format) +{ + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + unsigned int val; + + if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) + return 0; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + val = ADAU1701_SERICTL_RIGHTJ_16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val = ADAU1701_SERICTL_RIGHTJ_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val = ADAU1701_SERICTL_RIGHTJ_24; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, ADAU1701_SERICTL, + ADAU1701_SERICTL_MODE_MASK, val); + + return 0; +} + +static int adau1701_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + snd_pcm_format_t format; + unsigned int val; + + switch (params_rate(params)) { + case 192000: + val = ADAU1701_DSPCTRL_SR_192; + break; + case 96000: + val = ADAU1701_DSPCTRL_SR_96; + break; + case 48000: + val = ADAU1701_DSPCTRL_SR_48; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, ADAU1701_DSPCTRL, + ADAU1701_DSPCTRL_SR_MASK, val); + + format = params_format(params); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return adau1701_set_playback_pcm_format(codec, format); + else + return adau1701_set_capture_pcm_format(codec, format); +} + +static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + unsigned int serictl = 0x00, seroctl = 0x00; + bool invert_lrclk; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + /* master, 64-bits per sample, 1 frame per sample */ + seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16 + | ADAU1701_SEROCTL_OLF1024; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + invert_lrclk = false; + break; + case SND_SOC_DAIFMT_NB_IF: + invert_lrclk = true; + break; + case SND_SOC_DAIFMT_IB_NF: + invert_lrclk = false; + serictl |= ADAU1701_SERICTL_INV_BCLK; + seroctl |= ADAU1701_SEROCTL_INV_BCLK; + break; + case SND_SOC_DAIFMT_IB_IF: + invert_lrclk = true; + serictl |= ADAU1701_SERICTL_INV_BCLK; + seroctl |= ADAU1701_SEROCTL_INV_BCLK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + serictl |= ADAU1701_SERICTL_LEFTJ; + seroctl |= ADAU1701_SEROCTL_MSB_DEALY0; + invert_lrclk = !invert_lrclk; + break; + case SND_SOC_DAIFMT_RIGHT_J: + serictl |= ADAU1701_SERICTL_RIGHTJ_24; + seroctl |= ADAU1701_SEROCTL_MSB_DEALY8; + invert_lrclk = !invert_lrclk; + break; + default: + return -EINVAL; + } + + if (invert_lrclk) { + seroctl |= ADAU1701_SEROCTL_INV_LRCLK; + serictl |= ADAU1701_SERICTL_INV_LRCLK; + } + + adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + + snd_soc_write(codec, ADAU1701_SERICTL, serictl); + snd_soc_update_bits(codec, ADAU1701_SEROCTL, + ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl); + + return 0; +} + +static int adau1701_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + /* Enable VREF and VREF buffer */ + snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, 0x00); + break; + case SND_SOC_BIAS_OFF: + /* Disable VREF and VREF buffer */ + snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, mask); + break; + } + + codec->dapm.bias_level = level; + return 0; +} + +static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int mask = ADAU1701_DSPCTRL_DAM; + unsigned int val; + + if (mute) + val = 0; + else + val = mask; + + snd_soc_update_bits(codec, ADAU1701_DSPCTRL, mask, val); + + return 0; +} + +static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, + unsigned int freq, int dir) +{ + unsigned int val; + + switch (clk_id) { + case ADAU1701_CLK_SRC_OSC: + val = 0x0; + break; + case ADAU1701_CLK_SRC_MCLK: + val = ADAU1701_OSCIPOW_OPD; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); + + return 0; +} + +#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_192000) + +#define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops adau1701_dai_ops = { + .set_fmt = adau1701_set_dai_fmt, + .hw_params = adau1701_hw_params, + .digital_mute = adau1701_digital_mute, +}; + +static struct snd_soc_dai_driver adau1701_dai = { + .name = "adau1701", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 8, + .rates = ADAU1701_RATES, + .formats = ADAU1701_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = ADAU1701_RATES, + .formats = ADAU1701_FORMATS, + }, + .ops = &adau1701_dai_ops, + .symmetric_rates = 1, +}; + +static int adau1701_probe(struct snd_soc_codec *codec) +{ + int ret; + + codec->dapm.idle_bias_off = 1; + + ret = adau1701_load_firmware(codec); + if (ret) + dev_warn(codec->dev, "Failed to load firmware\n"); + + snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); + snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR); + + return 0; +} + +static struct snd_soc_codec_driver adau1701_codec_drv = { + .probe = adau1701_probe, + .set_bias_level = adau1701_set_bias_level, + + .reg_cache_size = ADAU1701_NUM_REGS, + .reg_word_size = sizeof(u16), + + .controls = adau1701_controls, + .num_controls = ARRAY_SIZE(adau1701_controls), + .dapm_widgets = adau1701_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(adau1701_dapm_widgets), + .dapm_routes = adau1701_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), + + .write = adau1701_write, + .read = adau1701_read, + + .set_sysclk = adau1701_set_sysclk, +}; + +static __devinit int adau1701_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adau1701 *adau1701; + int ret; + + adau1701 = kzalloc(sizeof(*adau1701), GFP_KERNEL); + if (!adau1701) + return -ENOMEM; + + i2c_set_clientdata(client, adau1701); + ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, + &adau1701_dai, 1); + if (ret < 0) + kfree(adau1701); + + return ret; +} + +static __devexit int adau1701_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + kfree(i2c_get_clientdata(client)); + return 0; +} + +static const struct i2c_device_id adau1701_i2c_id[] = { + { "adau1701", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id); + +static struct i2c_driver adau1701_i2c_driver = { + .driver = { + .name = "adau1701", + .owner = THIS_MODULE, + }, + .probe = adau1701_i2c_probe, + .remove = __devexit_p(adau1701_i2c_remove), + .id_table = adau1701_i2c_id, +}; + +static int __init adau1701_init(void) +{ + return i2c_add_driver(&adau1701_i2c_driver); +} +module_init(adau1701_init); + +static void __exit adau1701_exit(void) +{ + i2c_del_driver(&adau1701_i2c_driver); +} +module_exit(adau1701_exit); + +MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver"); +MODULE_AUTHOR("Cliff Cai "); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/adau1701.h b/sound/soc/codecs/adau1701.h new file mode 100644 index 000000000000..8d0949a2aec9 --- /dev/null +++ b/sound/soc/codecs/adau1701.h @@ -0,0 +1,17 @@ +/* + * header file for ADAU1701 SigmaDSP processor + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _ADAU1701_H +#define _ADAU1701_H + +enum adau1701_clk_src { + ADAU1701_CLK_SRC_OSC, + ADAU1701_CLK_SRC_MCLK, +}; + +#endif -- cgit v1.2.3 From 53a93d58fbcfca5c40ff58f8ced421293bfcbc2a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jun 2011 15:26:21 +0200 Subject: ASoC: Blackfin: Add bf5xx-adau1701 machine driver Add a machine driver to support the ADAU1701 SigmaDSP processors on Analog Devices BF5XX evaluation boards. Signed-off-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 11 +++ sound/soc/blackfin/Makefile | 2 + sound/soc/blackfin/bfin-eval-adau1701.c | 139 ++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 sound/soc/blackfin/bfin-eval-adau1701.c diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index ae403597fd31..30706235ba04 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -17,6 +17,17 @@ config SND_BF5XX_SOC_SSM2602 help Say Y if you want to add support for SoC audio on BF527-EZKIT. +config SND_SOC_BFIN_EVAL_ADAU1701 + tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" + depends on SND_BF5XX_I2S + select SND_BF5XX_SOC_I2S + select SND_SOC_ADAU1701 + select I2C + help + Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ + board connected to one of the Blackfin evaluation boards like the + BF5XX-STAMP or BF5XX-EZKIT. + config SND_BF5XX_SOC_AD73311 tristate "SoC AD73311 Audio support for Blackfin" depends on SND_BF5XX_I2S diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index 49af3f32aec8..f01bff63177d 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile @@ -21,9 +21,11 @@ snd-ad1980-objs := bf5xx-ad1980.o snd-ssm2602-objs := bf5xx-ssm2602.o snd-ad73311-objs := bf5xx-ad73311.o snd-ad193x-objs := bf5xx-ad193x.o +snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o +obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o diff --git a/sound/soc/blackfin/bfin-eval-adau1701.c b/sound/soc/blackfin/bfin-eval-adau1701.c new file mode 100644 index 000000000000..e5550acba2c2 --- /dev/null +++ b/sound/soc/blackfin/bfin-eval-adau1701.c @@ -0,0 +1,139 @@ +/* + * Machine driver for EVAL-ADAU1701MINIZ on Analog Devices bfin + * evaluation boards. + * + * Copyright 2011 Analog Devices Inc. + * Author: Lars-Peter Clausen + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include + +#include "../codecs/adau1701.h" + +static const struct snd_soc_dapm_widget bfin_eval_adau1701_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static const struct snd_soc_dapm_route bfin_eval_adau1701_dapm_routes[] = { + { "Speaker", NULL, "OUT0" }, + { "Speaker", NULL, "OUT1" }, + { "Line Out", NULL, "OUT2" }, + { "Line Out", NULL, "OUT3" }, + + { "IN0", NULL, "Line In" }, + { "IN1", NULL, "Line In" }, +}; + +static int bfin_eval_adau1701_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + if (ret) + return ret; + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + if (ret) + return ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000, + SND_SOC_CLOCK_IN); + + return ret; +} + +static struct snd_soc_ops bfin_eval_adau1701_ops = { + .hw_params = bfin_eval_adau1701_hw_params, +}; + +static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = { + { + .name = "adau1701", + .stream_name = "adau1701", + .cpu_dai_name = "bfin-i2s.0", + .codec_dai_name = "adau1701", + .platform_name = "bfin-i2s-pcm-audio", + .codec_name = "adau1701.0-0034", + .ops = &bfin_eval_adau1701_ops, + }, + { + .name = "adau1701", + .stream_name = "adau1701", + .cpu_dai_name = "bfin-i2s.1", + .codec_dai_name = "adau1701", + .platform_name = "bfin-i2s-pcm-audio", + .codec_name = "adau1701.0-0034", + .ops = &bfin_eval_adau1701_ops, + }, +}; + +static struct snd_soc_card bfin_eval_adau1701 = { + .name = "bfin-eval-adau1701", + .dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM], + .num_links = 1, + + .dapm_widgets = bfin_eval_adau1701_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1701_dapm_widgets), + .dapm_routes = bfin_eval_adau1701_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1701_dapm_routes), +}; + +static int bfin_eval_adau1701_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &bfin_eval_adau1701; + + card->dev = &pdev->dev; + + return snd_soc_register_card(&bfin_eval_adau1701); +} + +static int __devexit bfin_eval_adau1701_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + return 0; +} + +static struct platform_driver bfin_eval_adau1701_driver = { + .driver = { + .name = "bfin-eval-adau1701", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = bfin_eval_adau1701_probe, + .remove = __devexit_p(bfin_eval_adau1701_remove), +}; + +static int __init bfin_eval_adau1701_init(void) +{ + return platform_driver_register(&bfin_eval_adau1701_driver); +} +module_init(bfin_eval_adau1701_init); + +static void __exit bfin_eval_adau1701_exit(void) +{ + platform_driver_unregister(&bfin_eval_adau1701_driver); +} +module_exit(bfin_eval_adau1701_exit); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bfin-eval-adau1701"); -- cgit v1.2.3 From 42f32c559131921f3bb014e0ac2107345f14887c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 15 Jun 2011 15:29:23 -0400 Subject: ASoC: AD1836: clean up comment headers Signed-off-by: Mike Frysinger Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 19 +++++-------------- sound/soc/codecs/ad1836.h | 17 ++++------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index e3a9493e3ced..ff8e73850ed5 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -1,19 +1,10 @@ -/* - * File: sound/soc/codecs/ad1836.c - * Author: Barry Song - * - * Created: Aug 04 2009 - * Description: Driver for AD1836 sound chip - * - * Modified: - * Copyright 2009 Analog Devices Inc. + /* + * Audio Codec driver supporting: + * AD1835A, AD1836, AD1837A, AD1838A, AD1839A * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * Copyright 2009-2011 Analog Devices Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Licensed under the GPL-2 or later. */ #include diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h index f13402fe7333..18d5f2f62d92 100644 --- a/sound/soc/codecs/ad1836.h +++ b/sound/soc/codecs/ad1836.h @@ -1,19 +1,10 @@ /* - * File: sound/soc/codecs/ad1836.h - * Based on: - * Author: Barry Song + * Audio Codec driver supporting: + * AD1835A, AD1836, AD1837A, AD1838A, AD1839A * - * Created: Aug 04, 2009 - * Description: definitions for AD1836 registers + * Copyright 2009-2011 Analog Devices Inc. * - * Modified: - * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Licensed under the GPL-2 or later. */ #ifndef __AD1836_H__ -- cgit v1.2.3 From 15e870512956a1e573d033b3bb6ffbf3237e9723 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 15 Jun 2011 15:29:19 -0400 Subject: ASoC: AD1836: drop unnecessary spi register check The only thing the init func does is register a spi driver, so if that fails, we return the value back up to the caller who will display an error message for us. So drop the redundant checking/message. Signed-off-by: Mike Frysinger Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index ff8e73850ed5..e8a986f84c13 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -385,15 +385,7 @@ static struct spi_driver ad1836_spi_driver = { static int __init ad1836_init(void) { - int ret; - - ret = spi_register_driver(&ad1836_spi_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register ad1836 SPI driver: %d\n", - ret); - } - - return ret; + return spi_register_driver(&ad1836_spi_driver); } module_init(ad1836_init); -- cgit v1.2.3 From d4d80f5e46872b947357b44cf75d3e9fe97789d8 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 15 Jun 2011 15:29:20 -0400 Subject: ASoC: AD1836: fix intermixed tab/space indentation Signed-off-by: Mike Frysinger Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 4 ++-- sound/soc/codecs/ad1836.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index e8a986f84c13..816b85293e67 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -322,8 +322,8 @@ static int ad1836_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { - .probe = ad1836_probe, - .remove = ad1836_remove, + .probe = ad1836_probe, + .remove = ad1836_remove, .suspend = ad1836_soc_suspend, .resume = ad1836_soc_resume, .reg_cache_size = AD1836_NUM_REGS, diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h index 18d5f2f62d92..444747f0db26 100644 --- a/sound/soc/codecs/ad1836.h +++ b/sound/soc/codecs/ad1836.h @@ -12,7 +12,7 @@ #define AD1836_DAC_CTRL1 0 #define AD1836_DAC_POWERDOWN 2 -#define AD1836_DAC_SERFMT_MASK 0xE0 +#define AD1836_DAC_SERFMT_MASK 0xE0 #define AD1836_DAC_SERFMT_PCK256 (0x4 << 5) #define AD1836_DAC_SERFMT_PCK128 (0x5 << 5) #define AD1836_DAC_WORD_LEN_MASK 0x18 @@ -35,7 +35,7 @@ #define AD1836_ADC_CTRL2 13 #define AD1836_ADC_WORD_LEN_MASK 0x30 #define AD1836_ADC_WORD_OFFSET 5 -#define AD1836_ADC_SERFMT_MASK (7 << 6) +#define AD1836_ADC_SERFMT_MASK (7 << 6) #define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) #define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) #define AD1836_ADC_AUX (0x6 << 6) -- cgit v1.2.3 From 0679059a41413069d887a03c5db1c98dc273d6a3 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 15 Jun 2011 15:29:21 -0400 Subject: ASoC: AD1836: fix codec name The codec name should not have a "-codec" suffix since this is not part of a MFD. This was incorrectly changed during the multi-component updated. Signed-off-by: Mike Frysinger Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 816b85293e67..9cc6123cf7ea 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -375,7 +375,7 @@ MODULE_DEVICE_TABLE(spi, ad1836_ids); static struct spi_driver ad1836_spi_driver = { .driver = { - .name = "ad1836-codec", + .name = "ad1836", .owner = THIS_MODULE, }, .probe = ad1836_spi_probe, -- cgit v1.2.3 From 5d0e7f61702ea562ee8bdea56b475978c4ff08ac Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 15 Jun 2011 15:29:22 -0400 Subject: ASoC: AD1836: rename suspend/resume funcs Use less specific names for suspend/resume to match the probe/remove funcs where these are now used. Signed-off-by: Barry Song Signed-off-by: Scott Jiang Signed-off-by: Mike Frysinger Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 9cc6123cf7ea..4e5c5726366b 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -189,26 +189,6 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, return 0; } -#ifdef CONFIG_PM -static int ad1836_soc_suspend(struct snd_soc_codec *codec, - pm_message_t state) -{ - /* reset clock control mode */ - return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, - AD1836_ADC_SERFMT_MASK, 0); -} - -static int ad1836_soc_resume(struct snd_soc_codec *codec) -{ - /* restore clock control mode */ - return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, - AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX); -} -#else -#define ad1836_soc_suspend NULL -#define ad1836_soc_resume NULL -#endif - static struct snd_soc_dai_ops ad1836_dai_ops = { .hw_params = ad1836_hw_params, .set_fmt = ad1836_set_dai_fmt, @@ -242,6 +222,25 @@ static struct snd_soc_dai_driver ad183x_dais[] = { [AD1838] = AD183X_DAI("ad1838", 3, 1), }; +#ifdef CONFIG_PM +static int ad1836_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + /* reset clock control mode */ + return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, + AD1836_ADC_SERFMT_MASK, 0); +} + +static int ad1836_resume(struct snd_soc_codec *codec) +{ + /* restore clock control mode */ + return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, + AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX); +} +#else +#define ad1836_suspend NULL +#define ad1836_resume NULL +#endif + static int ad1836_probe(struct snd_soc_codec *codec) { struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); @@ -324,8 +323,8 @@ static int ad1836_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { .probe = ad1836_probe, .remove = ad1836_remove, - .suspend = ad1836_soc_suspend, - .resume = ad1836_soc_resume, + .suspend = ad1836_suspend, + .resume = ad1836_resume, .reg_cache_size = AD1836_NUM_REGS, .reg_word_size = sizeof(u16), -- cgit v1.2.3 From 4d1e46b7eff7e876cbbaa34ef238c9ac97973e56 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 16 Jun 2011 22:24:15 -0400 Subject: ASoC: Blackfin: allow SPI for SSM2602 parts This board has hardware switches for selecting SPI or I2C, so don't require I2C for this driver. Signed-off-by: Mike Frysinger Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 30706235ba04..fa6a6d2abffc 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -10,10 +10,9 @@ config SND_BF5XX_I2S config SND_BF5XX_SOC_SSM2602 tristate "SoC SSM2602 Audio support for BF52x ezkit" - depends on SND_BF5XX_I2S + depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) select SND_BF5XX_SOC_I2S select SND_SOC_SSM2602 - select I2C help Say Y if you want to add support for SoC audio on BF527-EZKIT. -- cgit v1.2.3 From 39c9d199ce6735513e13ec1b2d558e9d34762c50 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 17 Jun 2011 11:22:27 +0100 Subject: ASoC: Add adau* drivers to the Analog Devices file patterns Signed-off-by: Mark Brown Acked-by: Liam Girdwood Acked-by: Mike Frysinger --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 29801f760b6f..2406e0d8e807 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -533,6 +533,7 @@ L: device-drivers-devel@blackfin.uclinux.org L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://wiki.analog.com/ S: Supported +F: sound/soc/codecs/adau* F: sound/soc/codecs/ad1* F: sound/soc/codecs/ssm* -- cgit v1.2.3 From ee8c7e9744882b2cac8886384f156095b12d046d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 18 Jun 2011 15:31:38 +0100 Subject: ASoC: Remove adau1701 from SND_SOC_ALL_CODECS due to Sigma dependency The Sigma code is in drivers/firmware which is only included on a very small subset of architectures and so ends up breaking the build on others. There's a pending patch to make the directory build as standard but it's not merged yet. Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f745e557831e..7a2e4269b255 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -17,7 +17,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI select SND_SOC_AD1980 if SND_SOC_AC97_BUS select SND_SOC_AD73311 - select SND_SOC_ADAU1701 if I2C select SND_SOC_ADS117X select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C -- cgit v1.2.3 From 29376bc7e2bbb745c9ad47e48ca706ac5a24897f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 19 Jun 2011 13:49:28 +0100 Subject: ASoC: Fix DAPM sequence run for per-widget I/O methods Previously we were using the DAPM context rather than a widget as the argument for update_bits() so we didn't need to care that our list walk of widgets left us one beyond the end of the list. Now we're using them for the register update we need to make sure we're pointing at an actual widget not the list_head. Fix originally suggested by Liam on IM. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-dapm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 605c225c709a..ceb2ba44fd3f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -918,6 +918,12 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, } if (reg >= 0) { + /* Any widget will do, they should all be updating the + * same register. + */ + w = list_first_entry(pending, struct snd_soc_dapm_widget, + power_list); + pop_dbg(dapm->dev, card->pop_time, "pop test : Applying 0x%x/0x%x to %x in %dms\n", value, mask, reg, card->pop_time); -- cgit v1.2.3 From c20974090e9093b8b69b37543cba381336c41ab7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 20 Jun 2011 10:11:25 +0300 Subject: ASoC: adau1701: signedness bug in adau1701_write() "ret" is supposed to be signed here. The current code will only return -EIO on error, instead of a more appropriate error code such as -EAGAIN etc. Signed-off-by: Dan Carpenter Acked-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/adau1701.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 6c01bb649123..2758d5fc60d6 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -140,9 +140,10 @@ static unsigned int adau1701_register_size(struct snd_soc_codec *codec, static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - unsigned int i, ret; + unsigned int i; unsigned int size; uint8_t buf[4]; + int ret; size = adau1701_register_size(codec, reg); if (size == 0) -- cgit v1.2.3