From 17be5522f6de1d4920e7d9235bfb0e0c682c6f8f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 15 Oct 2008 19:57:12 +0200 Subject: ALSA: ASoC: Convert wm8580 to a new-style i2c driver Convert the wm8580 codec driver to the new (standard) device driver binding model. Signed-off-by: Jean Delvare Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8580.c | 108 +++++++++++++++++++++++----------------------- sound/soc/codecs/wm8580.h | 1 + 2 files changed, 54 insertions(+), 55 deletions(-) diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 627ebfb4209..cbcd7c324ab 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -900,85 +900,85 @@ static struct snd_soc_device *wm8580_socdev; * low = 0x1a * high = 0x1b */ -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver wm8580_i2c_driver; -static struct i2c_client client_template; - -static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind) +static int wm8580_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct snd_soc_device *socdev = wm8580_socdev; - struct wm8580_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; int ret; - if (addr != setup->i2c_address) - return -ENODEV; - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = i2c_attach_client(i2c); - if (ret < 0) { - dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr); - goto err; - } - ret = wm8580_init(socdev); - if (ret < 0) { + if (ret < 0) dev_err(&i2c->dev, "failed to initialise WM8580\n"); - goto err; - } - - return ret; - -err: - kfree(codec); - kfree(i2c); return ret; } -static int wm8580_i2c_detach(struct i2c_client *client) +static int wm8580_i2c_remove(struct i2c_client *client) { struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); kfree(codec->reg_cache); - kfree(client); return 0; } -static int wm8580_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, wm8580_codec_probe); -} +static const struct i2c_device_id wm8580_i2c_id[] = { + { "wm8580", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); -/* corgi i2c codec control layer */ static struct i2c_driver wm8580_i2c_driver = { .driver = { .name = "WM8580 I2C Codec", .owner = THIS_MODULE, }, - .attach_adapter = wm8580_i2c_attach, - .detach_client = wm8580_i2c_detach, - .command = NULL, + .probe = wm8580_i2c_probe, + .remove = wm8580_i2c_remove, + .id_table = wm8580_i2c_id, }; -static struct i2c_client client_template = { - .name = "WM8580", - .driver = &wm8580_i2c_driver, -}; +static int wm8580_add_i2c_device(struct platform_device *pdev, + const struct wm8580_setup_data *setup) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + int ret; + + ret = i2c_add_driver(&wm8580_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = setup->i2c_address; + strlcpy(info.type, "wm8580", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(setup->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "can't get i2c adapter %d\n", + setup->i2c_bus); + goto err_driver; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + goto err_driver; + } + + return 0; + +err_driver: + i2c_del_driver(&wm8580_i2c_driver); + return -ENODEV; +} #endif static int wm8580_probe(struct platform_device *pdev) @@ -1011,11 +1011,8 @@ static int wm8580_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8580_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); + ret = wm8580_add_i2c_device(pdev, setup); } #else /* Add other interfaces here */ @@ -1034,6 +1031,7 @@ static int wm8580_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_unregister_device(codec->control_data); i2c_del_driver(&wm8580_i2c_driver); #endif kfree(codec->private_data); diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h index 589ddaba21d..09e4422f6f2 100644 --- a/sound/soc/codecs/wm8580.h +++ b/sound/soc/codecs/wm8580.h @@ -29,6 +29,7 @@ #define WM8580_CLKSRC_NONE 5 struct wm8580_setup_data { + int i2c_bus; unsigned short i2c_address; }; -- cgit v1.2.3 From 8ae6a5523f4188dbe2b98a9385f5860df6ee47a3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 15 Oct 2008 19:58:12 +0200 Subject: ALSA: ASoC: Convert wm8900 to a new-style i2c driver Convert the wm8900 codec driver to the new (standard) device driver binding model. Signed-off-by: Jean Delvare Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8900.c | 113 ++++++++++++++++++++++------------------------ sound/soc/codecs/wm8900.h | 1 + 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 3b326c9b558..de016f41e04 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1387,89 +1387,86 @@ static struct snd_soc_device *wm8900_socdev; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; - -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver wm8900_i2c_driver; -static struct i2c_client client_template; - /* If the i2c layer weren't so broken, we could pass this kind of data around */ -static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind) +static int wm8900_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct snd_soc_device *socdev = wm8900_socdev; - struct wm8900_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; int ret; - if (addr != setup->i2c_address) - return -ENODEV; - - dev_err(&adap->dev, "Probe on %x\n", addr); - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = i2c_attach_client(i2c); - if (ret < 0) { - dev_err(&adap->dev, - "failed to attach codec at addr %x\n", addr); - goto err; - } - ret = wm8900_init(socdev); - if (ret < 0) { - dev_err(&adap->dev, "failed to initialise WM8900\n"); - goto err; - } - return ret; - -err: - kfree(codec); - kfree(i2c); + if (ret < 0) + dev_err(&i2c->dev, "failed to initialise WM8900\n"); return ret; } -static int wm8900_i2c_detach(struct i2c_client *client) +static int wm8900_i2c_remove(struct i2c_client *client) { struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); kfree(codec->reg_cache); - kfree(client); return 0; } -static int wm8900_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, wm8900_codec_probe); -} +static const struct i2c_device_id wm8900_i2c_id[] = { + { "wm8900", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); -/* corgi i2c codec control layer */ static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "WM8900 I2C codec", .owner = THIS_MODULE, }, - .attach_adapter = wm8900_i2c_attach, - .detach_client = wm8900_i2c_detach, - .command = NULL, + .probe = wm8900_i2c_probe, + .remove = wm8900_i2c_remove, + .id_table = wm8900_i2c_id, }; -static struct i2c_client client_template = { - .name = "WM8900", - .driver = &wm8900_i2c_driver, -}; +static int wm8900_add_i2c_device(struct platform_device *pdev, + const struct wm8900_setup_data *setup) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + int ret; + + ret = i2c_add_driver(&wm8900_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = setup->i2c_address; + strlcpy(info.type, "wm8900", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(setup->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "can't get i2c adapter %d\n", + setup->i2c_bus); + goto err_driver; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + goto err_driver; + } + + return 0; + +err_driver: + i2c_del_driver(&wm8900_i2c_driver); + return -ENODEV; +} #endif static int wm8900_probe(struct platform_device *pdev) @@ -1497,11 +1494,8 @@ static int wm8900_probe(struct platform_device *pdev) wm8900_socdev = socdev; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8900_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); + ret = wm8900_add_i2c_device(pdev, setup); } #else #error Non-I2C interfaces not yet supported @@ -1521,6 +1515,7 @@ static int wm8900_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_unregister_device(codec->control_data); i2c_del_driver(&wm8900_i2c_driver); #endif kfree(codec); diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h index ba450d99e90..2249a446ad3 100644 --- a/sound/soc/codecs/wm8900.h +++ b/sound/soc/codecs/wm8900.h @@ -55,6 +55,7 @@ #define WM8900_ struct wm8900_setup_data { + int i2c_bus; unsigned short i2c_address; }; -- cgit v1.2.3 From 6b9331165e9827e055389e22d1cbdb5fe3cff835 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Oct 2008 11:00:07 +0100 Subject: ALSA: ASoC: Remove snd_soc_dapm_connect_input() This was marked as deprecated in 2.6.27 and all users except for playpaq_wm8510 fixed in that release. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- include/sound/soc-dapm.h | 2 -- sound/soc/soc-dapm.c | 22 ---------------------- 2 files changed, 24 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index ca699a3017f..7ee2f70ca42 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -221,8 +221,6 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, int num); /* dapm path setup */ -int __deprecated snd_soc_dapm_connect_input(struct snd_soc_codec *codec, - const char *sink_name, const char *control_name, const char *src_name); int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); void snd_soc_dapm_free(struct snd_soc_device *socdev); int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index efbd0b37810..4060fc54bbb 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1006,28 +1006,6 @@ err: return ret; } -/** - * snd_soc_dapm_connect_input - connect dapm widgets - * @codec: audio codec - * @sink: name of target widget - * @control: mixer control name - * @source: name of source name - * - * Connects 2 dapm widgets together via a named audio path. The sink is - * the widget receiving the audio signal, whilst the source is the sender - * of the audio signal. - * - * This function has been deprecated in favour of snd_soc_dapm_add_routes(). - * - * Returns 0 for success else error. - */ -int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, - const char *control, const char *source) -{ - return snd_soc_dapm_add_route(codec, sink, control, source); -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); - /** * snd_soc_dapm_add_routes - Add routes between DAPM widgets * @codec: codec -- cgit v1.2.3 From 12ef193d5817504621e503e78d641265f6a86ac4 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 13 Oct 2008 17:42:14 -0700 Subject: ASoC: Allow setting codec register with debugfs filesystem i.e. echo 6 59 >/sys/kernel/debug/soc-audio.0/codec_reg will set register 0x06 to a value of 0x59. Also, pop_time debugfs interface setup is moved so that it is setup in the same function as codec_reg Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++ sound/soc/soc-core.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++-- sound/soc/soc-dapm.c | 33 ++++----------- 3 files changed, 125 insertions(+), 28 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index a1e0357a84d..d33825d624a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -425,6 +425,7 @@ struct snd_soc_codec { short reg_cache_step; /* dapm */ + u32 pop_time; struct list_head dapm_widgets; struct list_head dapm_paths; enum snd_soc_bias_level bias_level; @@ -516,6 +517,9 @@ struct snd_soc_device { struct delayed_work delayed_work; struct work_struct deferred_resume_work; void *codec_data; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; +#endif }; /* runtime channel data */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 462e635dfc7..4707042b3da 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -961,10 +962,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, } /* codec register dump */ -static ssize_t codec_reg_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf) { - struct snd_soc_device *devdata = dev_get_drvdata(dev); struct snd_soc_codec *codec = devdata->codec; int i, step = 1, count = 0; @@ -1001,8 +1000,117 @@ static ssize_t codec_reg_show(struct device *dev, return count; } +static ssize_t codec_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_soc_device *devdata = dev_get_drvdata(dev); + return soc_codec_reg_show(devdata, buf); +} + static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); +#ifdef CONFIG_DEBUG_FS +static int codec_reg_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + struct snd_soc_device *devdata = file->private_data; + char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = soc_codec_reg_show(devdata, buf); + if (ret >= 0) + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + kfree(buf); + return ret; +} + +static ssize_t codec_reg_write_file(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[32]; + int buf_size; + char *start = buf; + unsigned long reg, value; + int step = 1; + struct snd_soc_device *devdata = file->private_data; + struct snd_soc_codec *codec = devdata->codec; + + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (codec->reg_cache_step) + step = codec->reg_cache_step; + + while (*start == ' ') + start++; + reg = simple_strtoul(start, &start, 16); + if ((reg >= codec->reg_cache_size) || (reg % step)) + return -EINVAL; + while (*start == ' ') + start++; + if (strict_strtoul(start, 16, &value)) + return -EINVAL; + codec->write(codec, reg, value); + return buf_size; +} + +static const struct file_operations codec_reg_fops = { + .open = codec_reg_open_file, + .read = codec_reg_read_file, + .write = codec_reg_write_file, +}; + +static void soc_init_debugfs(struct snd_soc_device *socdev) +{ + struct dentry *root, *file; + struct snd_soc_codec *codec = socdev->codec; + root = debugfs_create_dir(dev_name(socdev->dev), NULL); + if (IS_ERR(root) || !root) + goto exit1; + + file = debugfs_create_file("codec_reg", 0644, + root, socdev, &codec_reg_fops); + if (!file) + goto exit2; + + file = debugfs_create_u32("dapm_pop_time", 0744, + root, &codec->pop_time); + if (!file) + goto exit2; + socdev->debugfs_root = root; + return; +exit2: + debugfs_remove_recursive(root); +exit1: + dev_err(socdev->dev, "debugfs is not available\n"); +} + +static void soc_cleanup_debugfs(struct snd_soc_device *socdev) +{ + debugfs_remove_recursive(socdev->debugfs_root); + socdev->debugfs_root = NULL; +} + +#else + +static inline void soc_init_debugfs(struct snd_soc_device *socdev) +{ +} + +static inline void soc_cleanup_debugfs(struct snd_soc_device *socdev) +{ +} +#endif + /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec @@ -1216,6 +1324,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) if (err < 0) printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); + soc_init_debugfs(socdev); mutex_unlock(&codec->mutex); out: @@ -1239,6 +1348,7 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) #endif mutex_lock(&codec->mutex); + soc_cleanup_debugfs(socdev); #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7e9f423f5b0..b51d82285be 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -67,17 +66,13 @@ static int dapm_status = 1; module_param(dapm_status, int, 0); MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); -static struct dentry *asoc_debugfs; - -static u32 pop_time; - -static void pop_wait(void) +static void pop_wait(u32 pop_time) { if (pop_time) schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); } -static void pop_dbg(const char *fmt, ...) +static void pop_dbg(u32 pop_time, const char *fmt, ...) { va_list args; @@ -85,7 +80,7 @@ static void pop_dbg(const char *fmt, ...) if (pop_time) { vprintk(fmt, args); - pop_wait(); + pop_wait(pop_time); } va_end(args); @@ -230,10 +225,11 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget) change = old != new; if (change) { - pop_dbg("pop test %s : %s in %d ms\n", widget->name, - widget->power ? "on" : "off", pop_time); + pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n", + widget->name, widget->power ? "on" : "off", + codec->pop_time); snd_soc_write(codec, widget->reg, new); - pop_wait(); + pop_wait(codec->pop_time); } pr_debug("reg %x old %x new %x change %d\n", widget->reg, old, new, change); @@ -821,23 +817,13 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { - int ret = 0; - if (!dapm_status) return 0; ret = device_create_file(dev, &dev_attr_dapm_widget); if (ret != 0) return ret; - - asoc_debugfs = debugfs_create_dir("asoc", NULL); - if (!IS_ERR(asoc_debugfs) && asoc_debugfs) - debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs, - &pop_time); - else - asoc_debugfs = NULL; - - return 0; + return device_create_file(dev, &dev_attr_dapm_widget); } static void snd_soc_dapm_sys_remove(struct device *dev) @@ -845,9 +831,6 @@ static void snd_soc_dapm_sys_remove(struct device *dev) if (dapm_status) { device_remove_file(dev, &dev_attr_dapm_widget); } - - if (asoc_debugfs) - debugfs_remove_recursive(asoc_debugfs); } /* free all dapm widgets and resources */ -- cgit v1.2.3 From d45f6219d256b4e02f9ebee2e3911f4ea80bac70 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 14 Oct 2008 13:58:36 +0100 Subject: ASoC: Fix handling of DAPM suspend work Since we can query the playback stream power state directly we do not need to infer if it is powered up from the timer being scheduled. Doing this avoids problems that previously existed with streams being incorrectly determined to be powered up caused when the timer is scheduled when streams are closed after being partially set up. Reported-by: Nobin Mathew Reported-by: Jukka Hynninen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 55 ++++++++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4707042b3da..411fd3bcf44 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -429,51 +429,42 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - /* we only want to start a DAPM playback stream if we are not waiting - * on an existing one stopping */ - if (codec_dai->pop_wait) { - /* we are waiting for the delayed work to start */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - snd_soc_dapm_stream_event(socdev->codec, - codec_dai->capture.stream_name, - SND_SOC_DAPM_STREAM_START); - else { - codec_dai->pop_wait = 0; - cancel_delayed_work(&socdev->delayed_work); - snd_soc_dai_digital_mute(codec_dai, 0); - } - } else { - /* no delayed work - do we need to power up codec */ - if (codec->bias_level != SND_SOC_BIAS_ON) { + /* cancel any delayed stream shutdown that is pending */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + codec_dai->pop_wait) { + codec_dai->pop_wait = 0; + cancel_delayed_work(&socdev->delayed_work); + } - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); + /* do we need to power up codec */ + if (codec->bias_level != SND_SOC_BIAS_ON) { + snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_PREPARE); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, + else + snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); - snd_soc_dai_digital_mute(codec_dai, 0); + snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); + snd_soc_dai_digital_mute(codec_dai, 0); - } else { - /* codec already powered - power on widgets */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, + } else { + /* codec already powered - power on widgets */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, + else + snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - snd_soc_dai_digital_mute(codec_dai, 0); - } + snd_soc_dai_digital_mute(codec_dai, 0); } out: -- cgit v1.2.3 From f24368c2fb524e911b831b86b5f0acfb38c70317 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Oct 2008 21:45:08 +0100 Subject: ASoC: Convert core to use standard debug print macros Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 411fd3bcf44..8f384df941f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -35,14 +35,6 @@ #include #include -/* debug */ -#define SOC_DEBUG 0 -#if SOC_DEBUG -#define dbg(format, arg...) printk(format, ## arg) -#else -#define dbg(format, arg...) -#endif - static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); @@ -229,12 +221,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto machine_err; } - dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); - dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); - dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, - runtime->hw.channels_max); - dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, - runtime->hw.rate_max); + pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); + pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); + pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, + runtime->hw.channels_max); + pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, + runtime->hw.rate_max); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) cpu_dai->playback.active = codec_dai->playback.active = 1; @@ -279,18 +271,18 @@ static void close_delayed_work(struct work_struct *work) for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - dbg("pop wq checking: %s status: %s waiting: %s\n", - codec_dai->playback.stream_name, - codec_dai->playback.active ? "active" : "inactive", - codec_dai->pop_wait ? "yes" : "no"); + pr_debug("pop wq checking: %s status: %s waiting: %s\n", + codec_dai->playback.stream_name, + codec_dai->playback.active ? "active" : "inactive", + codec_dai->pop_wait ? "yes" : "no"); /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { /* Reduce power if no longer active */ if (codec->active == 0) { - dbg("pop wq D1 %s %s\n", codec->name, - codec_dai->playback.stream_name); + pr_debug("pop wq D1 %s %s\n", codec->name, + codec_dai->playback.stream_name); snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE); } @@ -302,8 +294,8 @@ static void close_delayed_work(struct work_struct *work) /* Fall into standby if no longer active */ if (codec->active == 0) { - dbg("pop wq D3 %s %s\n", codec->name, - codec_dai->playback.stream_name); + pr_debug("pop wq D3 %s %s\n", codec->name, + codec_dai->playback.stream_name); snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY); } -- cgit v1.2.3 From 219b93f5252086c8c8d647c77fc9e1377aab0c8d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Oct 2008 13:02:31 +0000 Subject: ASoC: Remove DAPM restriction on mixer control name lengths As well as ensuring that UI-relevant parts of control names don't get truncated in the DAPM code this avoids conflicts in long control names that differ only at the end of a long string. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b51d82285be..407092c226f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -289,7 +289,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *w) { int i, ret = 0; - char name[32]; + size_t name_len; struct snd_soc_dapm_path *path; /* add kcontrol */ @@ -303,11 +303,16 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, continue; /* add dapm control with long name */ - snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name); - path->long_name = kstrdup (name, GFP_KERNEL); + name_len = 2 + strlen(w->name) + + strlen(w->kcontrols[i].name); + path->long_name = kmalloc(name_len, GFP_KERNEL); if (path->long_name == NULL) return -ENOMEM; + snprintf(path->long_name, name_len, "%s %s", + w->name, w->kcontrols[i].name); + path->long_name[name_len - 1] = '\0'; + path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, path->long_name); ret = snd_ctl_add(codec->card, path->kcontrol); -- cgit v1.2.3 From 1b340bd7e444f20eb2df88c65fa34960c4736ee9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 Jul 2008 19:12:04 +0100 Subject: ASoC: Add PXA SSP support The SSP ports PXA series processors can be used to implement a variety of audio interface formats. This patch implements support for I2S, DSP A and DSP B modes on these ports. This patch is based on the previous out of tree pxa2xx-ssp driver (which was originally written by Liam Girdwood with updates from Philipp Zabel and Nicola Perrino) and pxa3xx-ssp driver (originally written by Seth Forsee based on the pxa2xx-ssp driver). Testing coverage is not complete currently. Tested-by: Daniel Ribeiro Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 13 + sound/soc/pxa/Makefile | 2 + sound/soc/pxa/pxa-ssp.c | 929 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/pxa/pxa-ssp.h | 47 +++ 4 files changed, 991 insertions(+) create mode 100644 sound/soc/pxa/pxa-ssp.c create mode 100644 sound/soc/pxa/pxa-ssp.h diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index f8c1cdd940a..4235524238f 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -21,6 +21,9 @@ config SND_PXA2XX_SOC_AC97 config SND_PXA2XX_SOC_I2S tristate +config SND_PXA_SOC_SSP + tristate + config SND_PXA2XX_SOC_CORGI tristate "SoC Audio support for Sharp Zaurus SL-C7x0" depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx @@ -75,3 +78,13 @@ config SND_PXA2XX_SOC_EM_X270 help Say Y if you want to add support for SoC audio on CompuLab EM-x270. + +config SND_SOC_ZYLONITE + tristate "SoC Audio support for Marvell Zylonite" + depends on SND_PXA2XX_SOC && MACH_ZYLONITE + select SND_PXA2XX_SOC_AC97 + select SND_PXA_SOC_SSP + select SND_SOC_WM9713 + help + Say Y if you want to add support for SoC audio on the + Marvell Zylonite reference platform. diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 5bc8edf9dca..00258abb84a 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -2,10 +2,12 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o +snd-soc-pxa-ssp-objs := pxa-ssp.o obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o +obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o # PXA Machine Support snd-soc-corgi-objs := corgi.o diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c new file mode 100644 index 00000000000..e2b54b88c38 --- /dev/null +++ b/sound/soc/pxa/pxa-ssp.c @@ -0,0 +1,929 @@ +#define DEBUG +/* + * pxa-ssp.c -- ALSA Soc Audio Layer + * + * Copyright 2005,2008 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * 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. + * + * TODO: + * o Test network mode for > 16bit sample size + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pxa2xx-pcm.h" +#include "pxa-ssp.h" + +/* + * SSP audio private data + */ +struct ssp_priv { + struct ssp_dev dev; + unsigned int sysclk; + int dai_fmt; +#ifdef CONFIG_PM + struct ssp_state state; +#endif +}; + +#define PXA2xx_SSP1_BASE 0x41000000 +#define PXA27x_SSP2_BASE 0x41700000 +#define PXA27x_SSP3_BASE 0x41900000 +#define PXA3xx_SSP4_BASE 0x41a00000 + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_out = { + .name = "SSP1 PCM Mono out", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(14), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_in = { + .name = "SSP1 PCM Mono in", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(13), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_out = { + .name = "SSP1 PCM Stereo out", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(14), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_in = { + .name = "SSP1 PCM Stereo in", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(13), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_out = { + .name = "SSP2 PCM Mono out", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(16), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_in = { + .name = "SSP2 PCM Mono in", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(15), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_out = { + .name = "SSP2 PCM Stereo out", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(16), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_in = { + .name = "SSP2 PCM Stereo in", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(15), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_out = { + .name = "SSP3 PCM Mono out", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_in = { + .name = "SSP3 PCM Mono in", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_out = { + .name = "SSP3 PCM Stereo out", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_in = { + .name = "SSP3 PCM Stereo in", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_out = { + .name = "SSP4 PCM Mono out", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_in = { + .name = "SSP4 PCM Mono in", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_out = { + .name = "SSP4 PCM Stereo out", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_in = { + .name = "SSP4 PCM Stereo in", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static void dump_registers(struct ssp_device *ssp) +{ + dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n", + ssp_read_reg(ssp, SSCR0), ssp_read_reg(ssp, SSCR1), + ssp_read_reg(ssp, SSTO)); + + dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n", + ssp_read_reg(ssp, SSPSP), ssp_read_reg(ssp, SSSR), + ssp_read_reg(ssp, SSACD)); +} + +static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = { + { + &pxa_ssp1_pcm_mono_out, &pxa_ssp1_pcm_mono_in, + &pxa_ssp1_pcm_stereo_out, &pxa_ssp1_pcm_stereo_in, + }, + { + &pxa_ssp2_pcm_mono_out, &pxa_ssp2_pcm_mono_in, + &pxa_ssp2_pcm_stereo_out, &pxa_ssp2_pcm_stereo_in, + }, + { + &pxa_ssp3_pcm_mono_out, &pxa_ssp3_pcm_mono_in, + &pxa_ssp3_pcm_stereo_out, &pxa_ssp3_pcm_stereo_in, + }, + { + &pxa_ssp4_pcm_mono_out, &pxa_ssp4_pcm_mono_in, + &pxa_ssp4_pcm_stereo_out, &pxa_ssp4_pcm_stereo_in, + }, +}; + +static int pxa_ssp_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct ssp_priv *priv = cpu_dai->private_data; + int ret = 0; + + if (!cpu_dai->active) { + ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ); + if (ret < 0) + return ret; + ssp_disable(&priv->dev); + } + return ret; +} + +static void pxa_ssp_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct ssp_priv *priv = cpu_dai->private_data; + + if (!cpu_dai->active) { + ssp_disable(&priv->dev); + ssp_exit(&priv->dev); + } +} + +#ifdef CONFIG_PM + +static int pxa_ssp_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct ssp_priv *priv = cpu_dai->private_data; + + if (!cpu_dai->active) + return 0; + + ssp_save_state(&priv->dev, &priv->state); + clk_disable(priv->dev.ssp->clk); + return 0; +} + +static int pxa_ssp_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct ssp_priv *priv = cpu_dai->private_data; + + if (!cpu_dai->active) + return 0; + + clk_enable(priv->dev.ssp->clk); + ssp_restore_state(&priv->dev, &priv->state); + ssp_enable(&priv->dev); + + return 0; +} + +#else +#define pxa_ssp_suspend NULL +#define pxa_ssp_resume NULL +#endif + +/** + * ssp_set_clkdiv - set SSP clock divider + * @div: serial clock rate divider + */ +static void ssp_set_scr(struct ssp_dev *dev, u32 div) +{ + struct ssp_device *ssp = dev->ssp; + u32 sscr0 = ssp_read_reg(dev->ssp, SSCR0) & ~SSCR0_SCR; + + ssp_write_reg(ssp, SSCR0, (sscr0 | SSCR0_SerClkDiv(div))); +} + +/* + * Set the SSP ports SYSCLK. + */ +static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + int val; + + u32 sscr0 = ssp_read_reg(ssp, SSCR0) & + ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); + + dev_dbg(&ssp->pdev->dev, + "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", + cpu_dai->id, clk_id, freq); + + switch (clk_id) { + case PXA_SSP_CLK_NET_PLL: + sscr0 |= SSCR0_MOD; + break; + case PXA_SSP_CLK_PLL: + /* Internal PLL is fixed */ + if (cpu_is_pxa25x()) + priv->sysclk = 1843200; + else + priv->sysclk = 13000000; + break; + case PXA_SSP_CLK_EXT: + priv->sysclk = freq; + sscr0 |= SSCR0_ECS; + break; + case PXA_SSP_CLK_NET: + priv->sysclk = freq; + sscr0 |= SSCR0_NCS | SSCR0_MOD; + break; + case PXA_SSP_CLK_AUDIO: + priv->sysclk = 0; + ssp_set_scr(&priv->dev, 1); + sscr0 |= SSCR0_ADC; + break; + default: + return -ENODEV; + } + + /* The SSP clock must be disabled when changing SSP clock mode + * on PXA2xx. On PXA3xx it must be enabled when doing so. */ + if (!cpu_is_pxa3xx()) + clk_disable(priv->dev.ssp->clk); + val = ssp_read_reg(ssp, SSCR0) | sscr0; + ssp_write_reg(ssp, SSCR0, val); + if (!cpu_is_pxa3xx()) + clk_enable(priv->dev.ssp->clk); + + return 0; +} + +/* + * Set the SSP clock dividers. + */ +static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + int val; + + switch (div_id) { + case PXA_SSP_AUDIO_DIV_ACDS: + val = (ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div); + ssp_write_reg(ssp, SSACD, val); + break; + case PXA_SSP_AUDIO_DIV_SCDB: + val = ssp_read_reg(ssp, SSACD); + val &= ~SSACD_SCDB; +#if defined(CONFIG_PXA3xx) + if (cpu_is_pxa3xx()) + val &= ~SSACD_SCDX8; +#endif + switch (div) { + case PXA_SSP_CLK_SCDB_1: + val |= SSACD_SCDB; + break; + case PXA_SSP_CLK_SCDB_4: + break; +#if defined(CONFIG_PXA3xx) + case PXA_SSP_CLK_SCDB_8: + if (cpu_is_pxa3xx()) + val |= SSACD_SCDX8; + else + return -EINVAL; + break; +#endif + default: + return -EINVAL; + } + ssp_write_reg(ssp, SSACD, val); + break; + case PXA_SSP_DIV_SCR: + ssp_set_scr(&priv->dev, div); + break; + default: + return -ENODEV; + } + + return 0; +} + +/* + * Configure the PLL frequency pxa27x and (afaik - pxa320 only) + */ +static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + u32 ssacd = ssp_read_reg(ssp, SSACD) & ~0x70; + +#if defined(CONFIG_PXA3xx) + if (cpu_is_pxa3xx()) + ssp_write_reg(ssp, SSACDD, 0); +#endif + + switch (freq_out) { + case 5622000: + break; + case 11345000: + ssacd |= (0x1 << 4); + break; + case 12235000: + ssacd |= (0x2 << 4); + break; + case 14857000: + ssacd |= (0x3 << 4); + break; + case 32842000: + ssacd |= (0x4 << 4); + break; + case 48000000: + ssacd |= (0x5 << 4); + break; + case 0: + /* Disable */ + break; + + default: +#ifdef CONFIG_PXA3xx + /* PXA3xx has a clock ditherer which can be used to generate + * a wider range of frequencies - calculate a value for it. + */ + if (cpu_is_pxa3xx()) { + u32 val; + u64 tmp = 19968; + tmp *= 1000000; + do_div(tmp, freq_out); + val = tmp; + + val = (val << 16) | 64;; + ssp_write_reg(ssp, SSACDD, val); + + ssacd |= (0x6 << 4); + + dev_dbg(&ssp->pdev->dev, + "Using SSACDD %x to supply %dHz\n", + val, freq_out); + break; + } +#endif + + return -EINVAL; + } + + ssp_write_reg(ssp, SSACD, ssacd); + + return 0; +} + +/* + * Set the active slots in TDM/Network mode + */ +static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, + unsigned int mask, int slots) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + u32 sscr0; + + sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7); + + /* set number of active slots */ + sscr0 |= SSCR0_SlotsPerFrm(slots); + ssp_write_reg(ssp, SSCR0, sscr0); + + /* set active slot mask */ + ssp_write_reg(ssp, SSTSA, mask); + ssp_write_reg(ssp, SSRSA, mask); + return 0; +} + +/* + * Tristate the SSP DAI lines + */ +static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai, + int tristate) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + u32 sscr1; + + sscr1 = ssp_read_reg(ssp, SSCR1); + if (tristate) + sscr1 &= ~SSCR1_TTE; + else + sscr1 |= SSCR1_TTE; + ssp_write_reg(ssp, SSCR1, sscr1); + + return 0; +} + +/* + * Set up the SSP DAI format. + * The SSP Port must be inactive before calling this function as the + * physical interface format is changed. + */ +static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + u32 sscr0; + u32 sscr1; + u32 sspsp; + + /* reset port settings */ + sscr0 = ssp_read_reg(ssp, SSCR0) & + (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); + sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); + sspsp = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + sscr1 |= SSCR1_SCLKDIR; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + ssp_write_reg(ssp, SSCR0, sscr0); + ssp_write_reg(ssp, SSCR1, sscr1); + ssp_write_reg(ssp, SSPSP, sspsp); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + sscr0 |= SSCR0_MOD | SSCR0_PSP; + sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + sspsp |= SSPSP_FSRT; + break; + case SND_SOC_DAIFMT_NB_IF: + sspsp |= SSPSP_SFRMP | SSPSP_FSRT; + break; + case SND_SOC_DAIFMT_IB_IF: + sspsp |= SSPSP_SFRMP; + break; + default: + return -EINVAL; + } + break; + + case SND_SOC_DAIFMT_DSP_A: + sspsp |= SSPSP_FSRT; + case SND_SOC_DAIFMT_DSP_B: + sscr0 |= SSCR0_MOD | SSCR0_PSP; + sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + sspsp |= SSPSP_SFRMP; + break; + case SND_SOC_DAIFMT_IB_IF: + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + ssp_write_reg(ssp, SSCR0, sscr0); + ssp_write_reg(ssp, SSCR1, sscr1); + ssp_write_reg(ssp, SSPSP, sspsp); + + dump_registers(ssp); + + /* Since we are configuring the timings for the format by hand + * we have to defer some things until hw_params() where we + * know parameters like the sample size. + */ + priv->dai_fmt = fmt; + + return 0; +} + +/* + * Set the SSP audio DMA parameters and sample size. + * Can be called multiple times by oss emulation. + */ +static int pxa_ssp_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->dai->cpu_dai; + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + int dma = 0, chn = params_channels(params); + u32 sscr0; + u32 sspsp; + int width = snd_pcm_format_physical_width(params_format(params)); + + /* select correct DMA params */ + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + dma = 1; /* capture DMA offset is 1,3 */ + if (chn == 2) + dma += 2; /* stereo DMA offset is 2, mono is 0 */ + cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma]; + + dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma); + + /* we can only change the settings if the port is not in use */ + if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) + return 0; + + /* clear selected SSP bits */ + sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS); + ssp_write_reg(ssp, SSCR0, sscr0); + + /* bit size */ + sscr0 = ssp_read_reg(ssp, SSCR0); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: +#ifdef CONFIG_PXA3xx + if (cpu_is_pxa3xx()) + sscr0 |= SSCR0_FPCKE; +#endif + sscr0 |= SSCR0_DataSize(16); + if (params_channels(params) > 1) + sscr0 |= SSCR0_EDSS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); + /* we must be in network mode (2 slots) for 24 bit stereo */ + break; + case SNDRV_PCM_FORMAT_S32_LE: + sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); + /* we must be in network mode (2 slots) for 32 bit stereo */ + break; + } + ssp_write_reg(ssp, SSCR0, sscr0); + + switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* Cleared when the DAI format is set */ + sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width); + ssp_write_reg(ssp, SSPSP, sspsp); + break; + default: + break; + } + + /* We always use a network mode so we always require TDM slots + * - complain loudly and fail if they've not been set up yet. + */ + if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { + dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); + return -EINVAL; + } + + dump_registers(ssp); + + return 0; +} + +static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret = 0; + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + int val; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + ssp_enable(&priv->dev); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + val = ssp_read_reg(ssp, SSCR1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val |= SSCR1_TSRE; + else + val |= SSCR1_RSRE; + ssp_write_reg(ssp, SSCR1, val); + val = ssp_read_reg(ssp, SSSR); + ssp_write_reg(ssp, SSSR, val); + break; + case SNDRV_PCM_TRIGGER_START: + val = ssp_read_reg(ssp, SSCR1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val |= SSCR1_TSRE; + else + val |= SSCR1_RSRE; + ssp_write_reg(ssp, SSCR1, val); + ssp_enable(&priv->dev); + break; + case SNDRV_PCM_TRIGGER_STOP: + val = ssp_read_reg(ssp, SSCR1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val &= ~SSCR1_TSRE; + else + val &= ~SSCR1_RSRE; + ssp_write_reg(ssp, SSCR1, val); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + ssp_disable(&priv->dev); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + val = ssp_read_reg(ssp, SSCR1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val &= ~SSCR1_TSRE; + else + val &= ~SSCR1_RSRE; + ssp_write_reg(ssp, SSCR1, val); + break; + + default: + ret = -EINVAL; + } + + dump_registers(ssp); + + return ret; +} + +static int pxa_ssp_probe(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct ssp_priv *priv; + int ret; + + priv = kzalloc(sizeof(struct ssp_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev.ssp = ssp_request(dai->id, "SoC audio"); + if (priv->dev.ssp == NULL) { + ret = -ENODEV; + goto err_priv; + } + + dai->private_data = priv; + + return 0; + +err_priv: + kfree(priv); + return ret; +} + +static void pxa_ssp_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct ssp_priv *priv = dai->private_data; + ssp_free(priv->dev.ssp); +} + +#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +struct snd_soc_dai pxa_ssp_dai[] = { + { + .name = "pxa2xx-ssp1", + .id = 0, + .type = SND_SOC_DAI_PCM, + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .ops = { + .startup = pxa_ssp_startup, + .shutdown = pxa_ssp_shutdown, + .trigger = pxa_ssp_trigger, + .hw_params = pxa_ssp_hw_params, + }, + .dai_ops = { + .set_sysclk = pxa_ssp_set_dai_sysclk, + .set_clkdiv = pxa_ssp_set_dai_clkdiv, + .set_pll = pxa_ssp_set_dai_pll, + .set_fmt = pxa_ssp_set_dai_fmt, + .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, + .set_tristate = pxa_ssp_set_dai_tristate, + }, + }, + { .name = "pxa2xx-ssp2", + .id = 1, + .type = SND_SOC_DAI_PCM, + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .ops = { + .startup = pxa_ssp_startup, + .shutdown = pxa_ssp_shutdown, + .trigger = pxa_ssp_trigger, + .hw_params = pxa_ssp_hw_params, + }, + .dai_ops = { + .set_sysclk = pxa_ssp_set_dai_sysclk, + .set_clkdiv = pxa_ssp_set_dai_clkdiv, + .set_pll = pxa_ssp_set_dai_pll, + .set_fmt = pxa_ssp_set_dai_fmt, + .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, + .set_tristate = pxa_ssp_set_dai_tristate, + }, + }, + { + .name = "pxa2xx-ssp3", + .id = 2, + .type = SND_SOC_DAI_PCM, + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .ops = { + .startup = pxa_ssp_startup, + .shutdown = pxa_ssp_shutdown, + .trigger = pxa_ssp_trigger, + .hw_params = pxa_ssp_hw_params, + }, + .dai_ops = { + .set_sysclk = pxa_ssp_set_dai_sysclk, + .set_clkdiv = pxa_ssp_set_dai_clkdiv, + .set_pll = pxa_ssp_set_dai_pll, + .set_fmt = pxa_ssp_set_dai_fmt, + .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, + .set_tristate = pxa_ssp_set_dai_tristate, + }, + }, + { + .name = "pxa2xx-ssp4", + .id = 3, + .type = SND_SOC_DAI_PCM, + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .ops = { + .startup = pxa_ssp_startup, + .shutdown = pxa_ssp_shutdown, + .trigger = pxa_ssp_trigger, + .hw_params = pxa_ssp_hw_params, + }, + .dai_ops = { + .set_sysclk = pxa_ssp_set_dai_sysclk, + .set_clkdiv = pxa_ssp_set_dai_clkdiv, + .set_pll = pxa_ssp_set_dai_pll, + .set_fmt = pxa_ssp_set_dai_fmt, + .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, + .set_tristate = pxa_ssp_set_dai_tristate, + }, + }, +}; +EXPORT_SYMBOL_GPL(pxa_ssp_dai); + +/* Module information */ +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h new file mode 100644 index 00000000000..91deadd5567 --- /dev/null +++ b/sound/soc/pxa/pxa-ssp.h @@ -0,0 +1,47 @@ +/* + * ASoC PXA SSP port support + * + * 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 _PXA_SSP_H +#define _PXA_SSP_H + +/* pxa DAI SSP IDs */ +#define PXA_DAI_SSP1 0 +#define PXA_DAI_SSP2 1 +#define PXA_DAI_SSP3 2 +#define PXA_DAI_SSP4 3 + +/* SSP clock sources */ +#define PXA_SSP_CLK_PLL 0 +#define PXA_SSP_CLK_EXT 1 +#define PXA_SSP_CLK_NET 2 +#define PXA_SSP_CLK_AUDIO 3 +#define PXA_SSP_CLK_NET_PLL 4 + +/* SSP audio dividers */ +#define PXA_SSP_AUDIO_DIV_ACDS 0 +#define PXA_SSP_AUDIO_DIV_SCDB 1 +#define PXA_SSP_DIV_SCR 2 + +/* SSP ACDS audio dividers values */ +#define PXA_SSP_CLK_AUDIO_DIV_1 0 +#define PXA_SSP_CLK_AUDIO_DIV_2 1 +#define PXA_SSP_CLK_AUDIO_DIV_4 2 +#define PXA_SSP_CLK_AUDIO_DIV_8 3 +#define PXA_SSP_CLK_AUDIO_DIV_16 4 +#define PXA_SSP_CLK_AUDIO_DIV_32 5 + +/* SSP divider bypass */ +#define PXA_SSP_CLK_SCDB_4 0 +#define PXA_SSP_CLK_SCDB_1 1 +#define PXA_SSP_CLK_SCDB_8 2 + +#define PXA_SSP_PLL_OUT 0 + +extern struct snd_soc_dai pxa_ssp_dai[4]; + +#endif -- cgit v1.2.3 From e775f6c0fb6ac25ab8845d4ad1e17b4b015487f0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Oct 2008 15:04:35 +0000 Subject: ASoC: Do a warm reset after cold when resetting the WM9713 The WM9713 comes out of cold reset in low power mode so always requires a warm reset to bring up the AC97 link after a cold reset. Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index aba402b3c99..3214aa503ea 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1097,6 +1097,8 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) } soc_ac97_ops.reset(codec->ac97); + if (soc_ac97_ops.warm_reset) + soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, 0) != wm9713_reg[0]) return -EIO; return 0; -- cgit v1.2.3 From ca53fb24dd21bff32c4b41b2be1035a1adfc0135 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 22 Oct 2008 22:41:11 +0100 Subject: ASoC: Use finer grained dependencies in SND_SOC_ALL_CODECS Move the bus dependencies in SND_SOC_ALL_CODECS into the individual codec options rather than have them centrally. This allows the inclusion of AC97 codecs when testing on platforms with AC97 support and will also handle codecs on multi-function devices more gracefully. Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 38a0e3b620a..3c76cae68b4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1,31 +1,35 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" - depends on I2C - select SPI - select SPI_MASTER - select SND_SOC_AD73311 - select SND_SOC_AK4535 - select SND_SOC_CS4270 - select SND_SOC_SSM2602 - select SND_SOC_TLV320AIC23 - select SND_SOC_TLV320AIC26 - select SND_SOC_TLV320AIC3X - select SND_SOC_UDA1380 - select SND_SOC_WM8510 - select SND_SOC_WM8580 - select SND_SOC_WM8731 - select SND_SOC_WM8750 - select SND_SOC_WM8753 - select SND_SOC_WM8900 - select SND_SOC_WM8903 - select SND_SOC_WM8971 - select SND_SOC_WM8990 + select SND_SOC_AC97 if SND_SOC_AC97_BUS + select SND_SOC_AD1980 if SND_SOC_AC97_BUS + select SND_SOC_AD73311 if I2C + select SND_SOC_AK4535 if I2C + select SND_SOC_CS4270 if I2C + select SND_SOC_SSM2602 if I2C + select SND_SOC_TLV320AIC23 if I2C + select SND_SOC_TLV320AIC26 if SPI_MASTER + select SND_SOC_TLV320AIC3X if I2C + select SND_SOC_UDA1380 if I2C + select SND_SOC_WM8510 if (I2C || SPI_MASTER) + select SND_SOC_WM8580 if I2C + select SND_SOC_WM8731 if (I2C || SPI_MASTER) + select SND_SOC_WM8750 if (I2C || SPI_MASTER) + select SND_SOC_WM8753 if (I2C || SPI_MASTER) + select SND_SOC_WM8900 if I2C + select SND_SOC_WM8903 if I2C + select SND_SOC_WM8971 if I2C + select SND_SOC_WM8990 if I2C + select SND_SOC_WM9712 if SND_SOC_AC97_BUS + select SND_SOC_WM9713 if SND_SOC_AC97_BUS help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine driver. Selecting this option will allow these drivers to be built without an explicit machine driver for test and development purposes. + Support for the bus types used to access the codecs to be built must + be selected separately. + If unsure select "N". -- cgit v1.2.3 From 0c235d1e837c142b7565814318b6ba5917d5ac32 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 7 Aug 2008 11:22:32 -0500 Subject: ASoC: Disable automatic volume control in the CS4270 sound driver Disable the automatic volume control feature of the CS4270 audio codec. This feature, which is enabled by default, causes volume change commands to be delayed. Sometimes the volume change happens after playback is started. Signed-off-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 0bbd94501d7..0ff476d7057 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -450,6 +450,19 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, return ret; } + /* Disable automatic volume control. It's enabled by default, and + * it causes volume change commands to be delayed, sometimes until + * after playback has started. + */ + + reg = cs4270_read_reg_cache(codec, CS4270_TRANS); + reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); + ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); + if (ret < 0) { + printk(KERN_ERR "I2C write failed\n"); + return ret; + } + /* Thaw and power-up the codec */ ret = snd_soc_write(codec, CS4270_PWRCTL, 0); -- cgit v1.2.3 From 0763722d28b7b58fa1f9b83d3378efcde855b18a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Oct 2008 17:53:19 +0100 Subject: ALSA: ASoC - Fix a typo in Kconfig The last change to Kconfig ca53fb24dd21bff32c4b41b2be1035a1adfc0135 added a wrong item SND_SOC_AC97, which must be SND_SOC_AC97_CODEC. Signed-off-by: Takashi Iwai --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3c76cae68b4..0fd3341e6e3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1,6 +1,6 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" - select SND_SOC_AC97 if SND_SOC_AC97_BUS + select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS select SND_SOC_AD1980 if SND_SOC_AC97_BUS select SND_SOC_AD73311 if I2C select SND_SOC_AK4535 if I2C -- cgit v1.2.3 From 57b41898c2ecd13a9d338b66ef23f66caab5c4e9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 31 Oct 2008 14:41:06 +1100 Subject: ALSA: ASoC - restore removed variable declaration sound/soc/soc-dapm.c: In function 'snd_soc_dapm_sys_add': sound/soc/soc-dapm.c:828: error: 'ret' undeclared (first use in this function) Signed-off-by: Stephen Rothwell Signed-off-by: Takashi Iwai --- sound/soc/soc-dapm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 407092c226f..7bf3c409459 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -822,6 +822,8 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { + int ret; + if (!dapm_status) return 0; -- cgit v1.2.3 From cc17557e7876a92e11d4b406a367d28e103e42e6 Mon Sep 17 00:00:00 2001 From: Steve Sakoman Date: Thu, 30 Oct 2008 21:35:26 -0700 Subject: ASoC: Add support for TWL4030 audio codec Signed-off-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/twl4030.c | 653 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/twl4030.h | 197 ++++++++++++++ 4 files changed, 857 insertions(+) create mode 100644 sound/soc/codecs/twl4030.c create mode 100644 sound/soc/codecs/twl4030.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0fd3341e6e3..b73c36aad67 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -9,6 +9,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC3X if I2C + select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_UDA1380 if I2C select SND_SOC_WM8510 if (I2C || SPI_MASTER) select SND_SOC_WM8580 if I2C @@ -79,6 +80,10 @@ config SND_SOC_TLV320AIC3X tristate depends on I2C +config SND_SOC_TWL4030 + tristate + depends on TWL4030_CORE + config SND_SOC_UDA1380 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 90f0a585fc7..3b9b58a0ea7 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -7,6 +7,7 @@ snd-soc-ssm2602-objs := ssm2602.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o +snd-soc-twl4030-objs := twl4030.o snd-soc-uda1380-objs := uda1380.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o @@ -29,6 +30,7 @@ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o +obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c new file mode 100644 index 00000000000..ee2f0d37765 --- /dev/null +++ b/sound/soc/codecs/twl4030.c @@ -0,0 +1,653 @@ +/* + * ALSA SoC TWL4030 codec driver + * + * Author: Steve Sakoman, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "twl4030.h" + +/* + * twl4030 register cache & default register settings + */ +static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { + 0x00, /* this register not used */ + 0x93, /* REG_CODEC_MODE (0x1) */ + 0xc3, /* REG_OPTION (0x2) */ + 0x00, /* REG_UNKNOWN (0x3) */ + 0x00, /* REG_MICBIAS_CTL (0x4) */ + 0x24, /* REG_ANAMICL (0x5) */ + 0x04, /* REG_ANAMICR (0x6) */ + 0x0a, /* REG_AVADC_CTL (0x7) */ + 0x00, /* REG_ADCMICSEL (0x8) */ + 0x00, /* REG_DIGMIXING (0x9) */ + 0x0c, /* REG_ATXL1PGA (0xA) */ + 0x0c, /* REG_ATXR1PGA (0xB) */ + 0x00, /* REG_AVTXL2PGA (0xC) */ + 0x00, /* REG_AVTXR2PGA (0xD) */ + 0x01, /* REG_AUDIO_IF (0xE) */ + 0x00, /* REG_VOICE_IF (0xF) */ + 0x00, /* REG_ARXR1PGA (0x10) */ + 0x00, /* REG_ARXL1PGA (0x11) */ + 0x6c, /* REG_ARXR2PGA (0x12) */ + 0x6c, /* REG_ARXL2PGA (0x13) */ + 0x00, /* REG_VRXPGA (0x14) */ + 0x00, /* REG_VSTPGA (0x15) */ + 0x00, /* REG_VRX2ARXPGA (0x16) */ + 0x0c, /* REG_AVDAC_CTL (0x17) */ + 0x00, /* REG_ARX2VTXPGA (0x18) */ + 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ + 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ + 0x4b, /* REG_ARXL2_APGA_CTL (0x1B) */ + 0x4b, /* REG_ARXR2_APGA_CTL (0x1C) */ + 0x00, /* REG_ATX2ARXPGA (0x1D) */ + 0x00, /* REG_BT_IF (0x1E) */ + 0x00, /* REG_BTPGA (0x1F) */ + 0x00, /* REG_BTSTPGA (0x20) */ + 0x00, /* REG_EAR_CTL (0x21) */ + 0x24, /* REG_HS_SEL (0x22) */ + 0x0a, /* REG_HS_GAIN_SET (0x23) */ + 0x00, /* REG_HS_POPN_SET (0x24) */ + 0x00, /* REG_PREDL_CTL (0x25) */ + 0x00, /* REG_PREDR_CTL (0x26) */ + 0x00, /* REG_PRECKL_CTL (0x27) */ + 0x00, /* REG_PRECKR_CTL (0x28) */ + 0x00, /* REG_HFL_CTL (0x29) */ + 0x00, /* REG_HFR_CTL (0x2A) */ + 0x00, /* REG_ALC_CTL (0x2B) */ + 0x00, /* REG_ALC_SET1 (0x2C) */ + 0x00, /* REG_ALC_SET2 (0x2D) */ + 0x00, /* REG_BOOST_CTL (0x2E) */ + 0x01, /* REG_SOFTVOL_CTL (0x2F) */ + 0x00, /* REG_DTMF_FREQSEL (0x30) */ + 0x00, /* REG_DTMF_TONEXT1H (0x31) */ + 0x00, /* REG_DTMF_TONEXT1L (0x32) */ + 0x00, /* REG_DTMF_TONEXT2H (0x33) */ + 0x00, /* REG_DTMF_TONEXT2L (0x34) */ + 0x00, /* REG_DTMF_TONOFF (0x35) */ + 0x00, /* REG_DTMF_WANONOFF (0x36) */ + 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ + 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ + 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ + 0x16, /* REG_APLL_CTL (0x3A) */ + 0x00, /* REG_DTMF_CTL (0x3B) */ + 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ + 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ + 0x00, /* REG_MISC_SET_1 (0x3E) */ + 0x00, /* REG_PCMBTMUX (0x3F) */ + 0x00, /* not used (0x40) */ + 0x00, /* not used (0x41) */ + 0x00, /* not used (0x42) */ + 0x00, /* REG_RX_PATH_SEL (0x43) */ + 0x00, /* REG_VDL_APGA_CTL (0x44) */ + 0x00, /* REG_VIBRA_CTL (0x45) */ + 0x00, /* REG_VIBRA_SET (0x46) */ + 0x00, /* REG_VIBRA_PWM_SET (0x47) */ + 0x00, /* REG_ANAMIC_GAIN (0x48) */ + 0x00, /* REG_MISC_SET_2 (0x49) */ +}; + +/* + * read twl4030 register cache + */ +static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + + return cache[reg]; +} + +/* + * write twl4030 register cache + */ +static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec, + u8 reg, u8 value) +{ + u8 *cache = codec->reg_cache; + + if (reg >= TWL4030_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the twl4030 register space + */ +static int twl4030_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + twl4030_write_reg_cache(codec, reg, value); + return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); +} + +static void twl4030_clear_codecpdz(struct snd_soc_codec *codec) +{ + u8 mode; + + mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); + twl4030_write(codec, TWL4030_REG_CODEC_MODE, + mode & ~TWL4030_CODECPDZ); + + /* REVISIT: this delay is present in TI sample drivers */ + /* but there seems to be no TRM requirement for it */ + udelay(10); +} + +static void twl4030_set_codecpdz(struct snd_soc_codec *codec) +{ + u8 mode; + + mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); + twl4030_write(codec, TWL4030_REG_CODEC_MODE, + mode | TWL4030_CODECPDZ); + + /* REVISIT: this delay is present in TI sample drivers */ + /* but there seems to be no TRM requirement for it */ + udelay(10); +} + +static void twl4030_init_chip(struct snd_soc_codec *codec) +{ + int i; + + /* clear CODECPDZ prior to setting register defaults */ + twl4030_clear_codecpdz(codec); + + /* set all audio section registers to reasonable defaults */ + for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) + twl4030_write(codec, i, twl4030_reg[i]); + +} + +static const struct snd_kcontrol_new twl4030_snd_controls[] = { + SOC_DOUBLE_R("Master Playback Volume", + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, + 0, 127, 0), + SOC_DOUBLE_R("Capture Volume", + TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, + 0, 127, 0), +}; + +/* add non dapm controls */ +static int twl4030_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&twl4030_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("INL"), + SND_SOC_DAPM_INPUT("INR"), + + SND_SOC_DAPM_OUTPUT("OUTL"), + SND_SOC_DAPM_OUTPUT("OUTR"), + + SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route intercon[] = { + /* outputs */ + {"OUTL", NULL, "DACL"}, + {"OUTR", NULL, "DACR"}, + + /* inputs */ + {"ADCL", NULL, "INL"}, + {"ADCR", NULL, "INR"}, +}; + +static int twl4030_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets, + ARRAY_SIZE(twl4030_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static void twl4030_power_up(struct snd_soc_codec *codec) +{ + u8 anamicl, regmisc1, byte, popn, hsgain; + int i = 0; + + /* set CODECPDZ to turn on codec */ + twl4030_set_codecpdz(codec); + + /* initiate offset cancellation */ + anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); + twl4030_write(codec, TWL4030_REG_ANAMICL, + anamicl | TWL4030_CNCL_OFFSET_START); + + /* wait for offset cancellation to complete */ + do { + /* this takes a little while, so don't slam i2c */ + udelay(2000); + twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, + TWL4030_REG_ANAMICL); + } while ((i++ < 100) && + ((byte & TWL4030_CNCL_OFFSET_START) == + TWL4030_CNCL_OFFSET_START)); + + /* anti-pop when changing analog gain */ + regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); + twl4030_write(codec, TWL4030_REG_MISC_SET_1, + regmisc1 | TWL4030_SMOOTH_ANAVOL_EN); + + /* toggle CODECPDZ as per TRM */ + twl4030_clear_codecpdz(codec); + twl4030_set_codecpdz(codec); + + /* program anti-pop with bias ramp delay */ + popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + popn &= TWL4030_RAMP_DELAY; + popn |= TWL4030_RAMP_DELAY_645MS; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); + popn |= TWL4030_VMID_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); + + /* enable output stage and gain setting */ + hsgain = TWL4030_HSR_GAIN_0DB | TWL4030_HSL_GAIN_0DB; + twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain); + + /* enable anti-pop ramp */ + popn |= TWL4030_RAMP_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); +} + +static void twl4030_power_down(struct snd_soc_codec *codec) +{ + u8 popn, hsgain; + + /* disable anti-pop ramp */ + popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + popn &= ~TWL4030_RAMP_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); + + /* disable output stage and gain setting */ + hsgain = TWL4030_HSR_GAIN_PWR_DOWN | TWL4030_HSL_GAIN_PWR_DOWN; + twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain); + + /* disable bias out */ + popn &= ~TWL4030_VMID_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); + + /* power down */ + twl4030_clear_codecpdz(codec); +} + +static int twl4030_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + twl4030_power_up(codec); + break; + case SND_SOC_BIAS_PREPARE: + /* TODO: develop a twl4030_prepare function */ + break; + case SND_SOC_BIAS_STANDBY: + /* TODO: develop a twl4030_standby function */ + twl4030_power_down(codec); + break; + case SND_SOC_BIAS_OFF: + twl4030_power_down(codec); + break; + } + codec->bias_level = level; + + return 0; +} + +static int twl4030_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_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u8 mode, old_mode, format, old_format; + + + /* bit rate */ + old_mode = twl4030_read_reg_cache(codec, + TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; + mode = old_mode & ~TWL4030_APLL_RATE; + + switch (params_rate(params)) { + case 8000: + mode |= TWL4030_APLL_RATE_8000; + break; + case 11025: + mode |= TWL4030_APLL_RATE_11025; + break; + case 12000: + mode |= TWL4030_APLL_RATE_12000; + break; + case 16000: + mode |= TWL4030_APLL_RATE_16000; + break; + case 22050: + mode |= TWL4030_APLL_RATE_22050; + break; + case 24000: + mode |= TWL4030_APLL_RATE_24000; + break; + case 32000: + mode |= TWL4030_APLL_RATE_32000; + break; + case 44100: + mode |= TWL4030_APLL_RATE_44100; + break; + case 48000: + mode |= TWL4030_APLL_RATE_48000; + break; + default: + printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", + params_rate(params)); + return -EINVAL; + } + + if (mode != old_mode) { + /* change rate and set CODECPDZ */ + twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); + twl4030_set_codecpdz(codec); + } + + /* sample size */ + old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + format = old_format; + format &= ~TWL4030_DATA_WIDTH; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + format |= TWL4030_DATA_WIDTH_16S_16W; + break; + case SNDRV_PCM_FORMAT_S24_LE: + format |= TWL4030_DATA_WIDTH_32S_24W; + break; + default: + printk(KERN_ERR "TWL4030 hw params: unknown format %d\n", + params_format(params)); + return -EINVAL; + } + + if (format != old_format) { + + /* clear CODECPDZ before changing format (codec requirement) */ + twl4030_clear_codecpdz(codec); + + /* change format */ + twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); + + /* set CODECPDZ afterwards */ + twl4030_set_codecpdz(codec); + } + return 0; +} + +static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 infreq; + + switch (freq) { + case 19200000: + infreq = TWL4030_APLL_INFREQ_19200KHZ; + break; + case 26000000: + infreq = TWL4030_APLL_INFREQ_26000KHZ; + break; + case 38400000: + infreq = TWL4030_APLL_INFREQ_38400KHZ; + break; + default: + printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n", + freq); + return -EINVAL; + } + + infreq |= TWL4030_APLL_EN; + twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq); + + return 0; +} + +static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 old_format, format; + + /* get format */ + old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + format = old_format; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + format &= ~(TWL4030_AIF_SLAVE_EN); + format |= TWL4030_CLK256FS_EN; + break; + case SND_SOC_DAIFMT_CBS_CFS: + format &= ~(TWL4030_CLK256FS_EN); + format |= TWL4030_AIF_SLAVE_EN; + break; + default: + return -EINVAL; + } + + /* interface format */ + format &= ~TWL4030_AIF_FORMAT; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + format |= TWL4030_AIF_FORMAT_CODEC; + break; + default: + return -EINVAL; + } + + if (format != old_format) { + + /* clear CODECPDZ before changing format (codec requirement) */ + twl4030_clear_codecpdz(codec); + + /* change format */ + twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); + + /* set CODECPDZ afterwards */ + twl4030_set_codecpdz(codec); + } + + return 0; +} + +#define TWL4030_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) + +struct snd_soc_dai twl4030_dai = { + .name = "twl4030", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = TWL4030_RATES, + .formats = TWL4030_FORMATS,}, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = TWL4030_RATES, + .formats = TWL4030_FORMATS,}, + .ops = { + .hw_params = twl4030_hw_params, + }, + .dai_ops = { + .set_sysclk = twl4030_set_dai_sysclk, + .set_fmt = twl4030_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(twl4030_dai); + +static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int twl4030_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + twl4030_set_bias_level(codec, codec->suspend_bias_level); + return 0; +} + +/* + * initialize the driver + * register the mixer and dsp interfaces with the kernel + */ + +static int twl4030_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int ret = 0; + + printk(KERN_INFO "TWL4030 Audio Codec init \n"); + + codec->name = "twl4030"; + codec->owner = THIS_MODULE; + codec->read = twl4030_read_reg_cache; + codec->write = twl4030_write; + codec->set_bias_level = twl4030_set_bias_level; + codec->dai = &twl4030_dai; + codec->num_dai = 1; + codec->reg_cache_size = sizeof(twl4030_reg); + codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), + GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "twl4030: failed to create pcms\n"); + goto pcm_err; + } + + twl4030_init_chip(codec); + + /* power on device */ + twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + twl4030_add_controls(codec); + twl4030_add_widgets(codec); + + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "twl4030: failed to register card\n"); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +static struct snd_soc_device *twl4030_socdev; + +static int twl4030_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + twl4030_socdev = socdev; + twl4030_init(socdev); + + return 0; +} + +static int twl4030_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + printk(KERN_INFO "TWL4030 Audio Codec remove\n"); + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_twl4030 = { + .probe = twl4030_probe, + .remove = twl4030_remove, + .suspend = twl4030_suspend, + .resume = twl4030_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); + +MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); +MODULE_AUTHOR("Steve Sakoman"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h new file mode 100644 index 00000000000..09865d9f520 --- /dev/null +++ b/sound/soc/codecs/twl4030.h @@ -0,0 +1,197 @@ +/* + * ALSA SoC TWL4030 codec driver + * + * Author: Steve Sakoman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __TWL4030_AUDIO_H__ +#define __TWL4030_AUDIO_H__ + +#define TWL4030_REG_CODEC_MODE 0x1 +#define TWL4030_REG_OPTION 0x2 +#define TWL4030_REG_UNKNOWN 0x3 +#define TWL4030_REG_MICBIAS_CTL 0x4 +#define TWL4030_REG_ANAMICL 0x5 +#define TWL4030_REG_ANAMICR 0x6 +#define TWL4030_REG_AVADC_CTL 0x7 +#define TWL4030_REG_ADCMICSEL 0x8 +#define TWL4030_REG_DIGMIXING 0x9 +#define TWL4030_REG_ATXL1PGA 0xA +#define TWL4030_REG_ATXR1PGA 0xB +#define TWL4030_REG_AVTXL2PGA 0xC +#define TWL4030_REG_AVTXR2PGA 0xD +#define TWL4030_REG_AUDIO_IF 0xE +#define TWL4030_REG_VOICE_IF 0xF +#define TWL4030_REG_ARXR1PGA 0x10 +#define TWL4030_REG_ARXL1PGA 0x11 +#define TWL4030_REG_ARXR2PGA 0x12 +#define TWL4030_REG_ARXL2PGA 0x13 +#define TWL4030_REG_VRXPGA 0x14 +#define TWL4030_REG_VSTPGA 0x15 +#define TWL4030_REG_VRX2ARXPGA 0x16 +#define TWL4030_REG_AVDAC_CTL 0x17 +#define TWL4030_REG_ARX2VTXPGA 0x18 +#define TWL4030_REG_ARXL1_APGA_CTL 0x19 +#define TWL4030_REG_ARXR1_APGA_CTL 0x1A +#define TWL4030_REG_ARXL2_APGA_CTL 0x1B +#define TWL4030_REG_ARXR2_APGA_CTL 0x1C +#define TWL4030_REG_ATX2ARXPGA 0x1D +#define TWL4030_REG_BT_IF 0x1E +#define TWL4030_REG_BTPGA 0x1F +#define TWL4030_REG_BTSTPGA 0x20 +#define TWL4030_REG_EAR_CTL 0x21 +#define TWL4030_REG_HS_SEL 0x22 +#define TWL4030_REG_HS_GAIN_SET 0x23 +#define TWL4030_REG_HS_POPN_SET 0x24 +#define TWL4030_REG_PREDL_CTL 0x25 +#define TWL4030_REG_PREDR_CTL 0x26 +#define TWL4030_REG_PRECKL_CTL 0x27 +#define TWL4030_REG_PRECKR_CTL 0x28 +#define TWL4030_REG_HFL_CTL 0x29 +#define TWL4030_REG_HFR_CTL 0x2A +#define TWL4030_REG_ALC_CTL 0x2B +#define TWL4030_REG_ALC_SET1 0x2C +#define TWL4030_REG_ALC_SET2 0x2D +#define TWL4030_REG_BOOST_CTL 0x2E +#define TWL4030_REG_SOFTVOL_CTL 0x2F +#define TWL4030_REG_DTMF_FREQSEL 0x30 +#define TWL4030_REG_DTMF_TONEXT1H 0x31 +#define TWL4030_REG_DTMF_TONEXT1L 0x32 +#define TWL4030_REG_DTMF_TONEXT2H 0x33 +#define TWL4030_REG_DTMF_TONEXT2L 0x34 +#define TWL4030_REG_DTMF_TONOFF 0x35 +#define TWL4030_REG_DTMF_WANONOFF 0x36 +#define TWL4030_REG_I2S_RX_SCRAMBLE_H 0x37 +#define TWL4030_REG_I2S_RX_SCRAMBLE_M 0x38 +#define TWL4030_REG_I2S_RX_SCRAMBLE_L 0x39 +#define TWL4030_REG_APLL_CTL 0x3A +#define TWL4030_REG_DTMF_CTL 0x3B +#define TWL4030_REG_DTMF_PGA_CTL2 0x3C +#define TWL4030_REG_DTMF_PGA_CTL1 0x3D +#define TWL4030_REG_MISC_SET_1 0x3E +#define TWL4030_REG_PCMBTMUX 0x3F +#define TWL4030_REG_RX_PATH_SEL 0x43 +#define TWL4030_REG_VDL_APGA_CTL 0x44 +#define TWL4030_REG_VIBRA_CTL 0x45 +#define TWL4030_REG_VIBRA_SET 0x46 +#define TWL4030_REG_VIBRA_PWM_SET 0x47 +#define TWL4030_REG_ANAMIC_GAIN 0x48 +#define TWL4030_REG_MISC_SET_2 0x49 + +#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) + +/* Bitfield Definitions */ + +/* TWL4030_CODEC_MODE (0x01) Fields */ + +#define TWL4030_APLL_RATE 0xF0 +#define TWL4030_APLL_RATE_8000 0x00 +#define TWL4030_APLL_RATE_11025 0x10 +#define TWL4030_APLL_RATE_12000 0x20 +#define TWL4030_APLL_RATE_16000 0x40 +#define TWL4030_APLL_RATE_22050 0x50 +#define TWL4030_APLL_RATE_24000 0x60 +#define TWL4030_APLL_RATE_32000 0x80 +#define TWL4030_APLL_RATE_44100 0x90 +#define TWL4030_APLL_RATE_48000 0xA0 +#define TWL4030_SEL_16K 0x04 +#define TWL4030_CODECPDZ 0x02 +#define TWL4030_OPT_MODE 0x01 + +/* ANAMICL (0x05) Fields */ +#define TWL4030_CNCL_OFFSET_START 0x80 +#define TWL4030_OFFSET_CNCL_SEL 0x60 +#define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 +#define TWL4030_OFFSET_CNCL_SEL_ARX2 0x20 +#define TWL4030_OFFSET_CNCL_SEL_VRX 0x40 +#define TWL4030_OFFSET_CNCL_SEL_ALL 0x60 +#define TWL4030_MICAMPL_EN 0x10 +#define TWL4030_CKMIC_EN 0x08 +#define TWL4030_AUXL_EN 0x04 +#define TWL4030_HSMIC_EN 0x02 +#define TWL4030_MAINMIC_EN 0x01 + +/* ANAMICR (0x06) Fields */ +#define TWL4030_MICAMPR_EN 0x10 +#define TWL4030_AUXR_EN 0x04 +#define TWL4030_SUBMIC_EN 0x01 + +/* AUDIO_IF (0x0E) Fields */ + +#define TWL4030_AIF_SLAVE_EN 0x80 +#define TWL4030_DATA_WIDTH 0x60 +#define TWL4030_DATA_WIDTH_16S_16W 0x00 +#define TWL4030_DATA_WIDTH_32S_16W 0x40 +#define TWL4030_DATA_WIDTH_32S_24W 0x60 +#define TWL4030_AIF_FORMAT 0x18 +#define TWL4030_AIF_FORMAT_CODEC 0x00 +#define TWL4030_AIF_FORMAT_LEFT 0x08 +#define TWL4030_AIF_FORMAT_RIGHT 0x10 +#define TWL4030_AIF_FORMAT_TDM 0x18 +#define TWL4030_AIF_TRI_EN 0x04 +#define TWL4030_CLK256FS_EN 0x02 +#define TWL4030_AIF_EN 0x01 + +/* HS_GAIN_SET (0x23) Fields */ + +#define TWL4030_HSR_GAIN 0x0C +#define TWL4030_HSR_GAIN_PWR_DOWN 0x00 +#define TWL4030_HSR_GAIN_PLUS_6DB 0x04 +#define TWL4030_HSR_GAIN_0DB 0x08 +#define TWL4030_HSR_GAIN_MINUS_6DB 0x0C +#define TWL4030_HSL_GAIN 0x03 +#define TWL4030_HSL_GAIN_PWR_DOWN 0x00 +#define TWL4030_HSL_GAIN_PLUS_6DB 0x01 +#define TWL4030_HSL_GAIN_0DB 0x02 +#define TWL4030_HSL_GAIN_MINUS_6DB 0x03 + +/* HS_POPN_SET (0x24) Fields */ + +#define TWL4030_VMID_EN 0x40 +#define TWL4030_EXTMUTE 0x20 +#define TWL4030_RAMP_DELAY 0x1C +#define TWL4030_RAMP_DELAY_20MS 0x00 +#define TWL4030_RAMP_DELAY_40MS 0x04 +#define TWL4030_RAMP_DELAY_81MS 0x08 +#define TWL4030_RAMP_DELAY_161MS 0x0C +#define TWL4030_RAMP_DELAY_323MS 0x10 +#define TWL4030_RAMP_DELAY_645MS 0x14 +#define TWL4030_RAMP_DELAY_1291MS 0x18 +#define TWL4030_RAMP_DELAY_2581MS 0x1C +#define TWL4030_RAMP_EN 0x02 + +/* APLL_CTL (0x3A) Fields */ + +#define TWL4030_APLL_EN 0x10 +#define TWL4030_APLL_INFREQ 0x0F +#define TWL4030_APLL_INFREQ_19200KHZ 0x05 +#define TWL4030_APLL_INFREQ_26000KHZ 0x06 +#define TWL4030_APLL_INFREQ_38400KHZ 0x0F + +/* REG_MISC_SET_1 (0x3E) Fields */ + +#define TWL4030_CLK64_EN 0x80 +#define TWL4030_SCRAMBLE_EN 0x40 +#define TWL4030_FMLOOP_EN 0x20 +#define TWL4030_SMOOTH_ANAVOL_EN 0x02 +#define TWL4030_DIGMIC_LR_SWAP_EN 0x01 + +extern struct snd_soc_dai twl4030_dai; +extern struct snd_soc_codec_device soc_codec_dev_twl4030; + +#endif /* End of __TWL4030_AUDIO_H__ */ -- cgit v1.2.3 From 4e207873736adc55cbf92796eb4f26f280f84034 Mon Sep 17 00:00:00 2001 From: Steve Sakoman Date: Thu, 30 Oct 2008 21:50:13 -0700 Subject: ASoC: Add support for Gumstix Overo Signed-off-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 10 ++++ sound/soc/omap/Makefile | 3 + sound/soc/omap/overo.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 sound/soc/omap/overo.c diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 8b7766b998d..cf40e42954a 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -21,3 +21,13 @@ config SND_OMAP_SOC_OSK5912 select SND_SOC_TLV320AIC23 help Say Y if you want to add support for SoC audio on osk5912. + +config SND_OMAP_SOC_OVERO + tristate "SoC Audio support for Gumstix Overo" + depends on SND_OMAP_SOC && MACH_OVERO + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the Gumstix Overo. + + diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index e09d1f297f6..fefc9bed053 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -8,6 +8,9 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o # OMAP Machine Support snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o +snd-soc-overo-objs := overo.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o +obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o + diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c new file mode 100644 index 00000000000..c26d1de7da5 --- /dev/null +++ b/sound/soc/omap/overo.c @@ -0,0 +1,148 @@ +/* + * overo.c -- SoC audio for Gumstix Overo + * + * Author: Steve Sakoman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int overo_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops overo_ops = { + .hw_params = overo_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link overo_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &overo_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_overo = { + .name = "overo", + .dai_link = &overo_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device overo_snd_devdata = { + .machine = &snd_soc_machine_overo, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *overo_snd_device; + +static int __init overo_soc_init(void) +{ + int ret; + + if (!machine_is_overo()) { + pr_debug("Not Overo!\n"); + return -ENODEV; + } + printk(KERN_INFO "overo SoC init\n"); + + overo_snd_device = platform_device_alloc("soc-audio", -1); + if (!overo_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(overo_snd_device, &overo_snd_devdata); + overo_snd_devdata.dev = &overo_snd_device->dev; + *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(overo_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(overo_snd_device); + + return ret; +} +module_init(overo_soc_init); + +static void __exit overo_soc_exit(void) +{ + platform_device_unregister(overo_snd_device); +} +module_exit(overo_soc_exit); + +MODULE_AUTHOR("Steve Sakoman "); +MODULE_DESCRIPTION("ALSA SoC overo"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From dc06102a0c8b5aa0dd7f9a40ce241e793c252a87 Mon Sep 17 00:00:00 2001 From: Steve Sakoman Date: Thu, 30 Oct 2008 21:55:24 -0700 Subject: ASoC: Add support for Beagleboard Signed-off-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/omap/omap3beagle.c | 149 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 sound/soc/omap/omap3beagle.c diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c new file mode 100644 index 00000000000..ec84a9bbc56 --- /dev/null +++ b/sound/soc/omap/omap3beagle.c @@ -0,0 +1,149 @@ +/* + * omap3beagle.c -- SoC audio for OMAP3 Beagle + * + * Author: Steve Sakoman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int omap3beagle_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops omap3beagle_ops = { + .hw_params = omap3beagle_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap3beagle_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap3beagle_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_omap3beagle = { + .name = "omap3beagle", + .dai_link = &omap3beagle_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device omap3beagle_snd_devdata = { + .machine = &snd_soc_machine_omap3beagle, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap3beagle_snd_device; + +static int __init omap3beagle_soc_init(void) +{ + int ret; + + if (!machine_is_omap3_beagle()) { + pr_debug("Not OMAP3 Beagle!\n"); + return -ENODEV; + } + pr_info("OMAP3 Beagle SoC init\n"); + + omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); + if (!omap3beagle_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata); + omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev; + *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(omap3beagle_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(omap3beagle_snd_device); + + return ret; +} + +static void __exit omap3beagle_soc_exit(void) +{ + platform_device_unregister(omap3beagle_snd_device); +} + +module_init(omap3beagle_soc_init); +module_exit(omap3beagle_soc_exit); + +MODULE_AUTHOR("Steve Sakoman "); +MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 6c7425095c9ee23d080dba3e27217a254cce4562 Mon Sep 17 00:00:00 2001 From: Sedji Gaouaou Date: Fri, 3 Oct 2008 16:57:50 +0200 Subject: ASoC: Merge AT91 and AVR32 support into a single atmel architecture The Ateml AT91 and AVR32 SoC share common IP for audio and can share the same driver code using the atmel-ssc API provided for both architectures. Do this, creating a new unified atmel ASoC architecture to replace the previous at32 and at91 ones. [This was contributed as a patch series for reviewability but has been squashed down to a single commit to help preserve both the history and bisectability. A small bugfix from Jukka is included.] Tested-by: Jukka Hynninen Signed-off-by: Sedji Gaouaou Signed-off-by: Mark Brown --- sound/soc/Kconfig | 3 +- sound/soc/Makefile | 2 +- sound/soc/at32/Kconfig | 34 -- sound/soc/at32/Makefile | 11 - sound/soc/at32/at32-pcm.c | 492 ----------------------- sound/soc/at32/at32-pcm.h | 79 ---- sound/soc/at32/at32-ssc.c | 849 --------------------------------------- sound/soc/at32/at32-ssc.h | 59 --- sound/soc/at32/playpaq_wm8510.c | 513 ----------------------- sound/soc/at91/Kconfig | 10 - sound/soc/at91/Makefile | 6 - sound/soc/at91/at91-pcm.c | 434 -------------------- sound/soc/at91/at91-pcm.h | 72 ---- sound/soc/at91/at91-ssc.c | 791 ------------------------------------ sound/soc/at91/at91-ssc.h | 27 -- sound/soc/atmel/Kconfig | 43 ++ sound/soc/atmel/Makefile | 15 + sound/soc/atmel/atmel-pcm.c | 484 ++++++++++++++++++++++ sound/soc/atmel/atmel-pcm.h | 86 ++++ sound/soc/atmel/atmel_ssc_dai.c | 782 ++++++++++++++++++++++++++++++++++++ sound/soc/atmel/atmel_ssc_dai.h | 121 ++++++ sound/soc/atmel/playpaq_wm8510.c | 513 +++++++++++++++++++++++ 22 files changed, 2046 insertions(+), 3380 deletions(-) delete mode 100644 sound/soc/at32/Kconfig delete mode 100644 sound/soc/at32/Makefile delete mode 100644 sound/soc/at32/at32-pcm.c delete mode 100644 sound/soc/at32/at32-pcm.h delete mode 100644 sound/soc/at32/at32-ssc.c delete mode 100644 sound/soc/at32/at32-ssc.h delete mode 100644 sound/soc/at32/playpaq_wm8510.c delete mode 100644 sound/soc/at91/Kconfig delete mode 100644 sound/soc/at91/Makefile delete mode 100644 sound/soc/at91/at91-pcm.c delete mode 100644 sound/soc/at91/at91-pcm.h delete mode 100644 sound/soc/at91/at91-ssc.c delete mode 100644 sound/soc/at91/at91-ssc.h create mode 100644 sound/soc/atmel/Kconfig create mode 100644 sound/soc/atmel/Makefile create mode 100644 sound/soc/atmel/atmel-pcm.c create mode 100644 sound/soc/atmel/atmel-pcm.h create mode 100644 sound/soc/atmel/atmel_ssc_dai.c create mode 100644 sound/soc/atmel/atmel_ssc_dai.h create mode 100644 sound/soc/atmel/playpaq_wm8510.c diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 4dfda6674be..615ebf0b76e 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -23,8 +23,7 @@ config SND_SOC_AC97_BUS bool # All the supported Soc's -source "sound/soc/at32/Kconfig" -source "sound/soc/at91/Kconfig" +source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index d849349f2c6..4d475c3ceb9 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ +obj-$(CONFIG_SND_SOC) += codecs/ atmel/ pxa/ s3c24xx/ sh/ fsl/ davinci/ obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ diff --git a/sound/soc/at32/Kconfig b/sound/soc/at32/Kconfig deleted file mode 100644 index b0765e86c08..00000000000 --- a/sound/soc/at32/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config SND_AT32_SOC - tristate "SoC Audio for the Atmel AT32 System-on-a-Chip" - depends on AVR32 && SND_SOC - help - Say Y or M if you want to add support for codecs attached to - the AT32 SSC interface. You will also need to - to select the audio interfaces to support below. - - -config SND_AT32_SOC_SSC - tristate - - - -config SND_AT32_SOC_PLAYPAQ - tristate "SoC Audio support for PlayPaq with WM8510" - depends on SND_AT32_SOC && BOARD_PLAYPAQ - select SND_AT32_SOC_SSC - select SND_SOC_WM8510 - help - Say Y or M here if you want to add support for SoC audio - on the LRS PlayPaq. - - - -config SND_AT32_SOC_PLAYPAQ_SLAVE - bool "Run CODEC on PlayPaq in slave mode" - depends on SND_AT32_SOC_PLAYPAQ - default n - help - Say Y if you want to run with the AT32 SSC generating the BCLK - and FRAME signals on the PlayPaq. Unless you want to play - with the AT32 as the SSC master, you probably want to say N here, - as this will give you better sound quality. diff --git a/sound/soc/at32/Makefile b/sound/soc/at32/Makefile deleted file mode 100644 index c03e55ecece..00000000000 --- a/sound/soc/at32/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# AT32 Platform Support -snd-soc-at32-objs := at32-pcm.o -snd-soc-at32-ssc-objs := at32-ssc.o - -obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o -obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o - -# AT32 Machine Support -snd-soc-playpaq-objs := playpaq_wm8510.o - -obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/at32/at32-pcm.c deleted file mode 100644 index c83584f989a..00000000000 --- a/sound/soc/at32/at32-pcm.c +++ /dev/null @@ -1,492 +0,0 @@ -/* sound/soc/at32/at32-pcm.c - * ASoC PCM interface for Atmel AT32 SoC - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * 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. - * - * Note that this is basically a port of the sound/soc/at91-pcm.c to - * the AVR32 kernel. Thanks to Frank Mandarino for that code. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "at32-pcm.h" - - - -/*--------------------------------------------------------------------------*\ - * Hardware definition -\*--------------------------------------------------------------------------*/ -/* TODO: These values were taken from the AT91 platform driver, check - * them against real values for AT32 - */ -static const struct snd_pcm_hardware at32_pcm_hardware = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_PAUSE), - - .formats = SNDRV_PCM_FMTBIT_S16, - .period_bytes_min = 32, - .period_bytes_max = 8192, /* 512 frames * 16 bytes / frame */ - .periods_min = 2, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, -}; - - - -/*--------------------------------------------------------------------------*\ - * Data types -\*--------------------------------------------------------------------------*/ -struct at32_runtime_data { - struct at32_pcm_dma_params *params; - dma_addr_t dma_buffer; /* physical address of DMA buffer */ - dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ - size_t period_size; - - dma_addr_t period_ptr; /* physical address of next period */ - int periods; /* period index of period_ptr */ - - /* Save PDC registers (for power management) */ - u32 pdc_xpr_save; - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - - - -/*--------------------------------------------------------------------------*\ - * Helper functions -\*--------------------------------------------------------------------------*/ -static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *dmabuf = &substream->dma_buffer; - size_t size = at32_pcm_hardware.buffer_bytes_max; - - dmabuf->dev.type = SNDRV_DMA_TYPE_DEV; - dmabuf->dev.dev = pcm->card->dev; - dmabuf->private_data = NULL; - dmabuf->area = dma_alloc_coherent(pcm->card->dev, size, - &dmabuf->addr, GFP_KERNEL); - pr_debug("at32_pcm: preallocate_dma_buffer: " - "area=%p, addr=%p, size=%ld\n", - (void *)dmabuf->area, (void *)dmabuf->addr, size); - - if (!dmabuf->area) - return -ENOMEM; - - dmabuf->bytes = size; - return 0; -} - - - -/*--------------------------------------------------------------------------*\ - * ISR -\*--------------------------------------------------------------------------*/ -static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *rtd = substream->runtime; - struct at32_runtime_data *prtd = rtd->private_data; - struct at32_pcm_dma_params *params = prtd->params; - static int count; - - count++; - if (ssc_sr & params->mask->ssc_endbuf) { - pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "underrun" : "overrun", params->name, ssc_sr, count); - - /* re-start the PDC */ - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - } - - - if (ssc_sr & params->mask->ssc_endx) { - /* Load the PDC next pointer and counter registers */ - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - - snd_pcm_period_elapsed(substream); -} - - - -/*--------------------------------------------------------------------------*\ - * PCM operations -\*--------------------------------------------------------------------------*/ -static int at32_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at32_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* this may get called several times by oss emulation - * with different params - */ - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->params = rtd->dai->cpu_dai->dma_data; - prtd->params->dma_intr_handler = at32_pcm_dma_irq; - - prtd->dma_buffer = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; - prtd->period_size = params_period_bytes(params); - - pr_debug("hw_params: DMA for %s initialized " - "(dma_bytes=%ld, period_size=%ld)\n", - prtd->params->name, runtime->dma_bytes, prtd->period_size); - - return 0; -} - - - -static int at32_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct at32_runtime_data *prtd = substream->runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; - - if (params != NULL) { - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - - - -static int at32_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct at32_runtime_data *prtd = substream->runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; - - ssc_writex(params->ssc->regs, SSC_IDR, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - - return 0; -} - - -static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_pcm_runtime *rtd = substream->runtime; - struct at32_runtime_data *prtd = rtd->private_data; - struct at32_pcm_dma_params *params = prtd->params; - int ret = 0; - - pr_debug("at32_pcm_trigger: buffer_size = %ld, " - "dma_area = %p, dma_bytes = %ld\n", - rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - pr_debug("trigger: period_ptr=%lx, xpr=%x, " - "xcr=%d, xnpr=%x, xncr=%d\n", - (unsigned long)prtd->period_ptr, - ssc_readx(params->ssc->regs, params->pdc->xpr), - ssc_readx(params->ssc->regs, params->pdc->xcr), - ssc_readx(params->ssc->regs, params->pdc->xnpr), - ssc_readx(params->ssc->regs, params->pdc->xncr)); - - ssc_writex(params->ssc->regs, SSC_IER, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_enable); - - pr_debug("sr=%x, imr=%x\n", - ssc_readx(params->ssc->regs, SSC_SR), - ssc_readx(params->ssc->regs, SSC_IER)); - break; /* SNDRV_PCM_TRIGGER_START */ - - - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - break; - - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - - - -static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at32_runtime_data *prtd = runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - - return x; -} - - - -static int at32_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at32_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto out; - - prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - -out: - return ret; -} - - - -static int at32_pcm_close(struct snd_pcm_substream *substream) -{ - struct at32_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - - -static int at32_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - return remap_pfn_range(vma, vma->vm_start, - substream->dma_buffer.addr >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); -} - - - -static struct snd_pcm_ops at32_pcm_ops = { - .open = at32_pcm_open, - .close = at32_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = at32_pcm_hw_params, - .hw_free = at32_pcm_hw_free, - .prepare = at32_pcm_prepare, - .trigger = at32_pcm_trigger, - .pointer = at32_pcm_pointer, - .mmap = at32_pcm_mmap, -}; - - - -/*--------------------------------------------------------------------------*\ - * ASoC platform driver -\*--------------------------------------------------------------------------*/ -static u64 at32_pcm_dmamask = 0xffffffff; - -static int at32_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, - struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &at32_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = at32_pcm_preallocate_dma_buffer( - pcm, SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n"); - ret = at32_pcm_preallocate_dma_buffer( - pcm, SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - - -out: - return ret; -} - - - -static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (substream == NULL) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - dma_free_coherent(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - - - -#ifdef CONFIG_PM -static int at32_pcm_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at32_runtime_data *prtd; - struct at32_pcm_dma_params *params; - - if (runtime == NULL) - return 0; - prtd = runtime->private_data; - params = prtd->params; - - /* Disable the PDC and save the PDC registers */ - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - - prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); - prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); - prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); - prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); - - return 0; -} - - - -static int at32_pcm_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at32_runtime_data *prtd; - struct at32_pcm_dma_params *params; - - if (runtime == NULL) - return 0; - prtd = runtime->private_data; - params = prtd->params; - - /* Restore the PDC registers and enable the PDC */ - ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); - ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); - ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); - ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); - - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else /* CONFIG_PM */ -# define at32_pcm_suspend NULL -# define at32_pcm_resume NULL -#endif /* CONFIG_PM */ - - - -struct snd_soc_platform at32_soc_platform = { - .name = "at32-audio", - .pcm_ops = &at32_pcm_ops, - .pcm_new = at32_pcm_new, - .pcm_free = at32_pcm_free_dma_buffers, - .suspend = at32_pcm_suspend, - .resume = at32_pcm_resume, -}; -EXPORT_SYMBOL_GPL(at32_soc_platform); - - - -MODULE_AUTHOR("Geoffrey Wossum "); -MODULE_DESCRIPTION("Atmel AT32 PCM module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at32/at32-pcm.h b/sound/soc/at32/at32-pcm.h deleted file mode 100644 index 2a52430417d..00000000000 --- a/sound/soc/at32/at32-pcm.h +++ /dev/null @@ -1,79 +0,0 @@ -/* sound/soc/at32/at32-pcm.h - * ASoC PCM interface for Atmel AT32 SoC - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * 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 __SOUND_SOC_AT32_AT32_PCM_H -#define __SOUND_SOC_AT32_AT32_PCM_H __FILE__ - -#include - - -/* - * Registers and status bits that are required by the PCM driver - * TODO: Is ptcr really used? - */ -struct at32_pdc_regs { - u32 xpr; /* PDC RX/TX pointer */ - u32 xcr; /* PDC RX/TX counter */ - u32 xnpr; /* PDC next RX/TX pointer */ - u32 xncr; /* PDC next RX/TX counter */ - u32 ptcr; /* PDC transfer control */ -}; - - - -/* - * SSC mask info - */ -struct at32_ssc_mask { - u32 ssc_enable; /* SSC RX/TX enable */ - u32 ssc_disable; /* SSC RX/TX disable */ - u32 ssc_endx; /* SSC ENDTX or ENDRX */ - u32 ssc_endbuf; /* SSC TXBUFF or RXBUFF */ - u32 pdc_enable; /* PDC RX/TX enable */ - u32 pdc_disable; /* PDC RX/TX disable */ -}; - - - -/* - * This structure, shared between the PCM driver and the interface, - * contains all information required by the PCM driver to perform the - * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dms_intr_handler() pointer is set by the PCM - * driver and called by the interface SSC interrupt handler if it is - * non-NULL. - */ -struct at32_pcm_dma_params { - char *name; /* stream identifier */ - int pdc_xfer_size; /* PDC counter increment in bytes */ - struct ssc_device *ssc; /* SSC device for stream */ - struct at32_pdc_regs *pdc; /* PDC register info */ - struct at32_ssc_mask *mask; /* SSC mask info */ - struct snd_pcm_substream *substream; - void (*dma_intr_handler) (u32, struct snd_pcm_substream *); -}; - - - -/* - * The AT32 ASoC platform driver - */ -extern struct snd_soc_platform at32_soc_platform; - - - -/* - * SSC register access (since ssc_writel() / ssc_readl() require literal name) - */ -#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) -#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) - -#endif /* __SOUND_SOC_AT32_AT32_PCM_H */ diff --git a/sound/soc/at32/at32-ssc.c b/sound/soc/at32/at32-ssc.c deleted file mode 100644 index 4ef6492c902..00000000000 --- a/sound/soc/at32/at32-ssc.c +++ /dev/null @@ -1,849 +0,0 @@ -/* sound/soc/at32/at32-ssc.c - * ASoC platform driver for AT32 using SSC as DAI - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * 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. - * - * Note that this is basically a port of the sound/soc/at91-ssc.c to - * the AVR32 kernel. Thanks to Frank Mandarino for that code. - */ - -/* #define DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "at32-pcm.h" -#include "at32-ssc.h" - - - -/*-------------------------------------------------------------------------*\ - * Constants -\*-------------------------------------------------------------------------*/ -#define NUM_SSC_DEVICES 3 - -/* - * SSC direction masks - */ -#define SSC_DIR_MASK_UNUSED 0 -#define SSC_DIR_MASK_PLAYBACK 1 -#define SSC_DIR_MASK_CAPTURE 2 - -/* - * SSC register values that Atmel left out of . These - * are expected to be used with SSC_BF - */ -/* START bit field values */ -#define SSC_START_CONTINUOUS 0 -#define SSC_START_TX_RX 1 -#define SSC_START_LOW_RF 2 -#define SSC_START_HIGH_RF 3 -#define SSC_START_FALLING_RF 4 -#define SSC_START_RISING_RF 5 -#define SSC_START_LEVEL_RF 6 -#define SSC_START_EDGE_RF 7 -#define SSS_START_COMPARE_0 8 - -/* CKI bit field values */ -#define SSC_CKI_FALLING 0 -#define SSC_CKI_RISING 1 - -/* CKO bit field values */ -#define SSC_CKO_NONE 0 -#define SSC_CKO_CONTINUOUS 1 -#define SSC_CKO_TRANSFER 2 - -/* CKS bit field values */ -#define SSC_CKS_DIV 0 -#define SSC_CKS_CLOCK 1 -#define SSC_CKS_PIN 2 - -/* FSEDGE bit field values */ -#define SSC_FSEDGE_POSITIVE 0 -#define SSC_FSEDGE_NEGATIVE 1 - -/* FSOS bit field values */ -#define SSC_FSOS_NONE 0 -#define SSC_FSOS_NEGATIVE 1 -#define SSC_FSOS_POSITIVE 2 -#define SSC_FSOS_LOW 3 -#define SSC_FSOS_HIGH 4 -#define SSC_FSOS_TOGGLE 5 - -#define START_DELAY 1 - - - -/*-------------------------------------------------------------------------*\ - * Module data -\*-------------------------------------------------------------------------*/ -/* - * SSC PDC registered required by the PCM DMA engine - */ -static struct at32_pdc_regs pdc_tx_reg = { - .xpr = SSC_PDC_TPR, - .xcr = SSC_PDC_TCR, - .xnpr = SSC_PDC_TNPR, - .xncr = SSC_PDC_TNCR, -}; - - - -static struct at32_pdc_regs pdc_rx_reg = { - .xpr = SSC_PDC_RPR, - .xcr = SSC_PDC_RCR, - .xnpr = SSC_PDC_RNPR, - .xncr = SSC_PDC_RNCR, -}; - - - -/* - * SSC and PDC status bits for transmit and receive - */ -static struct at32_ssc_mask ssc_tx_mask = { - .ssc_enable = SSC_BIT(CR_TXEN), - .ssc_disable = SSC_BIT(CR_TXDIS), - .ssc_endx = SSC_BIT(SR_ENDTX), - .ssc_endbuf = SSC_BIT(SR_TXBUFE), - .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN), - .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS), -}; - - - -static struct at32_ssc_mask ssc_rx_mask = { - .ssc_enable = SSC_BIT(CR_RXEN), - .ssc_disable = SSC_BIT(CR_RXDIS), - .ssc_endx = SSC_BIT(SR_ENDRX), - .ssc_endbuf = SSC_BIT(SR_RXBUFF), - .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN), - .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS), -}; - - - -/* - * DMA parameters for each SSC - */ -static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { - { - { - .name = "SSC0 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC0 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, - { - { - .name = "SSC1 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, - { - { - .name = "SSC2 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC2 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, -}; - - - -static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = { - { - .name = "ssc0", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc1", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc2", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, -}; - - - - -/*-------------------------------------------------------------------------*\ - * ISR -\*-------------------------------------------------------------------------*/ -/* - * SSC interrupt handler. Passes PDC interrupts to the DMA interrupt - * handler in the PCM driver. - */ -static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id) -{ - struct at32_ssc_info *ssc_p = dev_id; - struct at32_pcm_dma_params *dma_params; - u32 ssc_sr; - u32 ssc_substream_mask; - int i; - - ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) & - ssc_readl(ssc_p->ssc->regs, IMR)); - - /* - * Loop through substreams attached to this SSC. If a DMA-related - * interrupt occured on that substream, call the DMA interrupt - * handler function, if one has been registered in the dma_param - * structure by the PCM driver. - */ - for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { - dma_params = ssc_p->dma_params[i]; - - if ((dma_params != NULL) && - (dma_params->dma_intr_handler != NULL)) { - ssc_substream_mask = (dma_params->mask->ssc_endx | - dma_params->mask->ssc_endbuf); - if (ssc_sr & ssc_substream_mask) { - dma_params->dma_intr_handler(ssc_sr, - dma_params-> - substream); - } - } - } - - - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*\ - * DAI functions -\*-------------------------------------------------------------------------*/ -/* - * Startup. Only that one substream allowed in each direction. - */ -static int at32_ssc_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - int dir_mask; - - dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE); - - spin_lock_irq(&ssc_p->lock); - if (ssc_p->dir_mask & dir_mask) { - spin_unlock_irq(&ssc_p->lock); - return -EBUSY; - } - ssc_p->dir_mask |= dir_mask; - spin_unlock_irq(&ssc_p->lock); - - return 0; -} - - - -/* - * Shutdown. Clear DMA parameters and shutdown the SSC if there - * are no other substreams open. - */ -static void at32_ssc_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at32_pcm_dma_params *dma_params; - int dir_mask; - - dma_params = ssc_p->dma_params[substream->stream]; - - if (dma_params != NULL) { - ssc_writel(dma_params->ssc->regs, CR, - dma_params->mask->ssc_disable); - pr_debug("%s disabled SSC_SR=0x%08x\n", - (substream->stream ? "receiver" : "transmit"), - ssc_readl(ssc_p->ssc->regs, SR)); - - dma_params->ssc = NULL; - dma_params->substream = NULL; - ssc_p->dma_params[substream->stream] = NULL; - } - - - dir_mask = 1 << substream->stream; - spin_lock_irq(&ssc_p->lock); - ssc_p->dir_mask &= ~dir_mask; - if (!ssc_p->dir_mask) { - /* Shutdown the SSC clock */ - pr_debug("at32-ssc: Stopping user %d clock\n", - ssc_p->ssc->user); - clk_disable(ssc_p->ssc->clk); - - if (ssc_p->initialized) { - free_irq(ssc_p->ssc->irq, ssc_p); - ssc_p->initialized = 0; - } - - /* Reset the SSC */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - - /* clear the SSC dividers */ - ssc_p->cmr_div = 0; - ssc_p->tcmr_period = 0; - ssc_p->rcmr_period = 0; - } - spin_unlock_irq(&ssc_p->lock); -} - - - -/* - * Set the SSC system clock rate - */ -static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - /* TODO: What the heck do I do here? */ - return 0; -} - - - -/* - * Record DAI format for use by hw_params() - */ -static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - ssc_p->daifmt = fmt; - return 0; -} - - - -/* - * Record SSC clock dividers for use in hw_params() - */ -static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - switch (div_id) { - case AT32_SSC_CMR_DIV: - /* - * The same master clock divider is used for both - * transmit and receive, so if a value has already - * been set, it must match this value - */ - if (ssc_p->cmr_div == 0) - ssc_p->cmr_div = div; - else if (div != ssc_p->cmr_div) - return -EBUSY; - break; - - case AT32_SSC_TCMR_PERIOD: - ssc_p->tcmr_period = div; - break; - - case AT32_SSC_RCMR_PERIOD: - ssc_p->rcmr_period = div; - break; - - default: - return -EINVAL; - } - - return 0; -} - - - -/* - * Configure the SSC - */ -static int at32_ssc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int id = rtd->dai->cpu_dai->id; - struct at32_ssc_info *ssc_p = &ssc_info[id]; - struct at32_pcm_dma_params *dma_params; - int channels, bits; - u32 tfmr, rfmr, tcmr, rcmr; - int start_event; - int ret; - - - /* - * Currently, there is only one set of dma_params for each direction. - * If more are added, this code will have to be changed to select - * the proper set - */ - dma_params = &ssc_dma_params[id][substream->stream]; - dma_params->ssc = ssc_p->ssc; - dma_params->substream = substream; - - ssc_p->dma_params[substream->stream] = dma_params; - - - /* - * The cpu_dai->dma_data field is only used to communicate the - * appropriate DMA parameters to the PCM driver's hw_params() - * function. It should not be used for other purposes as it - * is common to all substreams. - */ - rtd->dai->cpu_dai->dma_data = dma_params; - - channels = params_channels(params); - - - /* - * Determine sample size in bits and the PDC increment - */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - bits = 8; - dma_params->pdc_xfer_size = 1; - break; - - case SNDRV_PCM_FORMAT_S16: - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - - case SNDRV_PCM_FORMAT_S24: - bits = 24; - dma_params->pdc_xfer_size = 4; - break; - - case SNDRV_PCM_FORMAT_S32: - bits = 32; - dma_params->pdc_xfer_size = 4; - break; - - default: - pr_warning("at32-ssc: Unsupported PCM format %d", - params_format(params)); - return -EINVAL; - } - pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n", - bits, dma_params->pdc_xfer_size, channels); - - - /* - * The SSC only supports up to 16-bit samples in I2S format, due - * to the size of the Frame Mode Register FSLEN field. - */ - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) - if (bits > 16) { - pr_warning("at32-ssc: " - "sample size %d is too large for I2S\n", - bits); - return -EINVAL; - } - - - /* - * Compute the SSC register settings - */ - switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | - SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - /* - * I2S format, SSC provides BCLK and LRS clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line - */ - pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n"); - rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | - SSC_BF(RCMR_STTDLY, START_DELAY) | - SSC_BF(RCMR_START, SSC_START_FALLING_RF) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_DIV)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | - SSC_BF(RFMR_FSLEN, bits - 1) | - SSC_BF(RFMR_DATNB, channels - 1) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | - SSC_BF(TCMR_STTDLY, START_DELAY) | - SSC_BF(TCMR_START, SSC_START_FALLING_RF) | - SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | - SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | - SSC_BF(TCMR_CKS, SSC_CKS_DIV)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | - SSC_BF(TFMR_FSLEN, bits - 1) | - SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | - SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* - * I2S format, CODEC supplies BCLK and LRC clock. - * - * The SSC transmit clock is obtained from the BCLK signal - * on the TK line, and the SSC receive clock is generated from - * the transmit clock. - * - * For single channel data, one sample is transferred on the - * falling edge of the LRC clock. For two channel data, one - * sample is transferred on both edges of the LRC clock. - */ - pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n"); - start_event = ((channels == 1) ? - SSC_START_FALLING_RF : SSC_START_EDGE_RF); - - rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) | - SSC_BF(RCMR_START, start_event) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_CLOCK)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) | - SSC_BF(TCMR_START, start_event) | - SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | - SSC_BF(TCMR_CKO, SSC_CKO_NONE) | - SSC_BF(TCMR_CKS, SSC_CKS_PIN)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | - SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line - */ - pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n"); - rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | - SSC_BF(RCMR_STTDLY, 1) | - SSC_BF(RCMR_START, SSC_START_RISING_RF) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_DIV)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | - SSC_BF(RFMR_DATNB, channels - 1) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | - SSC_BF(TCMR_STTDLY, 1) | - SSC_BF(TCMR_START, SSC_START_RISING_RF) | - SSC_BF(TCMR_CKI, SSC_CKI_RISING) | - SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | - SSC_BF(TCMR_CKS, SSC_CKS_DIV)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | - SSC_BF(TFMR_DATNB, channels - 1) | - SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - default: - pr_warning("at32-ssc: unsupported DAI format 0x%x\n", - ssc_p->daifmt); - return -EINVAL; - break; - } - pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", - rcmr, rfmr, tcmr, tfmr); - - - if (!ssc_p->initialized) { - /* enable peripheral clock */ - pr_debug("at32-ssc: Starting clock\n"); - clk_enable(ssc_p->ssc->clk); - - /* Reset the SSC and its PDC registers */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - - ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); - - ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); - - ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0, - ssc_p->name, ssc_p); - if (ret < 0) { - pr_warning("at32-ssc: request irq failed (%d)\n", ret); - pr_debug("at32-ssc: Stopping clock\n"); - clk_disable(ssc_p->ssc->clk); - return ret; - } - - ssc_p->initialized = 1; - } - - /* Set SSC clock mode register */ - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); - - /* set receive clock mode and format */ - ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); - - /* set transmit clock mode and format */ - ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); - ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); - - pr_debug("at32-ssc: SSC initialized\n"); - return 0; -} - - - -static int at32_ssc_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at32_pcm_dma_params *dma_params; - - dma_params = ssc_p->dma_params[substream->stream]; - - ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable); - - return 0; -} - - - -#ifdef CONFIG_PM -static int at32_ssc_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at32_ssc_info *ssc_p; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* Save the status register before disabling transmit and receive */ - ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); - - /* Save the current interrupt mask, then disable unmasked interrupts */ - ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); - ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); - - ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); - ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); - ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); - ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); - ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); - - return 0; -} - - - -static int at32_ssc_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at32_ssc_info *ssc_p; - u32 cr; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* restore SSC register settings */ - ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); - ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); - ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); - - /* re-enable interrupts */ - ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); - - /* Re-enable recieve and transmit as appropriate */ - cr = 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; - ssc_writel(ssc_p->ssc->regs, CR, cr); - - return 0; -} -#else /* CONFIG_PM */ -# define at32_ssc_suspend NULL -# define at32_ssc_resume NULL -#endif /* CONFIG_PM */ - - -#define AT32_SSC_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) - - -#define AT32_SSC_FORMATS \ - (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16 | \ - SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32) - - -struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = { - { - .name = "at32-ssc0", - .id = 0, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[0], - }, - { - .name = "at32-ssc1", - .id = 1, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[1], - }, - { - .name = "at32-ssc2", - .id = 2, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[2], - }, -}; -EXPORT_SYMBOL_GPL(at32_ssc_dai); - - -MODULE_AUTHOR("Geoffrey Wossum "); -MODULE_DESCRIPTION("AT32 SSC ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at32/at32-ssc.h b/sound/soc/at32/at32-ssc.h deleted file mode 100644 index 3c052dbbe46..00000000000 --- a/sound/soc/at32/at32-ssc.h +++ /dev/null @@ -1,59 +0,0 @@ -/* sound/soc/at32/at32-ssc.h - * ASoC SSC interface for Atmel AT32 SoC - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * 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 __SOUND_SOC_AT32_AT32_SSC_H -#define __SOUND_SOC_AT32_AT32_SSC_H __FILE__ - -#include -#include - -#include "at32-pcm.h" - - - -struct at32_ssc_state { - u32 ssc_cmr; - u32 ssc_rcmr; - u32 ssc_rfmr; - u32 ssc_tcmr; - u32 ssc_tfmr; - u32 ssc_sr; - u32 ssc_imr; -}; - - - -struct at32_ssc_info { - char *name; - struct ssc_device *ssc; - spinlock_t lock; /* lock for dir_mask */ - unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ - unsigned short initialized; /* true if SSC has been initialized */ - unsigned short daifmt; - unsigned short cmr_div; - unsigned short tcmr_period; - unsigned short rcmr_period; - struct at32_pcm_dma_params *dma_params[2]; - struct at32_ssc_state ssc_state; -}; - - -/* SSC divider ids */ -#define AT32_SSC_CMR_DIV 0 /* MCK divider for BCLK */ -#define AT32_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ -#define AT32_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ - - -extern struct snd_soc_dai at32_ssc_dai[]; - - - -#endif /* __SOUND_SOC_AT32_AT32_SSC_H */ diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c deleted file mode 100644 index b1966e4dfcd..00000000000 --- a/sound/soc/at32/playpaq_wm8510.c +++ /dev/null @@ -1,513 +0,0 @@ -/* sound/soc/at32/playpaq_wm8510.c - * ASoC machine driver for PlayPaq using WM8510 codec - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c - * - * NOTE: If you don't have the AT32 enhanced portmux configured (which - * isn't currently in the mainline or Atmel patched kernel), you will - * need to set the MCLK pin (PA30) to peripheral A in your board initialization - * code. Something like: - * at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); - * - */ - -/* #define DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "../codecs/wm8510.h" -#include "at32-pcm.h" -#include "at32-ssc.h" - - -/*-------------------------------------------------------------------------*\ - * constants -\*-------------------------------------------------------------------------*/ -#define MCLK_PIN GPIO_PIN_PA(30) -#define MCLK_PERIPH GPIO_PERIPH_A - - -/*-------------------------------------------------------------------------*\ - * data types -\*-------------------------------------------------------------------------*/ -/* SSC clocking data */ -struct ssc_clock_data { - /* CMR div */ - unsigned int cmr_div; - - /* Frame period (as needed by xCMR.PERIOD) */ - unsigned int period; - - /* The SSC clock rate these settings where calculated for */ - unsigned long ssc_rate; -}; - - -/*-------------------------------------------------------------------------*\ - * module data -\*-------------------------------------------------------------------------*/ -static struct clk *_gclk0; -static struct clk *_pll0; - -#define CODEC_CLK (_gclk0) - - -/*-------------------------------------------------------------------------*\ - * Sound SOC operations -\*-------------------------------------------------------------------------*/ -#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE -static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( - struct snd_pcm_hw_params *params, - struct snd_soc_dai *cpu_dai) -{ - struct at32_ssc_info *ssc_p = cpu_dai->private_data; - struct ssc_device *ssc = ssc_p->ssc; - struct ssc_clock_data cd; - unsigned int rate, width_bits, channels; - unsigned int bitrate, ssc_div; - unsigned actual_rate; - - - /* - * Figure out required bitrate - */ - rate = params_rate(params); - channels = params_channels(params); - width_bits = snd_pcm_format_physical_width(params_format(params)); - bitrate = rate * width_bits * channels; - - - /* - * Figure out required SSC divider and period for required bitrate - */ - cd.ssc_rate = clk_get_rate(ssc->clk); - ssc_div = cd.ssc_rate / bitrate; - cd.cmr_div = ssc_div / 2; - if (ssc_div & 1) { - /* round cmr_div up */ - cd.cmr_div++; - } - cd.period = width_bits - 1; - - - /* - * Find actual rate, compare to requested rate - */ - actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); - pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n", - rate, actual_rate); - - - return cd; -} -#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ - - - -static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct at32_ssc_info *ssc_p = cpu_dai->private_data; - struct ssc_device *ssc = ssc_p->ssc; - unsigned int pll_out = 0, bclk = 0, mclk_div = 0; - int ret; - - - /* Due to difficulties with getting the correct clocks from the AT32's - * PLL0, we're going to let the CODEC be in charge of all the clocks - */ -#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE - const unsigned int fmt = (SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); -#else - struct ssc_clock_data cd; - const unsigned int fmt = (SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); -#endif - - if (ssc == NULL) { - pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n"); - return -EINVAL; - } - - - /* - * Figure out PLL and BCLK dividers for WM8510 - */ - switch (params_rate(params)) { - case 48000: - pll_out = 12288000; - mclk_div = WM8510_MCLKDIV_1; - bclk = WM8510_BCLKDIV_8; - break; - - case 44100: - pll_out = 11289600; - mclk_div = WM8510_MCLKDIV_1; - bclk = WM8510_BCLKDIV_8; - break; - - case 22050: - pll_out = 11289600; - mclk_div = WM8510_MCLKDIV_2; - bclk = WM8510_BCLKDIV_8; - break; - - case 16000: - pll_out = 12288000; - mclk_div = WM8510_MCLKDIV_3; - bclk = WM8510_BCLKDIV_8; - break; - - case 11025: - pll_out = 11289600; - mclk_div = WM8510_MCLKDIV_4; - bclk = WM8510_BCLKDIV_8; - break; - - case 8000: - pll_out = 12288000; - mclk_div = WM8510_MCLKDIV_6; - bclk = WM8510_BCLKDIV_8; - break; - - default: - pr_warning("playpaq_wm8510: Unsupported sample rate %d\n", - params_rate(params)); - return -EINVAL; - } - - - /* - * set CPU and CODEC DAI configuration - */ - ret = snd_soc_dai_set_fmt(codec_dai, fmt); - if (ret < 0) { - pr_warning("playpaq_wm8510: " - "Failed to set CODEC DAI format (%d)\n", - ret); - return ret; - } - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret < 0) { - pr_warning("playpaq_wm8510: " - "Failed to set CPU DAI format (%d)\n", - ret); - return ret; - } - - - /* - * Set CPU clock configuration - */ -#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE - cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai); - pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n", - cd.cmr_div, cd.period); - ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div); - if (ret < 0) { - pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n", - ret); - return ret; - } - ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD, - cd.period); - if (ret < 0) { - pr_warning("playpaq_wm8510: " - "Failed to set CPU transmit period (%d)\n", - ret); - return ret; - } -#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ - - - /* - * Set CODEC clock configuration - */ - pr_debug("playpaq_wm8510: " - "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n", - clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div); - - -#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk); - if (ret < 0) { - pr_warning - ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n", - ret); - return ret; - } -#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ - - - ret = snd_soc_dai_set_pll(codec_dai, 0, - clk_get_rate(CODEC_CLK), pll_out); - if (ret < 0) { - pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", - ret); - return ret; - } - - - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div); - if (ret < 0) { - pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n", - ret); - return ret; - } - - - return 0; -} - - - -static struct snd_soc_ops playpaq_wm8510_ops = { - .hw_params = playpaq_wm8510_hw_params, -}; - - - -static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), -}; - - - -static const struct snd_soc_dapm_route intercon[] = { - /* speaker connected to SPKOUT */ - {"Ext Spk", NULL, "SPKOUTP"}, - {"Ext Spk", NULL, "SPKOUTN"}, - - {"Mic Bias", NULL, "Int Mic"}, - {"MICN", NULL, "Mic Bias"}, - {"MICP", NULL, "Mic Bias"}, -}; - - - -static int playpaq_wm8510_init(struct snd_soc_codec *codec) -{ - int i; - - /* - * Add DAPM widgets - */ - for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++) - snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]); - - - - /* - * Setup audio path interconnects - */ - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - - - - /* always connected pins */ - snd_soc_dapm_enable_pin(codec, "Int Mic"); - snd_soc_dapm_enable_pin(codec, "Ext Spk"); - snd_soc_dapm_sync(codec); - - - - /* Make CSB show PLL rate */ - snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV, - WM8510_OPCLKDIV_1 | 4); - - return 0; -} - - - -static struct snd_soc_dai_link playpaq_wm8510_dai = { - .name = "WM8510", - .stream_name = "WM8510 PCM", - .cpu_dai = &at32_ssc_dai[0], - .codec_dai = &wm8510_dai, - .init = playpaq_wm8510_init, - .ops = &playpaq_wm8510_ops, -}; - - - -static struct snd_soc_machine snd_soc_machine_playpaq = { - .name = "LRS_PlayPaq_WM8510", - .dai_link = &playpaq_wm8510_dai, - .num_links = 1, -}; - - - -static struct wm8510_setup_data playpaq_wm8510_setup = { - .i2c_bus = 0, - .i2c_address = 0x1a, -}; - - - -static struct snd_soc_device playpaq_wm8510_snd_devdata = { - .machine = &snd_soc_machine_playpaq, - .platform = &at32_soc_platform, - .codec_dev = &soc_codec_dev_wm8510, - .codec_data = &playpaq_wm8510_setup, -}; - -static struct platform_device *playpaq_snd_device; - - -static int __init playpaq_asoc_init(void) -{ - int ret = 0; - struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; - struct ssc_device *ssc = NULL; - - - /* - * Request SSC device - */ - ssc = ssc_request(0); - if (IS_ERR(ssc)) { - ret = PTR_ERR(ssc); - goto err_ssc; - } - ssc_p->ssc = ssc; - - - /* - * Configure MCLK for WM8510 - */ - _gclk0 = clk_get(NULL, "gclk0"); - if (IS_ERR(_gclk0)) { - _gclk0 = NULL; - goto err_gclk0; - } - _pll0 = clk_get(NULL, "pll0"); - if (IS_ERR(_pll0)) { - _pll0 = NULL; - goto err_pll0; - } - if (clk_set_parent(_gclk0, _pll0)) { - pr_warning("snd-soc-playpaq: " - "Failed to set PLL0 as parent for DAC clock\n"); - goto err_set_clk; - } - clk_set_rate(CODEC_CLK, 12000000); - clk_enable(CODEC_CLK); - -#if defined CONFIG_AT32_ENHANCED_PORTMUX - at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0); -#endif - - - /* - * Create and register platform device - */ - playpaq_snd_device = platform_device_alloc("soc-audio", 0); - if (playpaq_snd_device == NULL) { - ret = -ENOMEM; - goto err_device_alloc; - } - - platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata); - playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev; - - ret = platform_device_add(playpaq_snd_device); - if (ret) { - pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n", - ret); - goto err_device_add; - } - - return 0; - - -err_device_add: - if (playpaq_snd_device != NULL) { - platform_device_put(playpaq_snd_device); - playpaq_snd_device = NULL; - } -err_device_alloc: -err_set_clk: - if (_pll0 != NULL) { - clk_put(_pll0); - _pll0 = NULL; - } -err_pll0: - if (_gclk0 != NULL) { - clk_put(_gclk0); - _gclk0 = NULL; - } -err_gclk0: - ssc_free(ssc); -err_ssc: - return ret; -} - - -static void __exit playpaq_asoc_exit(void) -{ - struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; - struct ssc_device *ssc; - - if (ssc_p != NULL) { - ssc = ssc_p->ssc; - if (ssc != NULL) - ssc_free(ssc); - ssc_p->ssc = NULL; - } - - if (_gclk0 != NULL) { - clk_put(_gclk0); - _gclk0 = NULL; - } - if (_pll0 != NULL) { - clk_put(_pll0); - _pll0 = NULL; - } - -#if defined CONFIG_AT32_ENHANCED_PORTMUX - at32_free_pin(MCLK_PIN); -#endif - - platform_device_unregister(playpaq_snd_device); - playpaq_snd_device = NULL; -} - -module_init(playpaq_asoc_init); -module_exit(playpaq_asoc_exit); - -MODULE_AUTHOR("Geoffrey Wossum "); -MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig deleted file mode 100644 index 85a883299c2..00000000000 --- a/sound/soc/at91/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config SND_AT91_SOC - tristate "SoC Audio for the Atmel AT91 System-on-Chip" - depends on ARCH_AT91 - help - Say Y or M if you want to add support for codecs attached to - the AT91 SSC interface. You will also need - to select the audio interfaces to support below. - -config SND_AT91_SOC_SSC - tristate diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile deleted file mode 100644 index b817f11df28..00000000000 --- a/sound/soc/at91/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# AT91 Platform Support -snd-soc-at91-objs := at91-pcm.o -snd-soc-at91-ssc-objs := at91-ssc.o - -obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o -obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c deleted file mode 100644 index 7ab48bd25e4..00000000000 --- a/sound/soc/at91/at91-pcm.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * Created: Mar 3, 2006 - * - * Based on pxa2xx-pcm.c by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: (C) 2004 MontaVista Software, Inc. - * - * 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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "at91-pcm.h" - -#if 0 -#define DBG(x...) printk(KERN_INFO "at91-pcm: " x) -#else -#define DBG(x...) -#endif - -static const struct snd_pcm_hardware at91_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 2, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, -}; - -struct at91_runtime_data { - struct at91_pcm_dma_params *params; - dma_addr_t dma_buffer; /* physical address of dma buffer */ - dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ - size_t period_size; - dma_addr_t period_ptr; /* physical address of next period */ - u32 pdc_xpr_save; /* PDC register save */ - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - -static void at91_pcm_dma_irq(u32 ssc_sr, - struct snd_pcm_substream *substream) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - static int count = 0; - - count++; - - if (ssc_sr & params->mask->ssc_endbuf) { - - printk(KERN_WARNING - "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? "underrun" : "overrun", - params->name, ssc_sr, count); - - /* re-start the PDC */ - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) { - prtd->period_ptr = prtd->dma_buffer; - } - - at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); - at91_ssc_write(params->ssc_base + params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); - } - - if (ssc_sr & params->mask->ssc_endx) { - - /* Load the PDC next pointer and counter registers */ - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) { - prtd->period_ptr = prtd->dma_buffer; - } - at91_ssc_write(params->ssc_base + params->pdc->xnpr, - prtd->period_ptr); - at91_ssc_write(params->ssc_base + params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - snd_pcm_period_elapsed(substream); -} - -static int at91_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at91_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* this may get called several times by oss emulation - * with different params */ - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->params = rtd->dai->cpu_dai->dma_data; - prtd->params->dma_intr_handler = at91_pcm_dma_irq; - - prtd->dma_buffer = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; - prtd->period_size = params_period_bytes(params); - - DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n", - prtd->params->name, runtime->dma_bytes, prtd->period_size); - return 0; -} - -static int at91_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - - if (params != NULL) { - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - -static int at91_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - - at91_ssc_write(params->ssc_base + AT91_SSC_IDR, - params->mask->ssc_endx | params->mask->ssc_endbuf); - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - return 0; -} - -static int at91_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); - at91_ssc_write(params->ssc_base + params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr); - at91_ssc_write(params->ssc_base + params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n", - (unsigned long) prtd->period_ptr, - at91_ssc_read(params->ssc_base + params->pdc->xpr), - at91_ssc_read(params->ssc_base + params->pdc->xcr), - at91_ssc_read(params->ssc_base + params->pdc->xnpr), - at91_ssc_read(params->ssc_base + params->pdc->xncr)); - - at91_ssc_write(params->ssc_base + AT91_SSC_IER, - params->mask->ssc_endx | params->mask->ssc_endbuf); - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, - params->mask->pdc_enable); - - DBG("sr=%lx imr=%lx\n", - at91_ssc_read(params->ssc_base + AT91_SSC_SR), - at91_ssc_read(params->ssc_base + AT91_SSC_IMR)); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - break; - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -static snd_pcm_uframes_t at91_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at91_runtime_data *prtd = runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - return x; -} - -static int at91_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at91_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto out; - - prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - out: - return ret; -} - -static int at91_pcm_close(struct snd_pcm_substream *substream) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - -static int at91_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); -} - -struct snd_pcm_ops at91_pcm_ops = { - .open = at91_pcm_open, - .close = at91_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = at91_pcm_hw_params, - .hw_free = at91_pcm_hw_free, - .prepare = at91_pcm_prepare, - .trigger = at91_pcm_trigger, - .pointer = at91_pcm_pointer, - .mmap = at91_pcm_mmap, -}; - -static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, - int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = at91_pcm_hardware.buffer_bytes_max; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - - DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, - (void *) buf->addr, - size); - - if (!buf->area) - return -ENOMEM; - - buf->bytes = size; - return 0; -} - -static u64 at91_pcm_dmamask = 0xffffffff; - -static int at91_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &at91_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = at91_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - ret = at91_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - out: - return ret; -} - -static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - -#ifdef CONFIG_PM -static int at91_pcm_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at91_runtime_data *prtd; - struct at91_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* disable the PDC and save the PDC registers */ - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - - prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr); - prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr); - prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr); - prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr); - - return 0; -} - -static int at91_pcm_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at91_runtime_data *prtd; - struct at91_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* restore the PDC registers and enable the PDC */ - at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save); - at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save); - at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save); - at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save); - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else -#define at91_pcm_suspend NULL -#define at91_pcm_resume NULL -#endif - -struct snd_soc_platform at91_soc_platform = { - .name = "at91-audio", - .pcm_ops = &at91_pcm_ops, - .pcm_new = at91_pcm_new, - .pcm_free = at91_pcm_free_dma_buffers, - .suspend = at91_pcm_suspend, - .resume = at91_pcm_resume, -}; - -EXPORT_SYMBOL_GPL(at91_soc_platform); - -MODULE_AUTHOR("Frank Mandarino "); -MODULE_DESCRIPTION("Atmel AT91 PCM module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h deleted file mode 100644 index e5aada2cb10..00000000000 --- a/sound/soc/at91/at91-pcm.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * Created: Mar 3, 2006 - * - * Based on pxa2xx-pcm.h by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: MontaVista Software, Inc. - * - * 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 _AT91_PCM_H -#define _AT91_PCM_H - -#include - -struct at91_ssc_periph { - void __iomem *base; - u32 pid; -}; - -/* - * Registers and status bits that are required by the PCM driver. - */ -struct at91_pdc_regs { - unsigned int xpr; /* PDC recv/trans pointer */ - unsigned int xcr; /* PDC recv/trans counter */ - unsigned int xnpr; /* PDC next recv/trans pointer */ - unsigned int xncr; /* PDC next recv/trans counter */ - unsigned int ptcr; /* PDC transfer control */ -}; - -struct at91_ssc_mask { - u32 ssc_enable; /* SSC recv/trans enable */ - u32 ssc_disable; /* SSC recv/trans disable */ - u32 ssc_endx; /* SSC ENDTX or ENDRX */ - u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ - u32 pdc_enable; /* PDC recv/trans enable */ - u32 pdc_disable; /* PDC recv/trans disable */ -}; - -/* - * This structure, shared between the PCM driver and the interface, - * contains all information required by the PCM driver to perform the - * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dms_intr_handler() pointer is set by the PCM - * driver and called by the interface SSC interrupt handler if it is - * non-NULL. - */ -struct at91_pcm_dma_params { - char *name; /* stream identifier */ - int pdc_xfer_size; /* PDC counter increment in bytes */ - void __iomem *ssc_base; /* SSC base address */ - struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */ - struct at91_ssc_mask *mask;/* SSC & PDC status bits */ - struct snd_pcm_substream *substream; - void (*dma_intr_handler)(u32, struct snd_pcm_substream *); -}; - -extern struct snd_soc_platform at91_soc_platform; - -#define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) -#define at91_ssc_write(a,v) __raw_writel((v),(a)) - -#endif /* _AT91_PCM_H */ diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c deleted file mode 100644 index 1b61cc46126..00000000000 --- a/sound/soc/at91/at91-ssc.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * at91-ssc.c -- ALSA SoC AT91 SSC Audio Layer Platform driver - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * - * Based on pxa2xx Platform drivers by - * Liam Girdwood - * - * 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 -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "at91-pcm.h" -#include "at91-ssc.h" - -#if 0 -#define DBG(x...) printk(KERN_DEBUG "at91-ssc:" x) -#else -#define DBG(x...) -#endif - -#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) -#define NUM_SSC_DEVICES 1 -#else -#define NUM_SSC_DEVICES 3 -#endif - - -/* - * SSC PDC registers required by the PCM DMA engine. - */ -static struct at91_pdc_regs pdc_tx_reg = { - .xpr = ATMEL_PDC_TPR, - .xcr = ATMEL_PDC_TCR, - .xnpr = ATMEL_PDC_TNPR, - .xncr = ATMEL_PDC_TNCR, -}; - -static struct at91_pdc_regs pdc_rx_reg = { - .xpr = ATMEL_PDC_RPR, - .xcr = ATMEL_PDC_RCR, - .xnpr = ATMEL_PDC_RNPR, - .xncr = ATMEL_PDC_RNCR, -}; - -/* - * SSC & PDC status bits for transmit and receive. - */ -static struct at91_ssc_mask ssc_tx_mask = { - .ssc_enable = AT91_SSC_TXEN, - .ssc_disable = AT91_SSC_TXDIS, - .ssc_endx = AT91_SSC_ENDTX, - .ssc_endbuf = AT91_SSC_TXBUFE, - .pdc_enable = ATMEL_PDC_TXTEN, - .pdc_disable = ATMEL_PDC_TXTDIS, -}; - -static struct at91_ssc_mask ssc_rx_mask = { - .ssc_enable = AT91_SSC_RXEN, - .ssc_disable = AT91_SSC_RXDIS, - .ssc_endx = AT91_SSC_ENDRX, - .ssc_endbuf = AT91_SSC_RXBUFF, - .pdc_enable = ATMEL_PDC_RXTEN, - .pdc_disable = ATMEL_PDC_RXTDIS, -}; - - -/* - * DMA parameters. - */ -static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { - {{ - .name = "SSC0 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC0 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }}, -#if NUM_SSC_DEVICES == 3 - {{ - .name = "SSC1 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }}, - {{ - .name = "SSC2 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC2 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }}, -#endif -}; - -struct at91_ssc_state { - u32 ssc_cmr; - u32 ssc_rcmr; - u32 ssc_rfmr; - u32 ssc_tcmr; - u32 ssc_tfmr; - u32 ssc_sr; - u32 ssc_imr; -}; - -static struct at91_ssc_info { - char *name; - struct at91_ssc_periph ssc; - spinlock_t lock; /* lock for dir_mask */ - unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ - unsigned short initialized; /* 1=SSC has been initialized */ - unsigned short daifmt; - unsigned short cmr_div; - unsigned short tcmr_period; - unsigned short rcmr_period; - struct at91_pcm_dma_params *dma_params[2]; - struct at91_ssc_state ssc_state; - -} ssc_info[NUM_SSC_DEVICES] = { - { - .name = "ssc0", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), - .dir_mask = 0, - .initialized = 0, - }, -#if NUM_SSC_DEVICES == 3 - { - .name = "ssc1", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), - .dir_mask = 0, - .initialized = 0, - }, - { - .name = "ssc2", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), - .dir_mask = 0, - .initialized = 0, - }, -#endif -}; - -static unsigned int at91_ssc_sysclk; - -/* - * SSC interrupt handler. Passes PDC interrupts to the DMA - * interrupt handler in the PCM driver. - */ -static irqreturn_t at91_ssc_interrupt(int irq, void *dev_id) -{ - struct at91_ssc_info *ssc_p = dev_id; - struct at91_pcm_dma_params *dma_params; - u32 ssc_sr; - int i; - - ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR) - & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); - - /* - * Loop through the substreams attached to this SSC. If - * a DMA-related interrupt occurred on that substream, call - * the DMA interrupt handler function, if one has been - * registered in the dma_params structure by the PCM driver. - */ - for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { - dma_params = ssc_p->dma_params[i]; - - if (dma_params != NULL && dma_params->dma_intr_handler != NULL && - (ssc_sr & - (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf))) - - dma_params->dma_intr_handler(ssc_sr, dma_params->substream); - } - - return IRQ_HANDLED; -} - -/* - * Startup. Only that one substream allowed in each direction. - */ -static int at91_ssc_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - int dir_mask; - - DBG("ssc_startup: SSC_SR=0x%08lx\n", - at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); - dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2; - - spin_lock_irq(&ssc_p->lock); - if (ssc_p->dir_mask & dir_mask) { - spin_unlock_irq(&ssc_p->lock); - return -EBUSY; - } - ssc_p->dir_mask |= dir_mask; - spin_unlock_irq(&ssc_p->lock); - - return 0; -} - -/* - * Shutdown. Clear DMA parameters and shutdown the SSC if there - * are no other substreams open. - */ -static void at91_ssc_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at91_pcm_dma_params *dma_params; - int dir, dir_mask; - - dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - dma_params = ssc_p->dma_params[dir]; - - if (dma_params != NULL) { - at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, - dma_params->mask->ssc_disable); - DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"), - at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); - - dma_params->ssc_base = NULL; - dma_params->substream = NULL; - ssc_p->dma_params[dir] = NULL; - } - - dir_mask = 1 << dir; - - spin_lock_irq(&ssc_p->lock); - ssc_p->dir_mask &= ~dir_mask; - if (!ssc_p->dir_mask) { - /* Shutdown the SSC clock. */ - DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); - at91_sys_write(AT91_PMC_PCDR, 1<ssc.pid); - - if (ssc_p->initialized) { - free_irq(ssc_p->ssc.pid, ssc_p); - ssc_p->initialized = 0; - } - - /* Reset the SSC */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); - - /* Clear the SSC dividers */ - ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; - } - spin_unlock_irq(&ssc_p->lock); -} - -/* - * Record the SSC system clock rate. - */ -static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - /* - * The only clock supplied to the SSC is the AT91 master clock, - * which is only used if the SSC is generating BCLK and/or - * LRC clocks. - */ - switch (clk_id) { - case AT91_SYSCLK_MCK: - at91_ssc_sysclk = freq; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* - * Record the DAI format for use in hw_params(). - */ -static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - ssc_p->daifmt = fmt; - return 0; -} - -/* - * Record SSC clock dividers for use in hw_params(). - */ -static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - switch (div_id) { - case AT91SSC_CMR_DIV: - /* - * The same master clock divider is used for both - * transmit and receive, so if a value has already - * been set, it must match this value. - */ - if (ssc_p->cmr_div == 0) - ssc_p->cmr_div = div; - else - if (div != ssc_p->cmr_div) - return -EBUSY; - break; - - case AT91SSC_TCMR_PERIOD: - ssc_p->tcmr_period = div; - break; - - case AT91SSC_RCMR_PERIOD: - ssc_p->rcmr_period = div; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * Configure the SSC. - */ -static int at91_ssc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int id = rtd->dai->cpu_dai->id; - struct at91_ssc_info *ssc_p = &ssc_info[id]; - struct at91_pcm_dma_params *dma_params; - int dir, channels, bits; - u32 tfmr, rfmr, tcmr, rcmr; - int start_event; - int ret; - - /* - * Currently, there is only one set of dma params for - * each direction. If more are added, this code will - * have to be changed to select the proper set. - */ - dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - - dma_params = &ssc_dma_params[id][dir]; - dma_params->ssc_base = ssc_p->ssc.base; - dma_params->substream = substream; - - ssc_p->dma_params[dir] = dma_params; - - /* - * The cpu_dai->dma_data field is only used to communicate the - * appropriate DMA parameters to the pcm driver hw_params() - * function. It should not be used for other purposes - * as it is common to all substreams. - */ - rtd->dai->cpu_dai->dma_data = dma_params; - - channels = params_channels(params); - - /* - * Determine sample size in bits and the PDC increment. - */ - switch(params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - bits = 8; - dma_params->pdc_xfer_size = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - case SNDRV_PCM_FORMAT_S24_LE: - bits = 24; - dma_params->pdc_xfer_size = 4; - break; - case SNDRV_PCM_FORMAT_S32_LE: - bits = 32; - dma_params->pdc_xfer_size = 4; - break; - default: - printk(KERN_WARNING "at91-ssc: unsupported PCM format\n"); - return -EINVAL; - } - - /* - * The SSC only supports up to 16-bit samples in I2S format, due - * to the size of the Frame Mode Register FSLEN field. - */ - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S - && bits > 16) { - printk(KERN_WARNING - "at91-ssc: sample size %d is too large for I2S\n", bits); - return -EINVAL; - } - - /* - * Compute SSC register settings. - */ - switch (ssc_p->daifmt - & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - /* - * I2S format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line. - */ - rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) - | (((bits - 1) << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_LOOP) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( 0 << 23) & AT91_SSC_FSDEN) - | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) - | (((bits - 1) << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_DATDEF) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - break; - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* - * I2S format, CODEC supplies BCLK and LRC clocks. - * - * The SSC transmit clock is obtained from the BCLK signal on - * on the TK line, and the SSC receive clock is generated from the - * transmit clock. - * - * For single channel data, one sample is transferred on the falling - * edge of the LRC clock. For two channel data, one sample is - * transferred on both edges of the LRC clock. - */ - start_event = channels == 1 - ? AT91_SSC_START_FALLING_RF - : AT91_SSC_START_EDGE_RF; - - rcmr = (( 0 << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( start_event ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); - - rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (( 0 << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_LOOP) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - tcmr = (( 0 << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( start_event ) & AT91_SSC_START) - | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS); - - tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( 0 << 23) & AT91_SSC_FSDEN) - | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (( 0 << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_DATDEF) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - break; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line. - */ - rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_LOOP) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( 0 << 23) & AT91_SSC_FSDEN) - | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_DATDEF) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - - - break; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - default: - printk(KERN_WARNING "at91-ssc: unsupported DAI format 0x%x.\n", - ssc_p->daifmt); - return -EINVAL; - break; - } - DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); - - if (!ssc_p->initialized) { - - /* Enable PMC peripheral clock for this SSC */ - DBG("Starting pid %d clock\n", ssc_p->ssc.pid); - at91_sys_write(AT91_PMC_PCER, 1<ssc.pid); - - /* Reset the SSC and its PDC registers */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); - - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0); - - if ((ret = request_irq(ssc_p->ssc.pid, at91_ssc_interrupt, - 0, ssc_p->name, ssc_p)) < 0) { - printk(KERN_WARNING "at91-ssc: request_irq failure\n"); - - DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); - at91_sys_write(AT91_PMC_PCDR, 1<ssc.pid); - return ret; - } - - ssc_p->initialized = 1; - } - - /* set SSC clock mode register */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div); - - /* set receive clock mode and format */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr); - - /* set transmit clock mode and format */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr); - - DBG("hw_params: SSC initialized\n"); - return 0; -} - - -static int at91_ssc_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at91_pcm_dma_params *dma_params; - int dir; - - dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - dma_params = ssc_p->dma_params[dir]; - - at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, - dma_params->mask->ssc_enable); - - DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit", - at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR)); - return 0; -} - - -#ifdef CONFIG_PM -static int at91_ssc_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at91_ssc_info *ssc_p; - - if(!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* Save the status register before disabling transmit and receive. */ - ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, - AT91_SSC_TXDIS | AT91_SSC_RXDIS); - - /* Save the current interrupt mask, then disable unmasked interrupts. */ - ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr); - - ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); - ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); - ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR); - ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR); - ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR); - - return 0; -} - -static int at91_ssc_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at91_ssc_info *ssc_p; - - if(!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr); - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr); - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, - ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | - ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); - - return 0; -} - -#else -#define at91_ssc_suspend NULL -#define at91_ssc_resume NULL -#endif - -#define AT91_SSC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ - SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ - SNDRV_PCM_RATE_96000) - -#define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = { - { .name = "at91-ssc0", - .id = 0, - .type = SND_SOC_DAI_PCM, - .suspend = at91_ssc_suspend, - .resume = at91_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .ops = { - .startup = at91_ssc_startup, - .shutdown = at91_ssc_shutdown, - .prepare = at91_ssc_prepare, - .hw_params = at91_ssc_hw_params,}, - .dai_ops = { - .set_sysclk = at91_ssc_set_dai_sysclk, - .set_fmt = at91_ssc_set_dai_fmt, - .set_clkdiv = at91_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[0].ssc, - }, -#if NUM_SSC_DEVICES == 3 - { .name = "at91-ssc1", - .id = 1, - .type = SND_SOC_DAI_PCM, - .suspend = at91_ssc_suspend, - .resume = at91_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .ops = { - .startup = at91_ssc_startup, - .shutdown = at91_ssc_shutdown, - .prepare = at91_ssc_prepare, - .hw_params = at91_ssc_hw_params,}, - .dai_ops = { - .set_sysclk = at91_ssc_set_dai_sysclk, - .set_fmt = at91_ssc_set_dai_fmt, - .set_clkdiv = at91_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[1].ssc, - }, - { .name = "at91-ssc2", - .id = 2, - .type = SND_SOC_DAI_PCM, - .suspend = at91_ssc_suspend, - .resume = at91_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .ops = { - .startup = at91_ssc_startup, - .shutdown = at91_ssc_shutdown, - .prepare = at91_ssc_prepare, - .hw_params = at91_ssc_hw_params,}, - .dai_ops = { - .set_sysclk = at91_ssc_set_dai_sysclk, - .set_fmt = at91_ssc_set_dai_fmt, - .set_clkdiv = at91_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[2].ssc, - }, -#endif -}; - -EXPORT_SYMBOL_GPL(at91_ssc_dai); - -/* Module information */ -MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com"); -MODULE_DESCRIPTION("AT91 SSC ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-ssc.h b/sound/soc/at91/at91-ssc.h deleted file mode 100644 index 6b7bf382d06..00000000000 --- a/sound/soc/at91/at91-ssc.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * at91-ssc.h - ALSA SSC interface for the Atmel AT91 SoC - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * Created: Jan 9, 2007 - * - * 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 _AT91_SSC_H -#define _AT91_SSC_H - -/* SSC system clock ids */ -#define AT91_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ - -/* SSC divider ids */ -#define AT91SSC_CMR_DIV 0 /* MCK divider for BCLK */ -#define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ -#define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ - -extern struct snd_soc_dai at91_ssc_dai[]; - -#endif /* _AT91_SSC_H */ - diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig new file mode 100644 index 00000000000..a608d7009db --- /dev/null +++ b/sound/soc/atmel/Kconfig @@ -0,0 +1,43 @@ +config SND_ATMEL_SOC + tristate "SoC Audio for the Atmel System-on-Chip" + depends on ARCH_AT91 || AVR32 + help + Say Y or M if you want to add support for codecs attached to + the ATMEL SSC interface. You will also need + to select the audio interfaces to support below. + +config SND_ATMEL_SOC_SSC + tristate + depends on SND_ATMEL_SOC + help + Say Y or M if you want to add support for codecs the + ATMEL SSC interface. You will also needs to select the individual + machine drivers to support below. + +config SND_AT91_SOC_SAM9G20_WM8731 + tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" + depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC + select SND_ATMEL_SOC_SSC + select SND_SOC_WM8731 + help + Say Y if you want to add support for SoC audio on WM8731-based + AT91sam9g20 evaluation board. + +config SND_AT32_SOC_PLAYPAQ + tristate "SoC Audio support for PlayPaq with WM8510" + depends on SND_ATMEL_SOC && BOARD_PLAYPAQ + select SND_ATMEL_SOC_SSC + select SND_SOC_WM8510 + help + Say Y or M here if you want to add support for SoC audio + on the LRS PlayPaq. + +config SND_AT32_SOC_PLAYPAQ_SLAVE + bool "Run CODEC on PlayPaq in slave mode" + depends on SND_AT32_SOC_PLAYPAQ + default n + help + Say Y if you want to run with the AT32 SSC generating the BCLK + and FRAME signals on the PlayPaq. Unless you want to play + with the AT32 as the SSC master, you probably want to say N here, + as this will give you better sound quality. diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile new file mode 100644 index 00000000000..f54a7cc68e6 --- /dev/null +++ b/sound/soc/atmel/Makefile @@ -0,0 +1,15 @@ +# AT91 Platform Support +snd-soc-atmel-pcm-objs := atmel-pcm.o +snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o + +obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o +obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o + +# AT91 Machine Support +snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o + +# AT32 Machine Support +snd-soc-playpaq-objs := playpaq_wm8510.o + +obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o +obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c new file mode 100644 index 00000000000..394412fb396 --- /dev/null +++ b/sound/soc/atmel/atmel-pcm.c @@ -0,0 +1,484 @@ +/* + * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Authors: Sedji Gaouaou + * + * Based on at91-pcm. by: + * Frank Mandarino + * Copyright 2006 Endrelia Technologies Inc. + * + * Based on pxa2xx-pcm.c by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "atmel-pcm.h" + + +/*--------------------------------------------------------------------------*\ + * Hardware definition +\*--------------------------------------------------------------------------*/ +/* TODO: These values were taken from the AT91 platform driver, check + * them against real values for AT32 + */ +static const struct snd_pcm_hardware atmel_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = 32 * 1024, +}; + + +/*--------------------------------------------------------------------------*\ + * Data types +\*--------------------------------------------------------------------------*/ +struct atmel_runtime_data { + struct atmel_pcm_dma_params *params; + dma_addr_t dma_buffer; /* physical address of dma buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + + dma_addr_t period_ptr; /* physical address of next period */ + int periods; /* period index of period_ptr */ + + /* PDC register save */ + u32 pdc_xpr_save; + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + + +/*--------------------------------------------------------------------------*\ + * Helper functions +\*--------------------------------------------------------------------------*/ +static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = atmel_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_coherent(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + pr_debug("atmel-pcm:" + "preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", + (void *) buf->area, + (void *) buf->addr, + size); + + if (!buf->area) + return -ENOMEM; + + buf->bytes = size; + return 0; +} +/*--------------------------------------------------------------------------*\ + * ISR +\*--------------------------------------------------------------------------*/ +static void atmel_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + static int count; + + count++; + + if (ssc_sr & params->mask->ssc_endbuf) { + pr_warning("atmel-pcm: buffer %s on %s" + " (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", + params->name, ssc_sr, count); + + /* re-start the PDC */ + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + } + + if (ssc_sr & params->mask->ssc_endx) { + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + snd_pcm_period_elapsed(substream); +} + + +/*--------------------------------------------------------------------------*\ + * PCM operations +\*--------------------------------------------------------------------------*/ +static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params */ + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params->dma_intr_handler = atmel_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + pr_debug("atmel-pcm: " + "hw_params: DMA for %s initialized " + "(dma_bytes=%u, period_size=%u)\n", + prtd->params->name, + runtime->dma_bytes, + prtd->period_size); + return 0; +} + +static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + + if (params != NULL) { + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + +static int atmel_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + + ssc_writex(params->ssc->regs, SSC_IDR, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + return 0; +} + +static int atmel_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_pcm_runtime *rtd = substream->runtime; + struct atmel_runtime_data *prtd = rtd->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + int ret = 0; + + pr_debug("atmel-pcm:buffer_size = %ld," + "dma_area = %p, dma_bytes = %u\n", + rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + pr_debug("atmel-pcm: trigger: " + "period_ptr=%lx, xpr=%u, " + "xcr=%u, xnpr=%u, xncr=%u\n", + (unsigned long)prtd->period_ptr, + ssc_readx(params->ssc->regs, params->pdc->xpr), + ssc_readx(params->ssc->regs, params->pdc->xcr), + ssc_readx(params->ssc->regs, params->pdc->xnpr), + ssc_readx(params->ssc->regs, params->pdc->xncr)); + + ssc_writex(params->ssc->regs, SSC_IER, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_enable); + + pr_debug("sr=%u imr=%u\n", + ssc_readx(params->ssc->regs, SSC_SR), + ssc_readx(params->ssc->regs, SSC_IER)); + break; /* SNDRV_PCM_TRIGGER_START */ + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t atmel_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd = runtime->private_data; + struct atmel_pcm_dma_params *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + + return x; +} + +static int atmel_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct atmel_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + out: + return ret; +} + +static int atmel_pcm_close(struct snd_pcm_substream *substream) +{ + struct atmel_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + +static int atmel_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return remap_pfn_range(vma, vma->vm_start, + substream->dma_buffer.addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); +} + +struct snd_pcm_ops atmel_pcm_ops = { + .open = atmel_pcm_open, + .close = atmel_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = atmel_pcm_hw_params, + .hw_free = atmel_pcm_hw_free, + .prepare = atmel_pcm_prepare, + .trigger = atmel_pcm_trigger, + .pointer = atmel_pcm_pointer, + .mmap = atmel_pcm_mmap, +}; + + +/*--------------------------------------------------------------------------*\ + * ASoC platform driver +\*--------------------------------------------------------------------------*/ +static u64 atmel_pcm_dmamask = 0xffffffff; + +static int atmel_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &atmel_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = atmel_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + pr_debug("at32-pcm:" + "Allocating PCM capture DMA buffer\n"); + ret = atmel_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + return ret; +} + +static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + dma_free_coherent(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +#ifdef CONFIG_PM +static int atmel_pcm_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct atmel_runtime_data *prtd; + struct atmel_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* disable the PDC and save the PDC registers */ + + ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); + + prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); + prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); + prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); + prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); + + return 0; +} + +static int atmel_pcm_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct atmel_runtime_data *prtd; + struct atmel_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* restore the PDC registers and enable the PDC */ + ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); + ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); + ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); + ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); + + ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); + return 0; +} +#else +#define atmel_pcm_suspend NULL +#define atmel_pcm_resume NULL +#endif + +struct snd_soc_platform atmel_soc_platform = { + .name = "atmel-audio", + .pcm_ops = &atmel_pcm_ops, + .pcm_new = atmel_pcm_new, + .pcm_free = atmel_pcm_free_dma_buffers, + .suspend = atmel_pcm_suspend, + .resume = atmel_pcm_resume, +}; +EXPORT_SYMBOL_GPL(atmel_soc_platform); + +MODULE_AUTHOR("Sedji Gaouaou "); +MODULE_DESCRIPTION("Atmel PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h new file mode 100644 index 00000000000..ec9b2824b66 --- /dev/null +++ b/sound/soc/atmel/atmel-pcm.h @@ -0,0 +1,86 @@ +/* + * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC. + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Authors: Sedji Gaouaou + * + * Based on at91-pcm. by: + * Frank Mandarino + * Copyright 2006 Endrelia Technologies Inc. + * + * Based on pxa2xx-pcm.c by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ATMEL_PCM_H +#define _ATMEL_PCM_H + +#include + +/* + * Registers and status bits that are required by the PCM driver. + */ +struct atmel_pdc_regs { + unsigned int xpr; /* PDC recv/trans pointer */ + unsigned int xcr; /* PDC recv/trans counter */ + unsigned int xnpr; /* PDC next recv/trans pointer */ + unsigned int xncr; /* PDC next recv/trans counter */ + unsigned int ptcr; /* PDC transfer control */ +}; + +struct atmel_ssc_mask { + u32 ssc_enable; /* SSC recv/trans enable */ + u32 ssc_disable; /* SSC recv/trans disable */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ + u32 pdc_enable; /* PDC recv/trans enable */ + u32 pdc_disable; /* PDC recv/trans disable */ +}; + +/* + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized + * by the interface. The dms_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +struct atmel_pcm_dma_params { + char *name; /* stream identifier */ + int pdc_xfer_size; /* PDC counter increment in bytes */ + struct ssc_device *ssc; /* SSC device for stream */ + struct atmel_pdc_regs *pdc; /* PDC receive or transmit registers */ + struct atmel_ssc_mask *mask; /* SSC & PDC status bits */ + struct snd_pcm_substream *substream; + void (*dma_intr_handler)(u32, struct snd_pcm_substream *); +}; + +extern struct snd_soc_platform atmel_soc_platform; + + +/* + * SSC register access (since ssc_writel() / ssc_readl() require literal name) + */ +#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) +#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) + +#endif /* _ATMEL_PCM_H */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c new file mode 100644 index 00000000000..d290b789491 --- /dev/null +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -0,0 +1,782 @@ +/* + * atmel_ssc_dai.c -- ALSA SoC ATMEL SSC Audio Layer Platform driver + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Author: Sedji Gaouaou + * ATMEL CORP. + * + * Based on at91-ssc.c by + * Frank Mandarino + * Based on pxa2xx Platform drivers by + * Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "atmel-pcm.h" +#include "atmel_ssc_dai.h" + + +#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) +#define NUM_SSC_DEVICES 1 +#else +#define NUM_SSC_DEVICES 3 +#endif + +/* + * SSC PDC registers required by the PCM DMA engine. + */ +static struct atmel_pdc_regs pdc_tx_reg = { + .xpr = ATMEL_PDC_TPR, + .xcr = ATMEL_PDC_TCR, + .xnpr = ATMEL_PDC_TNPR, + .xncr = ATMEL_PDC_TNCR, +}; + +static struct atmel_pdc_regs pdc_rx_reg = { + .xpr = ATMEL_PDC_RPR, + .xcr = ATMEL_PDC_RCR, + .xnpr = ATMEL_PDC_RNPR, + .xncr = ATMEL_PDC_RNCR, +}; + +/* + * SSC & PDC status bits for transmit and receive. + */ +static struct atmel_ssc_mask ssc_tx_mask = { + .ssc_enable = SSC_BIT(CR_TXEN), + .ssc_disable = SSC_BIT(CR_TXDIS), + .ssc_endx = SSC_BIT(SR_ENDTX), + .ssc_endbuf = SSC_BIT(SR_TXBUFE), + .pdc_enable = ATMEL_PDC_TXTEN, + .pdc_disable = ATMEL_PDC_TXTDIS, +}; + +static struct atmel_ssc_mask ssc_rx_mask = { + .ssc_enable = SSC_BIT(CR_RXEN), + .ssc_disable = SSC_BIT(CR_RXDIS), + .ssc_endx = SSC_BIT(SR_ENDRX), + .ssc_endbuf = SSC_BIT(SR_RXBUFF), + .pdc_enable = ATMEL_PDC_RXTEN, + .pdc_disable = ATMEL_PDC_RXTDIS, +}; + + +/* + * DMA parameters. + */ +static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { + {{ + .name = "SSC0 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC0 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + } }, +#if NUM_SSC_DEVICES == 3 + {{ + .name = "SSC1 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + } }, + {{ + .name = "SSC2 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC2 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + } }, +#endif +}; + + +static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { + { + .name = "ssc0", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, +#if NUM_SSC_DEVICES == 3 + { + .name = "ssc1", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, + { + .name = "ssc2", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, +#endif +}; + + +/* + * SSC interrupt handler. Passes PDC interrupts to the DMA + * interrupt handler in the PCM driver. + */ +static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) +{ + struct atmel_ssc_info *ssc_p = dev_id; + struct atmel_pcm_dma_params *dma_params; + u32 ssc_sr; + u32 ssc_substream_mask; + int i; + + ssc_sr = (unsigned long)ssc_readl(ssc_p->ssc->regs, SR) + & (unsigned long)ssc_readl(ssc_p->ssc->regs, IMR); + + /* + * Loop through the substreams attached to this SSC. If + * a DMA-related interrupt occurred on that substream, call + * the DMA interrupt handler function, if one has been + * registered in the dma_params structure by the PCM driver. + */ + for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { + dma_params = ssc_p->dma_params[i]; + + if ((dma_params != NULL) && + (dma_params->dma_intr_handler != NULL)) { + ssc_substream_mask = (dma_params->mask->ssc_endx | + dma_params->mask->ssc_endbuf); + if (ssc_sr & ssc_substream_mask) { + dma_params->dma_intr_handler(ssc_sr, + dma_params-> + substream); + } + } + } + + return IRQ_HANDLED; +} + + +/*-------------------------------------------------------------------------*\ + * DAI functions +\*-------------------------------------------------------------------------*/ +/* + * Startup. Only that one substream allowed in each direction. + */ +static int atmel_ssc_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + int dir_mask; + + pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", + ssc_readl(ssc_p->ssc->regs, SR)); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir_mask = SSC_DIR_MASK_PLAYBACK; + else + dir_mask = SSC_DIR_MASK_CAPTURE; + + spin_lock_irq(&ssc_p->lock); + if (ssc_p->dir_mask & dir_mask) { + spin_unlock_irq(&ssc_p->lock); + return -EBUSY; + } + ssc_p->dir_mask |= dir_mask; + spin_unlock_irq(&ssc_p->lock); + + return 0; +} + +/* + * Shutdown. Clear DMA parameters and shutdown the SSC if there + * are no other substreams open. + */ +static void atmel_ssc_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct atmel_pcm_dma_params *dma_params; + int dir, dir_mask; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir = 0; + else + dir = 1; + + dma_params = ssc_p->dma_params[dir]; + + if (dma_params != NULL) { + ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable); + pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n", + (dir ? "receive" : "transmit"), + ssc_readl(ssc_p->ssc->regs, SR)); + + dma_params->ssc = NULL; + dma_params->substream = NULL; + ssc_p->dma_params[dir] = NULL; + } + + dir_mask = 1 << dir; + + spin_lock_irq(&ssc_p->lock); + ssc_p->dir_mask &= ~dir_mask; + if (!ssc_p->dir_mask) { + if (ssc_p->initialized) { + /* Shutdown the SSC clock. */ + pr_debug("atmel_ssc_dau: Stopping clock\n"); + clk_disable(ssc_p->ssc->clk); + + free_irq(ssc_p->ssc->irq, ssc_p); + ssc_p->initialized = 0; + } + + /* Reset the SSC */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + /* Clear the SSC dividers */ + ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; + } + spin_unlock_irq(&ssc_p->lock); +} + + +/* + * Record the DAI format for use in hw_params(). + */ +static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + ssc_p->daifmt = fmt; + return 0; +} + +/* + * Record SSC clock dividers for use in hw_params(). + */ +static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + switch (div_id) { + case ATMEL_SSC_CMR_DIV: + /* + * The same master clock divider is used for both + * transmit and receive, so if a value has already + * been set, it must match this value. + */ + if (ssc_p->cmr_div == 0) + ssc_p->cmr_div = div; + else + if (div != ssc_p->cmr_div) + return -EBUSY; + break; + + case ATMEL_SSC_TCMR_PERIOD: + ssc_p->tcmr_period = div; + break; + + case ATMEL_SSC_RCMR_PERIOD: + ssc_p->rcmr_period = div; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Configure the SSC. + */ +static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + int id = rtd->dai->cpu_dai->id; + struct atmel_ssc_info *ssc_p = &ssc_info[id]; + struct atmel_pcm_dma_params *dma_params; + int dir, channels, bits; + u32 tfmr, rfmr, tcmr, rcmr; + int start_event; + int ret; + + /* + * Currently, there is only one set of dma params for + * each direction. If more are added, this code will + * have to be changed to select the proper set. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir = 0; + else + dir = 1; + + dma_params = &ssc_dma_params[id][dir]; + dma_params->ssc = ssc_p->ssc; + dma_params->substream = substream; + + ssc_p->dma_params[dir] = dma_params; + + /* + * The cpu_dai->dma_data field is only used to communicate the + * appropriate DMA parameters to the pcm driver hw_params() + * function. It should not be used for other purposes + * as it is common to all substreams. + */ + rtd->dai->cpu_dai->dma_data = dma_params; + + channels = params_channels(params); + + /* + * Determine sample size in bits and the PDC increment. + */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + bits = 8; + dma_params->pdc_xfer_size = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + bits = 16; + dma_params->pdc_xfer_size = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + bits = 24; + dma_params->pdc_xfer_size = 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bits = 32; + dma_params->pdc_xfer_size = 4; + break; + default: + printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format"); + return -EINVAL; + } + + /* + * The SSC only supports up to 16-bit samples in I2S format, due + * to the size of the Frame Mode Register FSLEN field. + */ + if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S + && bits > 16) { + printk(KERN_WARNING + "atmel_ssc_dai: sample size %d" + "is too large for I2S\n", bits); + return -EINVAL; + } + + /* + * Compute SSC register settings. + */ + switch (ssc_p->daifmt + & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + /* + * I2S format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated + * from the MCK divider, and the BCLK signal + * is output on the SSC TK line. + */ + rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + | SSC_BF(RCMR_STTDLY, START_DELAY) + | SSC_BF(RCMR_START, SSC_START_FALLING_RF) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_DIV); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) + | SSC_BF(RFMR_FSLEN, (bits - 1)) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + | SSC_BF(TCMR_STTDLY, START_DELAY) + | SSC_BF(TCMR_START, SSC_START_FALLING_RF) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) + | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) + | SSC_BF(TCMR_CKS, SSC_CKS_DIV); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) + | SSC_BF(TFMR_FSLEN, (bits - 1)) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + /* + * I2S format, CODEC supplies BCLK and LRC clocks. + * + * The SSC transmit clock is obtained from the BCLK signal on + * on the TK line, and the SSC receive clock is + * generated from the transmit clock. + * + * For single channel data, one sample is transferred + * on the falling edge of the LRC clock. + * For two channel data, one sample is + * transferred on both edges of the LRC clock. + */ + start_event = ((channels == 1) + ? SSC_START_FALLING_RF + : SSC_START_EDGE_RF); + + rcmr = SSC_BF(RCMR_PERIOD, 0) + | SSC_BF(RCMR_STTDLY, START_DELAY) + | SSC_BF(RCMR_START, start_event) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(RFMR_FSLEN, 0) + | SSC_BF(RFMR_DATNB, 0) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, 0) + | SSC_BF(TCMR_STTDLY, START_DELAY) + | SSC_BF(TCMR_START, start_event) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE) + | SSC_BF(TCMR_CKS, SSC_CKS_PIN); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(TFMR_FSLEN, 0) + | SSC_BF(TFMR_DATNB, 0) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + /* + * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output + * on the SSC TK line. + */ + rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + | SSC_BF(RCMR_STTDLY, 1) + | SSC_BF(RCMR_START, SSC_START_RISING_RF) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_DIV); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) + | SSC_BF(RFMR_FSLEN, 0) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + | SSC_BF(TCMR_STTDLY, 1) + | SSC_BF(TCMR_START, SSC_START_RISING_RF) + | SSC_BF(TCMR_CKI, SSC_CKI_RISING) + | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) + | SSC_BF(TCMR_CKS, SSC_CKS_DIV); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) + | SSC_BF(TFMR_FSLEN, 0) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + default: + printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", + ssc_p->daifmt); + return -EINVAL; + break; + } + pr_debug("atmel_ssc_hw_params: " + "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", + rcmr, rfmr, tcmr, tfmr); + + if (!ssc_p->initialized) { + + /* Enable PMC peripheral clock for this SSC */ + pr_debug("atmel_ssc_dai: Starting clock\n"); + clk_enable(ssc_p->ssc->clk); + + /* Reset the SSC and its PDC registers */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + + ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); + + ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); + + ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0, + ssc_p->name, ssc_p); + if (ret < 0) { + printk(KERN_WARNING + "atmel_ssc_dai: request_irq failure\n"); + pr_debug("Atmel_ssc_dai: Stoping clock\n"); + clk_disable(ssc_p->ssc->clk); + return ret; + } + + ssc_p->initialized = 1; + } + + /* set SSC clock mode register */ + ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); + + /* set receive clock mode and format */ + ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); + ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); + + /* set transmit clock mode and format */ + ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); + ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); + + pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n"); + return 0; +} + + +static int atmel_ssc_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct atmel_pcm_dma_params *dma_params; + int dir; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir = 0; + else + dir = 1; + + dma_params = ssc_p->dma_params[dir]; + + ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); + + pr_debug("%s enabled SSC_SR=0x%08x\n", + dir ? "receive" : "transmit", + ssc_readl(ssc_p->ssc->regs, SR)); + return 0; +} + + +#ifdef CONFIG_PM +static int atmel_ssc_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct atmel_ssc_info *ssc_p; + + if (!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* Save the status register before disabling transmit and receive */ + ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); + + /* Save the current interrupt mask, then disable unmasked interrupts */ + ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); + ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); + + ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); + ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); + ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); + ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); + ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); + + return 0; +} + + + +static int atmel_ssc_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct atmel_ssc_info *ssc_p; + u32 cr; + + if (!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* restore SSC register settings */ + ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); + ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); + ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); + ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); + ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); + + /* re-enable interrupts */ + ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); + + /* Re-enable recieve and transmit as appropriate */ + cr = 0; + cr |= + (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; + cr |= + (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; + ssc_writel(ssc_p->ssc->regs, CR, cr); + + return 0; +} +#else /* CONFIG_PM */ +# define atmel_ssc_suspend NULL +# define atmel_ssc_resume NULL +#endif /* CONFIG_PM */ + + +#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) + +#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { + { .name = "atmel-ssc0", + .id = 0, + .type = SND_SOC_DAI_PCM, + .suspend = atmel_ssc_suspend, + .resume = atmel_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = ATMEL_SSC_RATES, + .formats = ATMEL_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = ATMEL_SSC_RATES, + .formats = ATMEL_SSC_FORMATS,}, + .ops = { + .startup = atmel_ssc_startup, + .shutdown = atmel_ssc_shutdown, + .prepare = atmel_ssc_prepare, + .hw_params = atmel_ssc_hw_params,}, + .dai_ops = { + .set_fmt = atmel_ssc_set_dai_fmt, + .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[0], + }, +#if NUM_SSC_DEVICES == 3 + { .name = "atmel-ssc1", + .id = 1, + .type = SND_SOC_DAI_PCM, + .suspend = atmel_ssc_suspend, + .resume = atmel_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = ATMEL_SSC_RATES, + .formats = ATMEL_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = ATMEL_SSC_RATES, + .formats = ATMEL_SSC_FORMATS,}, + .ops = { + .startup = atmel_ssc_startup, + .shutdown = atmel_ssc_shutdown, + .prepare = atmel_ssc_prepare, + .hw_params = atmel_ssc_hw_params,}, + .dai_ops = { + .set_fmt = atmel_ssc_set_dai_fmt, + .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[1], + }, + { .name = "atmel-ssc2", + .id = 2, + .type = SND_SOC_DAI_PCM, + .suspend = atmel_ssc_suspend, + .resume = atmel_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = ATMEL_SSC_RATES, + .formats = ATMEL_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = ATMEL_SSC_RATES, + .formats = ATMEL_SSC_FORMATS,}, + .ops = { + .startup = atmel_ssc_startup, + .shutdown = atmel_ssc_shutdown, + .prepare = atmel_ssc_prepare, + .hw_params = atmel_ssc_hw_params,}, + .dai_ops = { + .set_fmt = atmel_ssc_set_dai_fmt, + .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[2], + }, +#endif +}; +EXPORT_SYMBOL_GPL(atmel_ssc_dai); + +/* Module information */ +MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); +MODULE_DESCRIPTION("ATMEL SSC ASoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h new file mode 100644 index 00000000000..a828746e8a2 --- /dev/null +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -0,0 +1,121 @@ +/* + * atmel_ssc_dai.h - ALSA SSC interface for the Atmel SoC + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Author: Sedji Gaouaou + * ATMEL CORP. + * + * Based on at91-ssc.c by + * Frank Mandarino + * Based on pxa2xx Platform drivers by + * Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ATMEL_SSC_DAI_H +#define _ATMEL_SSC_DAI_H + +#include +#include + +#include "atmel-pcm.h" + +/* SSC system clock ids */ +#define ATMEL_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ + +/* SSC divider ids */ +#define ATMEL_SSC_CMR_DIV 0 /* MCK divider for BCLK */ +#define ATMEL_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ +#define ATMEL_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ +/* + * SSC direction masks + */ +#define SSC_DIR_MASK_UNUSED 0 +#define SSC_DIR_MASK_PLAYBACK 1 +#define SSC_DIR_MASK_CAPTURE 2 + +/* + * SSC register values that Atmel left out of . These + * are expected to be used with SSC_BF + */ +/* START bit field values */ +#define SSC_START_CONTINUOUS 0 +#define SSC_START_TX_RX 1 +#define SSC_START_LOW_RF 2 +#define SSC_START_HIGH_RF 3 +#define SSC_START_FALLING_RF 4 +#define SSC_START_RISING_RF 5 +#define SSC_START_LEVEL_RF 6 +#define SSC_START_EDGE_RF 7 +#define SSS_START_COMPARE_0 8 + +/* CKI bit field values */ +#define SSC_CKI_FALLING 0 +#define SSC_CKI_RISING 1 + +/* CKO bit field values */ +#define SSC_CKO_NONE 0 +#define SSC_CKO_CONTINUOUS 1 +#define SSC_CKO_TRANSFER 2 + +/* CKS bit field values */ +#define SSC_CKS_DIV 0 +#define SSC_CKS_CLOCK 1 +#define SSC_CKS_PIN 2 + +/* FSEDGE bit field values */ +#define SSC_FSEDGE_POSITIVE 0 +#define SSC_FSEDGE_NEGATIVE 1 + +/* FSOS bit field values */ +#define SSC_FSOS_NONE 0 +#define SSC_FSOS_NEGATIVE 1 +#define SSC_FSOS_POSITIVE 2 +#define SSC_FSOS_LOW 3 +#define SSC_FSOS_HIGH 4 +#define SSC_FSOS_TOGGLE 5 + +#define START_DELAY 1 + +struct atmel_ssc_state { + u32 ssc_cmr; + u32 ssc_rcmr; + u32 ssc_rfmr; + u32 ssc_tcmr; + u32 ssc_tfmr; + u32 ssc_sr; + u32 ssc_imr; +}; + + +struct atmel_ssc_info { + char *name; + struct ssc_device *ssc; + spinlock_t lock; /* lock for dir_mask */ + unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ + unsigned short initialized; /* true if SSC has been initialized */ + unsigned short daifmt; + unsigned short cmr_div; + unsigned short tcmr_period; + unsigned short rcmr_period; + struct atmel_pcm_dma_params *dma_params[2]; + struct atmel_ssc_state ssc_state; +}; +extern struct snd_soc_dai atmel_ssc_dai[]; + +#endif /* _AT91_SSC_DAI_H */ diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c new file mode 100644 index 00000000000..5b07cf7ea4e --- /dev/null +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -0,0 +1,513 @@ +/* sound/soc/at32/playpaq_wm8510.c + * ASoC machine driver for PlayPaq using WM8510 codec + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c + * + * NOTE: If you don't have the AT32 enhanced portmux configured (which + * isn't currently in the mainline or Atmel patched kernel), you will + * need to set the MCLK pin (PA30) to peripheral A in your board initialization + * code. Something like: + * at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); + * + */ + +/* #define DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "../codecs/wm8510.h" +#include "atmel-pcm.h" +#include "atmel_ssc_dai.h" + + +/*-------------------------------------------------------------------------*\ + * constants +\*-------------------------------------------------------------------------*/ +#define MCLK_PIN GPIO_PIN_PA(30) +#define MCLK_PERIPH GPIO_PERIPH_A + + +/*-------------------------------------------------------------------------*\ + * data types +\*-------------------------------------------------------------------------*/ +/* SSC clocking data */ +struct ssc_clock_data { + /* CMR div */ + unsigned int cmr_div; + + /* Frame period (as needed by xCMR.PERIOD) */ + unsigned int period; + + /* The SSC clock rate these settings where calculated for */ + unsigned long ssc_rate; +}; + + +/*-------------------------------------------------------------------------*\ + * module data +\*-------------------------------------------------------------------------*/ +static struct clk *_gclk0; +static struct clk *_pll0; + +#define CODEC_CLK (_gclk0) + + +/*-------------------------------------------------------------------------*\ + * Sound SOC operations +\*-------------------------------------------------------------------------*/ +#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE +static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct at32_ssc_info *ssc_p = cpu_dai->private_data; + struct ssc_device *ssc = ssc_p->ssc; + struct ssc_clock_data cd; + unsigned int rate, width_bits, channels; + unsigned int bitrate, ssc_div; + unsigned actual_rate; + + + /* + * Figure out required bitrate + */ + rate = params_rate(params); + channels = params_channels(params); + width_bits = snd_pcm_format_physical_width(params_format(params)); + bitrate = rate * width_bits * channels; + + + /* + * Figure out required SSC divider and period for required bitrate + */ + cd.ssc_rate = clk_get_rate(ssc->clk); + ssc_div = cd.ssc_rate / bitrate; + cd.cmr_div = ssc_div / 2; + if (ssc_div & 1) { + /* round cmr_div up */ + cd.cmr_div++; + } + cd.period = width_bits - 1; + + + /* + * Find actual rate, compare to requested rate + */ + actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); + pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n", + rate, actual_rate); + + + return cd; +} +#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ + + + +static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct at32_ssc_info *ssc_p = cpu_dai->private_data; + struct ssc_device *ssc = ssc_p->ssc; + unsigned int pll_out = 0, bclk = 0, mclk_div = 0; + int ret; + + + /* Due to difficulties with getting the correct clocks from the AT32's + * PLL0, we're going to let the CODEC be in charge of all the clocks + */ +#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE + const unsigned int fmt = (SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); +#else + struct ssc_clock_data cd; + const unsigned int fmt = (SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); +#endif + + if (ssc == NULL) { + pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n"); + return -EINVAL; + } + + + /* + * Figure out PLL and BCLK dividers for WM8510 + */ + switch (params_rate(params)) { + case 48000: + pll_out = 12288000; + mclk_div = WM8510_MCLKDIV_1; + bclk = WM8510_BCLKDIV_8; + break; + + case 44100: + pll_out = 11289600; + mclk_div = WM8510_MCLKDIV_1; + bclk = WM8510_BCLKDIV_8; + break; + + case 22050: + pll_out = 11289600; + mclk_div = WM8510_MCLKDIV_2; + bclk = WM8510_BCLKDIV_8; + break; + + case 16000: + pll_out = 12288000; + mclk_div = WM8510_MCLKDIV_3; + bclk = WM8510_BCLKDIV_8; + break; + + case 11025: + pll_out = 11289600; + mclk_div = WM8510_MCLKDIV_4; + bclk = WM8510_BCLKDIV_8; + break; + + case 8000: + pll_out = 12288000; + mclk_div = WM8510_MCLKDIV_6; + bclk = WM8510_BCLKDIV_8; + break; + + default: + pr_warning("playpaq_wm8510: Unsupported sample rate %d\n", + params_rate(params)); + return -EINVAL; + } + + + /* + * set CPU and CODEC DAI configuration + */ + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + pr_warning("playpaq_wm8510: " + "Failed to set CODEC DAI format (%d)\n", + ret); + return ret; + } + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_warning("playpaq_wm8510: " + "Failed to set CPU DAI format (%d)\n", + ret); + return ret; + } + + + /* + * Set CPU clock configuration + */ +#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE + cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai); + pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n", + cd.cmr_div, cd.period); + ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div); + if (ret < 0) { + pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n", + ret); + return ret; + } + ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD, + cd.period); + if (ret < 0) { + pr_warning("playpaq_wm8510: " + "Failed to set CPU transmit period (%d)\n", + ret); + return ret; + } +#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ + + + /* + * Set CODEC clock configuration + */ + pr_debug("playpaq_wm8510: " + "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n", + clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div); + + +#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk); + if (ret < 0) { + pr_warning + ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n", + ret); + return ret; + } +#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ + + + ret = snd_soc_dai_set_pll(codec_dai, 0, + clk_get_rate(CODEC_CLK), pll_out); + if (ret < 0) { + pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", + ret); + return ret; + } + + + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div); + if (ret < 0) { + pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n", + ret); + return ret; + } + + + return 0; +} + + + +static struct snd_soc_ops playpaq_wm8510_ops = { + .hw_params = playpaq_wm8510_hw_params, +}; + + + +static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + + + +static const struct snd_soc_dapm_route intercon[] = { + /* speaker connected to SPKOUT */ + {"Ext Spk", NULL, "SPKOUTP"}, + {"Ext Spk", NULL, "SPKOUTN"}, + + {"Mic Bias", NULL, "Int Mic"}, + {"MICN", NULL, "Mic Bias"}, + {"MICP", NULL, "Mic Bias"}, +}; + + + +static int playpaq_wm8510_init(struct snd_soc_codec *codec) +{ + int i; + + /* + * Add DAPM widgets + */ + for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++) + snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]); + + + + /* + * Setup audio path interconnects + */ + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + + + /* always connected pins */ + snd_soc_dapm_enable_pin(codec, "Int Mic"); + snd_soc_dapm_enable_pin(codec, "Ext Spk"); + snd_soc_dapm_sync(codec); + + + + /* Make CSB show PLL rate */ + snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV, + WM8510_OPCLKDIV_1 | 4); + + return 0; +} + + + +static struct snd_soc_dai_link playpaq_wm8510_dai = { + .name = "WM8510", + .stream_name = "WM8510 PCM", + .cpu_dai = &at32_ssc_dai[0], + .codec_dai = &wm8510_dai, + .init = playpaq_wm8510_init, + .ops = &playpaq_wm8510_ops, +}; + + + +static struct snd_soc_machine snd_soc_machine_playpaq = { + .name = "LRS_PlayPaq_WM8510", + .dai_link = &playpaq_wm8510_dai, + .num_links = 1, +}; + + + +static struct wm8510_setup_data playpaq_wm8510_setup = { + .i2c_bus = 0, + .i2c_address = 0x1a, +}; + + + +static struct snd_soc_device playpaq_wm8510_snd_devdata = { + .machine = &snd_soc_machine_playpaq, + .platform = &at32_soc_platform, + .codec_dev = &soc_codec_dev_wm8510, + .codec_data = &playpaq_wm8510_setup, +}; + +static struct platform_device *playpaq_snd_device; + + +static int __init playpaq_asoc_init(void) +{ + int ret = 0; + struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; + struct ssc_device *ssc = NULL; + + + /* + * Request SSC device + */ + ssc = ssc_request(0); + if (IS_ERR(ssc)) { + ret = PTR_ERR(ssc); + goto err_ssc; + } + ssc_p->ssc = ssc; + + + /* + * Configure MCLK for WM8510 + */ + _gclk0 = clk_get(NULL, "gclk0"); + if (IS_ERR(_gclk0)) { + _gclk0 = NULL; + goto err_gclk0; + } + _pll0 = clk_get(NULL, "pll0"); + if (IS_ERR(_pll0)) { + _pll0 = NULL; + goto err_pll0; + } + if (clk_set_parent(_gclk0, _pll0)) { + pr_warning("snd-soc-playpaq: " + "Failed to set PLL0 as parent for DAC clock\n"); + goto err_set_clk; + } + clk_set_rate(CODEC_CLK, 12000000); + clk_enable(CODEC_CLK); + +#if defined CONFIG_AT32_ENHANCED_PORTMUX + at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0); +#endif + + + /* + * Create and register platform device + */ + playpaq_snd_device = platform_device_alloc("soc-audio", 0); + if (playpaq_snd_device == NULL) { + ret = -ENOMEM; + goto err_device_alloc; + } + + platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata); + playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev; + + ret = platform_device_add(playpaq_snd_device); + if (ret) { + pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n", + ret); + goto err_device_add; + } + + return 0; + + +err_device_add: + if (playpaq_snd_device != NULL) { + platform_device_put(playpaq_snd_device); + playpaq_snd_device = NULL; + } +err_device_alloc: +err_set_clk: + if (_pll0 != NULL) { + clk_put(_pll0); + _pll0 = NULL; + } +err_pll0: + if (_gclk0 != NULL) { + clk_put(_gclk0); + _gclk0 = NULL; + } +err_gclk0: + ssc_free(ssc); +err_ssc: + return ret; +} + + +static void __exit playpaq_asoc_exit(void) +{ + struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; + struct ssc_device *ssc; + + if (ssc_p != NULL) { + ssc = ssc_p->ssc; + if (ssc != NULL) + ssc_free(ssc); + ssc_p->ssc = NULL; + } + + if (_gclk0 != NULL) { + clk_put(_gclk0); + _gclk0 = NULL; + } + if (_pll0 != NULL) { + clk_put(_pll0); + _pll0 = NULL; + } + +#if defined CONFIG_AT32_ENHANCED_PORTMUX + at32_free_pin(MCLK_PIN); +#endif + + platform_device_unregister(playpaq_snd_device); + playpaq_snd_device = NULL; +} + +module_init(playpaq_asoc_init); +module_exit(playpaq_asoc_exit); + +MODULE_AUTHOR("Geoffrey Wossum "); +MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 5b99e6ccf964e733f0afe2b7bd09559a51a540ca Mon Sep 17 00:00:00 2001 From: Sedji Gaouaou Date: Fri, 3 Oct 2008 16:58:58 +0200 Subject: ASoC: Add audio support for the Atmel AT91SAM9G20ek board(uing wolfson 8731). Add audio support for the Atmel AT91SAM9G20ek board(uing wolfson 8731). It is based on the former eti_b1_wm8731.c file, using the atmel scc API. Signed-off-by: Sedji Gaouaou Signed-off-by: Mark Brown --- sound/soc/atmel/sam9g20_wm8731.c | 329 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 sound/soc/atmel/sam9g20_wm8731.c diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c new file mode 100644 index 00000000000..4e191df4e2b --- /dev/null +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -0,0 +1,329 @@ +/* + * sam9g20_wm8731 -- SoC audio for AT91SAM9G20-based + * ATMEL AT91SAM9G20ek board. + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Authors: Sedji Gaouaou + * + * Based on ati_b1_wm8731.c by: + * Frank Mandarino + * Copyright 2006 Endrelia Technologies Inc. + * Based on corgi.c by: + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "../codecs/wm8731.h" +#include "atmel-pcm.h" +#include "atmel_ssc_dai.h" + + +static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + int ret; + + /* codec system clock is supplied by PCK0, set to 12MHz */ + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, + 12000000, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + +static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + + dev_dbg(rtd->socdev->dev, "shutdown"); +} + +static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct atmel_ssc_info *ssc_p = cpu_dai->private_data; + struct ssc_device *ssc = ssc_p->ssc; + int ret; + + unsigned int rate; + int cmr_div, period; + + if (ssc == NULL) { + printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n"); + return -EINVAL; + } + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* + * The SSC clock dividers depend on the sample rate. The CMR.DIV + * field divides the system master clock MCK to drive the SSC TK + * signal which provides the codec BCLK. The TCMR.PERIOD and + * RCMR.PERIOD fields further divide the BCLK signal to drive + * the SSC TF and RF signals which provide the codec DACLRC and + * ADCLRC clocks. + * + * The dividers were determined through trial and error, where a + * CMR.DIV value is chosen such that the resulting BCLK value is + * divisible, or almost divisible, by (2 * sample rate), and then + * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. + */ + rate = params_rate(params); + + switch (rate) { + case 8000: + cmr_div = 55; /* BCLK = 133MHz/(2*55) = 1.209MHz */ + period = 74; /* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */ + break; + case 11025: + cmr_div = 67; /* BCLK = 133MHz/(2*60) = 1.108MHz */ + period = 45; /* LRC = BCLK/(2*(49+1)) = 11083,3Hz */ + break; + case 16000: + cmr_div = 63; /* BCLK = 133MHz/(2*63) = 1.055MHz */ + period = 32; /* LRC = BCLK/(2*(32+1)) = 15993,2Hz */ + break; + case 22050: + cmr_div = 52; /* BCLK = 133MHz/(2*52) = 1.278MHz */ + period = 28; /* LRC = BCLK/(2*(28+1)) = 22049Hz */ + break; + case 32000: + cmr_div = 66; /* BCLK = 133MHz/(2*66) = 1.007MHz */ + period = 15; /* LRC = BCLK/(2*(15+1)) = 31486,742Hz */ + break; + case 44100: + cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ + period = 25; /* LRC = BCLK/(2*(25+1)) = 44098Hz */ + break; + case 48000: + cmr_div = 33; /* BCLK = 133MHz/(2*33) = 2.015MHz */ + period = 20; /* LRC = BCLK/(2*(20+1)) = 47979,79Hz */ + break; + case 88200: + cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ + period = 12; /* LRC = BCLK/(2*(12+1)) = 88196Hz */ + break; + case 96000: + cmr_div = 23; /* BCLK = 133MHz/(2*23) = 2.891MHz */ + period = 14; /* LRC = BCLK/(2*(14+1)) = 96376Hz */ + break; + default: + printk(KERN_WARNING "unsupported rate %d" + " on at91sam9g20ek board\n", rate); + return -EINVAL; + } + + /* set the MCK divider for BCLK */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div); + if (ret < 0) + return ret; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* set the BCLK divider for DACLRC */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, + ATMEL_SSC_TCMR_PERIOD, period); + } else { + /* set the BCLK divider for ADCLRC */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, + ATMEL_SSC_RCMR_PERIOD, period); + } + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops at91sam9g20ek_ops = { + .startup = at91sam9g20ek_startup, + .hw_params = at91sam9g20ek_hw_params, + .shutdown = at91sam9g20ek_shutdown, +}; + + +static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static const struct snd_soc_dapm_route intercon[] = { + + /* speaker connected to LHPOUT */ + {"Ext Spk", NULL, "LHPOUT"}, + + /* mic is connected to Mic Jack, with WM8731 Mic Bias */ + {"MICIN", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Int Mic"}, +}; + +/* + * Logic for a wm8731 as connected on a at91sam9g20ek board. + */ +static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) +{ + printk(KERN_DEBUG + "at91sam9g20ek_wm8731 " + ": at91sam9g20ek_wm8731_init() called\n"); + + /* Add specific widgets */ + snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets, + ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); + /* Set up specific audio path interconnects */ + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + /* not connected */ + snd_soc_dapm_disable_pin(codec, "RLINEIN"); + snd_soc_dapm_disable_pin(codec, "LLINEIN"); + + /* always connected */ + snd_soc_dapm_enable_pin(codec, "Int Mic"); + snd_soc_dapm_enable_pin(codec, "Ext Spk"); + + snd_soc_dapm_sync(codec); + + return 0; +} + +static struct snd_soc_dai_link at91sam9g20ek_dai = { + .name = "WM8731", + .stream_name = "WM8731 PCM", + .cpu_dai = &atmel_ssc_dai[0], + .codec_dai = &wm8731_dai, + .init = at91sam9g20ek_wm8731_init, + .ops = &at91sam9g20ek_ops, +}; + +static struct snd_soc_machine snd_soc_machine_at91sam9g20ek = { + .name = "WM8731", + .dai_link = &at91sam9g20ek_dai, + .num_links = 1, +}; + +static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { + .i2c_bus = 0, + .i2c_address = 0x1b, +}; + +static struct snd_soc_device at91sam9g20ek_snd_devdata = { + .machine = &snd_soc_machine_at91sam9g20ek, + .platform = &atmel_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &at91sam9g20ek_wm8731_setup, +}; + +static struct platform_device *at91sam9g20ek_snd_device; + +static int __init at91sam9g20ek_init(void) +{ + struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; + struct ssc_device *ssc = NULL; + int ret; + + /* + * Request SSC device + */ + ssc = ssc_request(0); + if (IS_ERR(ssc)) { + ret = PTR_ERR(ssc); + ssc = NULL; + goto err_ssc; + } + ssc_p->ssc = ssc; + + at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); + if (!at91sam9g20ek_snd_device) { + printk(KERN_DEBUG + "platform device allocation failed\n"); + ret = -ENOMEM; + } + + platform_set_drvdata(at91sam9g20ek_snd_device, + &at91sam9g20ek_snd_devdata); + at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev; + + ret = platform_device_add(at91sam9g20ek_snd_device); + if (ret) { + printk(KERN_DEBUG + "platform device allocation failed\n"); + platform_device_put(at91sam9g20ek_snd_device); + } + + return ret; + +err_ssc: + return ret; +} + +static void __exit at91sam9g20ek_exit(void) +{ + struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; + struct ssc_device *ssc; + + if (ssc_p != NULL) { + ssc = ssc_p->ssc; + if (ssc != NULL) + ssc_free(ssc); + ssc_p->ssc = NULL; + } + + platform_device_unregister(at91sam9g20ek_snd_device); + at91sam9g20ek_snd_device = NULL; +} + +module_init(at91sam9g20ek_init); +module_exit(at91sam9g20ek_exit); + +/* Module information */ +MODULE_AUTHOR("Sedji Gaouaou "); +MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From dce908e26fa0ea7d504d3f294c7411ed1eba5077 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 3 Nov 2008 12:22:07 -0700 Subject: ALSA: SOC: Fix setting codec register with debugfs filesystem merge error Call device_create_file only once in snd_soc_dapm_sys_add function. Signed-off-by: Troy Kisky Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/soc-dapm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7bf3c409459..0fecbb44726 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -822,14 +822,8 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { - int ret; - if (!dapm_status) return 0; - - ret = device_create_file(dev, &dev_attr_dapm_widget); - if (ret != 0) - return ret; return device_create_file(dev, &dev_attr_dapm_widget); } -- cgit v1.2.3 From 3865675c60aec3e81d72d484680b544afc6fc51d Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Fri, 31 Oct 2008 22:50:00 +0800 Subject: ALSA: ASoC codec: remove unused #include The file(s) below do not use LINUX_VERSION_CODE nor KERNEL_VERSION. sound/soc/codecs/ad73311.c This patch removes the said #include . Signed-off-by: Huang Weiyi Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/ad73311.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 37af8607b00..59c4c8f18cb 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include -- cgit v1.2.3 From 0ee4663617fb0f78cec4cc6558a096ccbd8c3ffc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2008 18:06:23 +0100 Subject: ALSA: ASoC - Remove unnecessary inclusion of linux/version.h Signed-off-by: Takashi Iwai --- sound/soc/atmel/playpaq_wm8510.c | 1 - sound/soc/atmel/sam9g20_wm8731.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index 5b07cf7ea4e..ea7935d2a66 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 4e191df4e2b..710addcc66b 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include -- cgit v1.2.3 From 74e722015fe47c8f0e7ef7c0b4cf32d3e4ae11a0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 3 Nov 2008 12:02:12 +0000 Subject: ASoC: Add Palm/PXA27x unified ASoC audio driver this patch adds asoc audio driver for pxa27x based Palm PDAs. I tested it for palmtx, t5 and ld, it should work with palmz72 as well (slapin, please test). I sent it here some time ago, but now I got to fixing bugs in it. It should be somehow mostly ok and ready for applying. [Converted to use snd_soc_dapm_nc_pin() and bool Kconfig -- broonie] Signed-off-by: Marek Vasut Signed-off-by: Mark Brown --- arch/arm/mach-pxa/include/mach/palmasoc.h | 13 ++ sound/soc/pxa/Kconfig | 9 + sound/soc/pxa/Makefile | 2 + sound/soc/pxa/palm27x.c | 269 ++++++++++++++++++++++++++++++ 4 files changed, 293 insertions(+) create mode 100644 arch/arm/mach-pxa/include/mach/palmasoc.h create mode 100644 sound/soc/pxa/palm27x.c diff --git a/arch/arm/mach-pxa/include/mach/palmasoc.h b/arch/arm/mach-pxa/include/mach/palmasoc.h new file mode 100644 index 00000000000..6c4b1f7de20 --- /dev/null +++ b/arch/arm/mach-pxa/include/mach/palmasoc.h @@ -0,0 +1,13 @@ +#ifndef _INCLUDE_PALMASOC_H_ +#define _INCLUDE_PALMASOC_H_ +struct palm27x_asoc_info { + int jack_gpio; +}; + +#ifdef CONFIG_SND_PXA2XX_SOC_PALM27X +void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data); +#else +static inline void palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) {} +#endif + +#endif diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 4235524238f..f82e1069947 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -79,6 +79,15 @@ config SND_PXA2XX_SOC_EM_X270 Say Y if you want to add support for SoC audio on CompuLab EM-x270. +config SND_PXA2XX_SOC_PALM27X + bool "SoC Audio support for Palm T|X, T5 and LifeDrive" + depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || MACH_PALMT5) + select SND_PXA2XX_SOC_AC97 + select SND_SOC_WM9712 + help + Say Y if you want to add support for SoC audio on + Palm T|X, T5 or LifeDrive handheld computer. + config SND_SOC_ZYLONITE tristate "SoC Audio support for Marvell Zylonite" depends on SND_PXA2XX_SOC && MACH_ZYLONITE diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 00258abb84a..1a3a36e75bf 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -16,6 +16,7 @@ snd-soc-tosa-objs := tosa.o snd-soc-e800-objs := e800_wm9712.o snd-soc-spitz-objs := spitz.o snd-soc-em-x270-objs := em-x270.o +snd-soc-palm27x-objs := palm27x.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -23,3 +24,4 @@ obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o +obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c new file mode 100644 index 00000000000..e364abc700d --- /dev/null +++ b/sound/soc/pxa/palm27x.c @@ -0,0 +1,269 @@ +/* + * linux/sound/soc/pxa/palm27x.c + * + * SoC Audio driver for Palm T|X, T5 and LifeDrive + * + * based on tosa.c + * + * Copyright (C) 2008 Marek Vasut + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "../codecs/wm9712.h" +#include "pxa2xx-pcm.h" +#include "pxa2xx-ac97.h" + +static int palm27x_jack_func = 1; +static int palm27x_spk_func = 1; +static int palm27x_ep_gpio = -1; + +static void palm27x_ext_control(struct snd_soc_codec *codec) +{ + if (!palm27x_spk_func) + snd_soc_dapm_enable_pin(codec, "Speaker"); + else + snd_soc_dapm_disable_pin(codec, "Speaker"); + + if (!palm27x_jack_func) + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + else + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + + snd_soc_dapm_sync(codec); +} + +static int palm27x_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + /* check the jack status at stream startup */ + palm27x_ext_control(codec); + return 0; +} + +static struct snd_soc_ops palm27x_ops = { + .startup = palm27x_startup, +}; + +static irqreturn_t palm27x_interrupt(int irq, void *v) +{ + palm27x_spk_func = gpio_get_value(palm27x_ep_gpio); + palm27x_jack_func = !palm27x_spk_func; + return IRQ_HANDLED; +} + +static int palm27x_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = palm27x_jack_func; + return 0; +} + +static int palm27x_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (palm27x_jack_func == ucontrol->value.integer.value[0]) + return 0; + + palm27x_jack_func = ucontrol->value.integer.value[0]; + palm27x_ext_control(codec); + return 1; +} + +static int palm27x_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = palm27x_spk_func; + return 0; +} + +static int palm27x_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (palm27x_spk_func == ucontrol->value.integer.value[0]) + return 0; + + palm27x_spk_func = ucontrol->value.integer.value[0]; + palm27x_ext_control(codec); + return 1; +} + +/* PalmTX machine dapm widgets */ +static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +/* PalmTX audio map */ +static const struct snd_soc_dapm_route audio_map[] = { + /* headphone connected to HPOUTL, HPOUTR */ + {"Headphone Jack", NULL, "HPOUTL"}, + {"Headphone Jack", NULL, "HPOUTR"}, + + /* ext speaker connected to ROUT2, LOUT2 */ + {"Speaker", NULL, "LOUT2"}, + {"Speaker", NULL, "ROUT2"}, +}; + +static const char *jack_function[] = {"Headphone", "Off"}; +static const char *spk_function[] = {"On", "Off"}; +static const struct soc_enum palm27x_enum[] = { + SOC_ENUM_SINGLE_EXT(2, jack_function), + SOC_ENUM_SINGLE_EXT(2, spk_function), +}; + +static const struct snd_kcontrol_new palm27x_controls[] = { + SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack, + palm27x_set_jack), + SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk, + palm27x_set_spk), +}; + +static int palm27x_ac97_init(struct snd_soc_codec *codec) +{ + int i, err; + + snd_soc_dapm_nc_pin(codec, "OUT3"); + snd_soc_dapm_nc_pin(codec, "MONOOUT"); + + /* add palm27x specific controls */ + for (i = 0; i < ARRAY_SIZE(palm27x_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&palm27x_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + /* add palm27x specific widgets */ + snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, + ARRAY_SIZE(palm27x_dapm_widgets)); + + /* set up palm27x specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_sync(codec); + return 0; +} + +static struct snd_soc_dai_link palm27x_dai[] = { +{ + .name = "AC97 HiFi", + .stream_name = "AC97 HiFi", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], + .init = palm27x_ac97_init, + .ops = &palm27x_ops, +}, +{ + .name = "AC97 Aux", + .stream_name = "AC97 Aux", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], + .ops = &palm27x_ops, +}, +}; + +static struct snd_soc_machine palm27x_asoc = { + .name = "Palm/PXA27x", + .dai_link = palm27x_dai, + .num_links = ARRAY_SIZE(palm27x_dai), +}; + +static struct snd_soc_device palm27x_snd_devdata = { + .machine = &palm27x_asoc, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm9712, +}; + +static struct platform_device *palm27x_snd_device; + +static int __init palm27x_asoc_init(void) +{ + int ret; + + if (!(machine_is_palmtx() || machine_is_palmt5() || + machine_is_palmld())) + return -ENODEV; + + ret = gpio_request(palm27x_ep_gpio, "Headphone Jack"); + if (ret) + return ret; + ret = gpio_direction_input(palm27x_ep_gpio); + if (ret) + goto err_alloc; + + if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "Headphone jack", NULL)) + goto err_alloc; + + palm27x_snd_device = platform_device_alloc("soc-audio", -1); + if (!palm27x_snd_device) { + ret = -ENOMEM; + goto err_dev; + } + + platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata); + palm27x_snd_devdata.dev = &palm27x_snd_device->dev; + ret = platform_device_add(palm27x_snd_device); + + if (ret != 0) + goto put_device; + + return 0; + +put_device: + platform_device_put(palm27x_snd_device); +err_dev: + free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); +err_alloc: + gpio_free(palm27x_ep_gpio); + + return ret; +} + +static void __exit palm27x_asoc_exit(void) +{ + free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); + gpio_free(palm27x_ep_gpio); + platform_device_unregister(palm27x_snd_device); +} + +void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) +{ + palm27x_ep_gpio = data->jack_gpio; +} + +module_init(palm27x_asoc_init); +module_exit(palm27x_asoc_exit); + +/* Module information */ +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ea913940c39a61214c799cc7093d7b20fe11a94c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 5 Nov 2008 11:13:21 +0000 Subject: ASoC: Remove core version number Rather than try to remember to keep the core version number updated (which hasn't been happening) just remove it. It was much more useful when ASoC was out of tree. Signed-off-by: Mark brown --- include/sound/soc.h | 2 -- sound/soc/soc-core.c | 1 - 2 files changed, 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index da0040b69c2..fa1b99b4589 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -21,8 +21,6 @@ #include #include -#define SND_SOC_VERSION "0.13.2" - /* * Convenience kcontrol builders */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1a173682965..9feaa7b6dc3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1965,7 +1965,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); static int __devinit snd_soc_init(void) { - printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); return platform_driver_register(&soc_driver); } -- cgit v1.2.3 From 8dc840f88d9c9f75f46d5dbe489242f8a114fab6 Mon Sep 17 00:00:00 2001 From: David Anders Date: Wed, 5 Nov 2008 07:39:47 -0800 Subject: ASoC: Add new parameter to s3c24xx_pcm_enqueue The S3C24xx dma does not allow more than one buffer to be enqueue prior to the dma transfers starting. This patch adds an additional parameter to s3c24xx_pcm_enqueue() to allow for passing an initial dma maximum load value. Signed-off-by: David Anders Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx-pcm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index e13e614bada..341198bb0c1 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -78,7 +78,8 @@ struct s3c24xx_runtime_data { * place a dma buffer onto the queue for the dma system * to handle. */ -static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) +static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream, + int dma_max) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; @@ -86,7 +87,10 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) DBG("Entered %s\n", __func__); - while (prtd->dma_loaded < prtd->dma_limit) { + if (!dma_max) + dma_max = prtd->dma_limit; + + while (prtd->dma_loaded < dma_max) { unsigned long len = prtd->dma_period; DBG("dma_loaded: %d\n", prtd->dma_loaded); @@ -132,7 +136,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING) { prtd->dma_loaded--; - s3c24xx_pcm_enqueue(substream); + s3c24xx_pcm_enqueue(substream, 0); } spin_unlock(&prtd->lock); @@ -249,7 +253,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ - s3c24xx_pcm_enqueue(substream); + s3c24xx_pcm_enqueue(substream, 1); return ret; } -- cgit v1.2.3 From e18c94d20224f3df584531a48d944d8cccfda46d Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Wed, 5 Nov 2008 23:51:05 +0200 Subject: ALSA: ASoC: TWL4030 codec - fix 256*Fs clock According to TRM, 256*Fs clock output should be enabled when TWL4030 is in slave mode, not master. This allows sound to work on OMAP3 Pandora, which uses 256*Fs clock. Signed-off-by: Grazvydas Ignotas Acked-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ee2f0d37765..90f3b4decba 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -469,11 +469,11 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: format &= ~(TWL4030_AIF_SLAVE_EN); - format |= TWL4030_CLK256FS_EN; + format &= ~(TWL4030_CLK256FS_EN); break; case SND_SOC_DAIFMT_CBS_CFS: - format &= ~(TWL4030_CLK256FS_EN); format |= TWL4030_AIF_SLAVE_EN; + format |= TWL4030_CLK256FS_EN; break; default: return -EINVAL; -- cgit v1.2.3 From 26df91c36fb976af9d08c20028b5cb1317eedcb3 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Wed, 5 Nov 2008 18:53:28 +0000 Subject: ASoC: TLV320AIC23B Support more sample rates Add support for more sample rates, different crystals and split playback/capture rates. Signed-off-by: Troy Kisky Acked-by: Arun KS Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 222 ++++++++++++++++++++++++++++++++--------- 1 file changed, 177 insertions(+), 45 deletions(-) diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 44308dac9e1..a95b538b8fe 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -37,12 +37,6 @@ #define AIC23_VERSION "0.1" -struct tlv320aic23_srate_reg_info { - u32 sample_rate; - u8 control; /* SR3, SR2, SR1, SR0 and BOSR */ - u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */ -}; - /* * AIC23 register cache */ @@ -261,20 +255,151 @@ static const struct snd_soc_dapm_route intercon[] = { }; -/* tlv320aic23 related */ -static const struct tlv320aic23_srate_reg_info srate_reg_info[] = { - {4000, 0x06, 1}, /* 4000 */ - {8000, 0x06, 0}, /* 8000 */ - {16000, 0x0C, 1}, /* 16000 */ - {22050, 0x11, 1}, /* 22050 */ - {24000, 0x00, 1}, /* 24000 */ - {32000, 0x0C, 0}, /* 32000 */ - {44100, 0x11, 0}, /* 44100 */ - {48000, 0x00, 0}, /* 48000 */ - {88200, 0x1F, 0}, /* 88200 */ - {96000, 0x0E, 0}, /* 96000 */ +/* AIC23 driver data */ +struct aic23 { + struct snd_soc_codec codec; + int mclk; + int requested_adc; + int requested_dac; +}; + +/* + * Common Crystals used + * 11.2896 Mhz /128 = *88.2k /192 = 58.8k + * 12.0000 Mhz /125 = *96k /136 = 88.235K + * 12.2880 Mhz /128 = *96k /192 = 64k + * 16.9344 Mhz /128 = 132.3k /192 = *88.2k + * 18.4320 Mhz /128 = 144k /192 = *96k + */ + +/* + * Normal BOSR 0-256/2 = 128, 1-384/2 = 192 + * USB BOSR 0-250/2 = 125, 1-272/2 = 136 + */ +static const int bosr_usb_divisor_table[] = { + 128, 125, 192, 136 +}; +#define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7)) +#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11) | (1<<15)) +static const unsigned short sr_valid_mask[] = { + LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 0*/ + LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 1*/ + LOWER_GROUP, /* Usb, bosr - 0*/ + UPPER_GROUP, /* Usb, bosr - 1*/ +}; +/* + * Every divisor is a factor of 11*12 + */ +#define SR_MULT (11*12) +#define A(x) (x) ? (SR_MULT/x) : 0 +static const unsigned char sr_adc_mult_table[] = { + A(2), A(2), A(12), A(12), A(0), A(0), A(3), A(1), + A(2), A(2), A(11), A(11), A(0), A(0), A(0), A(1) +}; +static const unsigned char sr_dac_mult_table[] = { + A(2), A(12), A(2), A(12), A(0), A(0), A(3), A(1), + A(2), A(11), A(2), A(11), A(0), A(0), A(0), A(1) }; +static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc, + int dac, int dac_l, int dac_h, int need_dac) +{ + if ((adc >= adc_l) && (adc <= adc_h) && + (dac >= dac_l) && (dac <= dac_h)) { + int diff_adc = need_adc - adc; + int diff_dac = need_dac - dac; + return abs(diff_adc) + abs(diff_dac); + } + return UINT_MAX; +} + +static int find_rate(int mclk, u32 need_adc, u32 need_dac) +{ + int i, j; + int best_i = -1; + int best_j = -1; + int best_div = 0; + unsigned best_score = UINT_MAX; + int adc_l, adc_h, dac_l, dac_h; + + need_adc *= SR_MULT; + need_dac *= SR_MULT; + /* + * rates given are +/- 1/32 + */ + adc_l = need_adc - (need_adc >> 5); + adc_h = need_adc + (need_adc >> 5); + dac_l = need_dac - (need_dac >> 5); + dac_h = need_dac + (need_dac >> 5); + for (i = 0; i < 4; i++) { + int base = mclk / bosr_usb_divisor_table[i]; + int mask = sr_valid_mask[i]; + for (j = 0; j < 16; j++, mask >>= 1) { + int adc; + int dac; + int score; + if ((mask & 1) == 0) + continue; + adc = base * sr_adc_mult_table[j]; + dac = base * sr_dac_mult_table[j]; + score = get_score(adc, adc_l, adc_h, need_adc, + dac, dac_l, dac_h, need_dac); + if (best_score > score) { + best_score = score; + best_i = i; + best_j = j; + best_div = 0; + } + score = get_score((adc >> 1), adc_l, adc_h, need_adc, + (dac >> 1), dac_l, dac_h, need_dac); + /* prefer to have a /2 */ + if ((score != UINT_MAX) && (best_score >= score)) { + best_score = score; + best_i = i; + best_j = j; + best_div = 1; + } + } + } + return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT); +} + +static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, + u32 *sample_rate_adc, u32 *sample_rate_dac) +{ + int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE); + int sr = (src >> 2) & 0x0f; + int val = (mclk / bosr_usb_divisor_table[src & 3]); + int adc = (val * sr_adc_mult_table[sr]) / SR_MULT; + int dac = (val * sr_dac_mult_table[sr]) / SR_MULT; + if (src & TLV320AIC23_CLKIN_HALF) { + adc >>= 1; + dac >>= 1; + } + *sample_rate_adc = adc; + *sample_rate_dac = dac; +} + +static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, + u32 sample_rate_adc, u32 sample_rate_dac) +{ + /* Search for the right sample rate */ + int data = find_rate(mclk, sample_rate_adc, sample_rate_dac); + if (data < 0) { + printk(KERN_ERR "%s:Invalid rate %u,%u requested\n", + __func__, sample_rate_adc, sample_rate_dac); + return -EINVAL; + } + tlv320aic23_write(codec, TLV320AIC23_SRATE, data); + if (1) { + int adc, dac; + get_current_sample_rates(codec, mclk, &adc, &dac); + printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n", + adc, dac, data); + } + return 0; +} + static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) { snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, @@ -293,27 +418,30 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 iface_reg, data; - u8 count = 0; + u16 iface_reg; + int ret; + struct aic23 *aic23 = container_of(codec, struct aic23, codec); + u32 sample_rate_adc = aic23->requested_adc; + u32 sample_rate_dac = aic23->requested_dac; + u32 sample_rate = params_rate(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aic23->requested_dac = sample_rate_dac = sample_rate; + if (!sample_rate_adc) + sample_rate_adc = sample_rate; + } else { + aic23->requested_adc = sample_rate_adc = sample_rate; + if (!sample_rate_dac) + sample_rate_dac = sample_rate; + } + ret = set_sample_rate_control(codec, aic23->mclk, sample_rate_adc, + sample_rate_dac); + if (ret < 0) + return ret; iface_reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2); - - /* Search for the right sample rate */ - /* Verify what happens if the rate is not supported - * now it goes to 96Khz */ - while ((srate_reg_info[count].sample_rate != params_rate(params)) && - (count < ARRAY_SIZE(srate_reg_info))) { - count++; - } - - data = (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) | - (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) | - TLV320AIC23_USB_CLK_ON; - - tlv320aic23_write(codec, TLV320AIC23_SRATE, data); - switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; @@ -349,12 +477,17 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; + struct aic23 *aic23 = container_of(codec, struct aic23, codec); /* deactivate */ if (!codec->active) { udelay(50); tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + aic23->requested_dac = 0; + else + aic23->requested_adc = 0; } static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute) @@ -422,12 +555,9 @@ static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; - - switch (freq) { - case 12000000: - return 0; - } - return -EINVAL; + struct aic23 *aic23 = container_of(codec, struct aic23, codec); + aic23->mclk = freq; + return 0; } static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, @@ -659,14 +789,15 @@ static int tlv320aic23_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec; + struct aic23 *aic23; int ret = 0; printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) + aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL); + if (aic23 == NULL) return -ENOMEM; - + codec = &aic23->codec; socdev->codec = codec; mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); @@ -687,6 +818,7 @@ static int tlv320aic23_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; + struct aic23 *aic23 = container_of(codec, struct aic23, codec); if (codec->control_data) tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); @@ -697,7 +829,7 @@ static int tlv320aic23_remove(struct platform_device *pdev) i2c_del_driver(&tlv320aic23_i2c_driver); #endif kfree(codec->reg_cache); - kfree(codec); + kfree(aic23); return 0; } -- cgit v1.2.3 From 53599bbc30343f0cbfe750d2af19c9c45b841b82 Mon Sep 17 00:00:00 2001 From: Christian Pellegrin Date: Sat, 8 Nov 2008 08:44:16 +0100 Subject: ASoC: s3c24xx 8 bit sound fix fixes playing/recording of 8 bit audio files. Generated on 20081108 against v2.6.27 Signed-off-by: Christian Pellegrin Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx-i2s.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index ba4476b55fb..c18977bceaf 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -261,10 +261,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: + iismod &= ~S3C2410_IISMOD_16BIT; + ((struct s3c24xx_pcm_dma_params *) + rtd->dai->cpu_dai->dma_data)->dma_size = 1; break; case SNDRV_PCM_FORMAT_S16_LE: iismod |= S3C2410_IISMOD_16BIT; + ((struct s3c24xx_pcm_dma_params *) + rtd->dai->cpu_dai->dma_data)->dma_size = 2; break; + default: + return -EINVAL; } writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); -- cgit v1.2.3 From b402dff8739cd82c58b632ba472caf26ae8741ed Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Sat, 8 Nov 2008 13:26:09 -0500 Subject: ASoC: Add Right-Justified mode and Codec clock master to davinci-i2s The TI DVEVM board uses the SND_SOC_DAIFMT_CBM_CFM & I2S formats, but the Lyrtech SFFSDR board uses the SND_SOC_DAIFMT_CBM_CFS & RIGHT-JUSTIFIED formats. Signed-off-by: Hugo Villeneuve Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index abb5fedb0b1..d814ec8947e 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -59,6 +59,7 @@ #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) #define DAVINCI_MCBSP_PCR_FSRP (1 << 2) #define DAVINCI_MCBSP_PCR_FSXP (1 << 3) +#define DAVINCI_MCBSP_PCR_SCLKME (1 << 7) #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) @@ -171,6 +172,16 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, DAVINCI_MCBSP_SRGR_FSGM); break; + case SND_SOC_DAIFMT_CBM_CFS: + /* McBSP CLKR pin is the input for the Sample Rate Generator. + * McBSP FSR and FSX are driven by the Sample Rate Generator. */ + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, + DAVINCI_MCBSP_PCR_SCLKME | + DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, + DAVINCI_MCBSP_SRGR_FSGM); + break; case SND_SOC_DAIFMT_CBM_CFM: davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); break; @@ -205,6 +216,28 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, + DAVINCI_MCBSP_RCR_RFRLEN1(1) | + DAVINCI_MCBSP_RCR_RDATDLY(0)); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, + DAVINCI_MCBSP_XCR_XFRLEN1(1) | + DAVINCI_MCBSP_XCR_XDATDLY(0) | + DAVINCI_MCBSP_XCR_XFIG); + break; + case SND_SOC_DAIFMT_I2S: + default: + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, + DAVINCI_MCBSP_RCR_RFRLEN1(1) | + DAVINCI_MCBSP_RCR_RDATDLY(1)); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, + DAVINCI_MCBSP_XCR_XFRLEN1(1) | + DAVINCI_MCBSP_XCR_XDATDLY(1) | + DAVINCI_MCBSP_XCR_XFIG); + break; + } + return 0; } @@ -223,13 +256,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(1)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(1) | - DAVINCI_MCBSP_XCR_XFIG); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); -- cgit v1.2.3 From fb0ef645f2c546f8297b2fbf9b2b8fff4a7455e8 Mon Sep 17 00:00:00 2001 From: Naresh Medisetty Date: Wed, 12 Nov 2008 10:26:31 +0530 Subject: ASoC: DaVinci: Audio: Fix swapping of channels at start of stereo playback Fixes swapping of channels at start of stereo playback. Channel swap can be observed while playing left-only or right-only audio data. The channel swap is fixed by handling the XSYNCERR condition. Signed-off-by: Naresh Medisetty Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 49 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d814ec8947e..8c1bf876031 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -111,16 +111,59 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_platform *platform = socdev->platform; u32 w; + int ret; /* Start the sample generator and enable transmitter/receiver */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Stop the DMA to avoid data loss */ + /* while the transmitter is out of reset to handle XSYNCERR */ + if (platform->pcm_ops->trigger) { + ret = platform->pcm_ops->trigger(substream, + SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) + printk(KERN_DEBUG "Playback DMA stop failed\n"); + } + + /* Enable the transmitter */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - else + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + /* wait for any unexpected frame sync error to occur */ + udelay(100); + + /* Disable the transmitter to clear any outstanding XSYNCERR */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + /* Restart the DMA */ + if (platform->pcm_ops->trigger) { + ret = platform->pcm_ops->trigger(substream, + SNDRV_PCM_TRIGGER_START); + if (ret < 0) + printk(KERN_DEBUG "Playback DMA start failed\n"); + } + /* Enable the transmitter */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + } else { + + /* Enable the reciever */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } + /* Start frame sync */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); -- cgit v1.2.3 From bbba944410310181de14a5c60a7c161ff2447dd9 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 12 Nov 2008 17:05:41 +0200 Subject: ASoC: Fix supported sample rates of TWL4030 audio codec TWL4030 currently supports rates between 8 kHz and 48 kHz and sets the codec mode register accordingly in twl4030_hw_params. Expose this info so that ASoC can match other rates than 44.1 kHz or 48 kHz as well. Signed-off-by: Jarkko Nikula Acked-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 90f3b4decba..c1893d23703 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -504,7 +504,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -#define TWL4030_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) struct snd_soc_dai twl4030_dai = { -- cgit v1.2.3 From 0b6048561d5f505e3a027a519a6d0f488ba9a2bb Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 12 Nov 2008 17:05:51 +0200 Subject: ASoC: OMAP: Add more supported sample rates into McBSP DAI driver Originally it was put too tight limits to support only 44.1 kHz and 48 kHz sample rates in McBSP DAI driver. Extend it now to 8 kHz - 96 kHz. With 96 kHz and 2*16 bits, bit clock is 3.072 MHz < 3.125 MHz (I2S max?). Tested on Nokia N810 with TVL320AIC33 from rates 8 - 96 kHz and on Texas Instruments Beagle with TWL4030 from rates 8 - 48 kHz. Signed-off-by: Jarkko Nikula Acked-by: Steve Sakoman Acked-by: Arun KS Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 8485a8a9d0f..3d4060b00eb 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -36,9 +36,7 @@ #include "omap-mcbsp.h" #include "omap-pcm.h" -#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_KNOT) +#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) struct omap_mcbsp_data { unsigned int bus_id; -- cgit v1.2.3 From 2bef901071448e0c86af8edb4797cd5f81b6240d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 14 Nov 2008 14:40:46 +0000 Subject: ASoC: Revert "ASoC: Add new parameter to s3c24xx_pcm_enqueue" This reverts commit 8dc840f88d9c9f75f46d5dbe489242f8a114fab6. Christian Pellegrin reported that on some systems the patch caused DMA to fail which is much more serious than the original skipped audio issue. Further investigation by Dave shows that the behaviour depends on the clock speed of the SoC - a better fix is neeeded. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx-pcm.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 341198bb0c1..e13e614bada 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -78,8 +78,7 @@ struct s3c24xx_runtime_data { * place a dma buffer onto the queue for the dma system * to handle. */ -static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream, - int dma_max) +static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; @@ -87,10 +86,7 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream, DBG("Entered %s\n", __func__); - if (!dma_max) - dma_max = prtd->dma_limit; - - while (prtd->dma_loaded < dma_max) { + while (prtd->dma_loaded < prtd->dma_limit) { unsigned long len = prtd->dma_period; DBG("dma_loaded: %d\n", prtd->dma_loaded); @@ -136,7 +132,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING) { prtd->dma_loaded--; - s3c24xx_pcm_enqueue(substream, 0); + s3c24xx_pcm_enqueue(substream); } spin_unlock(&prtd->lock); @@ -253,7 +249,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ - s3c24xx_pcm_enqueue(substream, 1); + s3c24xx_pcm_enqueue(substream); return ret; } -- cgit v1.2.3 From 71cfc9028d762419ce4dea62b4afc9c32c4b4820 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Nov 2008 14:33:14 +0000 Subject: ASoC: Add WM8728 codec driver The WM8728 is a high performance stereo DAC designed for applications such as DVD, home theatre and digital TV. Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8728.c | 574 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8728.h | 30 +++ 4 files changed, 610 insertions(+) create mode 100644 sound/soc/codecs/wm8728.c create mode 100644 sound/soc/codecs/wm8728.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b73c36aad67..8a84460a6f7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -13,6 +13,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_UDA1380 if I2C select SND_SOC_WM8510 if (I2C || SPI_MASTER) select SND_SOC_WM8580 if I2C + select SND_SOC_WM8728 if (I2C || SPI_MASTER) select SND_SOC_WM8731 if (I2C || SPI_MASTER) select SND_SOC_WM8750 if (I2C || SPI_MASTER) select SND_SOC_WM8753 if (I2C || SPI_MASTER) @@ -93,6 +94,9 @@ config SND_SOC_WM8510 config SND_SOC_WM8580 tristate +config SND_SOC_WM8728 + tristate + config SND_SOC_WM8731 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3b9b58a0ea7..7ae17a6ea27 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -11,6 +11,7 @@ snd-soc-twl4030-objs := twl4030.o snd-soc-uda1380-objs := uda1380.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o +snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o +obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c new file mode 100644 index 00000000000..3e39dea6124 --- /dev/null +++ b/sound/soc/codecs/wm8728.c @@ -0,0 +1,574 @@ +/* + * wm8728.c -- WM8728 ALSA SoC Audio driver + * + * Copyright 2008 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 version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8728.h" + +struct snd_soc_codec_device soc_codec_dev_wm8728; + +/* + * We can't read the WM8728 register space so we cache them instead. + * Note that the defaults here aren't the physical defaults, we latch + * the volume update bits, mute the output and enable infinite zero + * detect. + */ +static const u16 wm8728_reg_defaults[] = { + 0x1ff, + 0x1ff, + 0x001, + 0x100, +}; + +static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); + return cache[reg]; +} + +static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); + cache[reg] = value; +} + +/* + * write to the WM8728 register space + */ +static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8728 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8728_write_reg_cache(codec, reg, value); + + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); + +static const struct snd_kcontrol_new wm8728_snd_controls[] = { + +SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL, + 0, 255, 0, wm8728_tlv), + +SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), +}; + +static int wm8728_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8728_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +/* + * DAPM controls. + */ +static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("VOUTL"), +SND_SOC_DAPM_OUTPUT("VOUTR"), +}; + +static const struct snd_soc_dapm_route intercon[] = { + {"VOUTL", NULL, "DAC"}, + {"VOUTR", NULL, "DAC"}, +}; + +static int wm8728_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets, + ARRAY_SIZE(wm8728_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + + return 0; +} + +static int wm8728_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + + if (mute) + wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); + else + wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); + + return 0; +} + +static int wm8728_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_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); + + dac &= ~0x18; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + dac |= 0x10; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dac |= 0x08; + break; + default: + return -EINVAL; + } + + wm8728_write(codec, WM8728_DACCTL, dac); + + return 0; +} + +static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL); + + /* Currently only I2S is supported by the driver, though the + * hardware is more flexible. + */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 1; + break; + default: + return -EINVAL; + } + + /* The hardware only support full slave mode */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + iface &= ~0x22; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x20; + iface &= ~0x02; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x02; + iface &= ~0x20; + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x22; + break; + default: + return -EINVAL; + } + + wm8728_write(codec, WM8728_IFCTL, iface); + return 0; +} + +static int wm8728_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u16 reg; + int i; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Power everything up... */ + reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); + + /* ..then sync in the register cache. */ + for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) + wm8728_write(codec, i, + wm8728_read_reg_cache(codec, i)); + } + break; + + case SND_SOC_BIAS_OFF: + reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + wm8728_write(codec, WM8728_DACCTL, reg | 0x4); + break; + } + codec->bias_level = level; + return 0; +} + +#define WM8728_RATES (SNDRV_PCM_RATE_8000_192000) + +#define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +struct snd_soc_dai wm8728_dai = { + .name = "WM8728", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8728_RATES, + .formats = WM8728_FORMATS, + }, + .ops = { + .hw_params = wm8728_hw_params, + }, + .dai_ops = { + .digital_mute = wm8728_mute, + .set_fmt = wm8728_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(wm8728_dai); + +static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm8728_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8728_set_bias_level(codec, codec->suspend_bias_level); + + return 0; +} + +/* + * initialise the WM8728 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8728_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int ret = 0; + + codec->name = "WM8728"; + codec->owner = THIS_MODULE; + codec->read = wm8728_read_reg_cache; + codec->write = wm8728_write; + codec->set_bias_level = wm8728_set_bias_level; + codec->dai = &wm8728_dai; + codec->num_dai = 1; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults); + codec->reg_cache = kmemdup(wm8728_reg_defaults, + sizeof(wm8728_reg_defaults), + GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "wm8728: failed to create pcms\n"); + goto pcm_err; + } + + /* power on device */ + wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + wm8728_add_controls(codec); + wm8728_add_widgets(codec); + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "wm8728: failed to register card\n"); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +static struct snd_soc_device *wm8728_socdev; + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + +/* + * WM8728 2 wire address is determined by GPIO5 + * state during powerup. + * low = 0x1a + * high = 0x1b + */ + +static int wm8728_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_device *socdev = wm8728_socdev; + struct snd_soc_codec *codec = socdev->codec; + int ret; + + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = wm8728_init(socdev); + if (ret < 0) + pr_err("failed to initialise WM8728\n"); + + return ret; +} + +static int wm8728_i2c_remove(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + kfree(codec->reg_cache); + return 0; +} + +static const struct i2c_device_id wm8728_i2c_id[] = { + { "wm8728", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); + +static struct i2c_driver wm8728_i2c_driver = { + .driver = { + .name = "WM8728 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = wm8728_i2c_probe, + .remove = wm8728_i2c_remove, + .id_table = wm8728_i2c_id, +}; + +static int wm8728_add_i2c_device(struct platform_device *pdev, + const struct wm8728_setup_data *setup) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + int ret; + + ret = i2c_add_driver(&wm8728_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = setup->i2c_address; + strlcpy(info.type, "wm8728", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(setup->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "can't get i2c adapter %d\n", + setup->i2c_bus); + goto err_driver; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + goto err_driver; + } + + return 0; + +err_driver: + i2c_del_driver(&wm8728_i2c_driver); + return -ENODEV; +} +#endif + +#if defined(CONFIG_SPI_MASTER) +static int __devinit wm8728_spi_probe(struct spi_device *spi) +{ + struct snd_soc_device *socdev = wm8728_socdev; + struct snd_soc_codec *codec = socdev->codec; + int ret; + + codec->control_data = spi; + + ret = wm8728_init(socdev); + if (ret < 0) + dev_err(&spi->dev, "failed to initialise WM8728\n"); + + return ret; +} + +static int __devexit wm8728_spi_remove(struct spi_device *spi) +{ + return 0; +} + +static struct spi_driver wm8728_spi_driver = { + .driver = { + .name = "wm8728", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm8728_spi_probe, + .remove = __devexit_p(wm8728_spi_remove), +}; + +static int wm8728_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} +#endif /* CONFIG_SPI_MASTER */ + +static int wm8728_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8728_setup_data *setup; + struct snd_soc_codec *codec; + int ret = 0; + + setup = socdev->codec_data; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + wm8728_socdev = socdev; + ret = -ENODEV; + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + if (setup->i2c_address) { + codec->hw_write = (hw_write_t)i2c_master_send; + ret = wm8728_add_i2c_device(pdev, setup); + } +#endif +#if defined(CONFIG_SPI_MASTER) + if (setup->spi) { + codec->hw_write = (hw_write_t)wm8728_spi_write; + ret = spi_register_driver(&wm8728_spi_driver); + if (ret != 0) + printk(KERN_ERR "can't add spi driver"); + } +#endif + + if (ret != 0) + kfree(codec); + + return ret; +} + +/* power down chip */ +static int wm8728_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + if (codec->control_data) + wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_unregister_device(codec->control_data); + i2c_del_driver(&wm8728_i2c_driver); +#endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&wm8728_spi_driver); +#endif + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8728 = { + .probe = wm8728_probe, + .remove = wm8728_remove, + .suspend = wm8728_suspend, + .resume = wm8728_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); + +MODULE_DESCRIPTION("ASoC WM8728 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8728.h b/sound/soc/codecs/wm8728.h new file mode 100644 index 00000000000..d269c132474 --- /dev/null +++ b/sound/soc/codecs/wm8728.h @@ -0,0 +1,30 @@ +/* + * wm8728.h -- WM8728 ASoC codec driver + * + * Copyright 2008 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 version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8728_H +#define _WM8728_H + +#define WM8728_DACLVOL 0x00 +#define WM8728_DACRVOL 0x01 +#define WM8728_DACCTL 0x02 +#define WM8728_IFCTL 0x03 + +struct wm8728_setup_data { + int spi; + int i2c_bus; + unsigned short i2c_address; +}; + +extern struct snd_soc_dai wm8728_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8728; + +#endif -- cgit v1.2.3 From 6e5d9db271ab57789b09bcc61083ab71b7eabea9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 14 Nov 2008 08:57:28 +0200 Subject: ASoC: Fix for master playback/capture volume range for TWL4030 codec FGAIN for playback is in range of 0-0x3f, while for capture GAIN it is in the range of 0-0x1f. The original value of 128 (0x7f) would modify the CGAIN also for playback. Signed-off-by: Peter Ujfalusi Acked-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c1893d23703..c778eb446a5 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -192,10 +192,10 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R("Master Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 0, 127, 0), + 0, 0x3f, 0), SOC_DOUBLE_R("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, - 0, 127, 0), + 0, 0x1f, 0), }; /* add non dapm controls */ -- cgit v1.2.3 From 1cad1de1b216b355a60d907c103b2daf1a285345 Mon Sep 17 00:00:00 2001 From: Christian Pellegrin Date: Sat, 15 Nov 2008 08:58:16 +0100 Subject: ASoC: UDA134x codec driver Signed-off-by: Christian Pellegrin Signed-off-by: Mark Brown --- include/sound/l3.h | 18 ++ include/sound/uda134x.h | 26 ++ sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 4 + sound/soc/codecs/l3.c | 91 ++++++ sound/soc/codecs/uda134x.c | 656 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/uda134x_codec.h | 36 +++ 7 files changed, 839 insertions(+) create mode 100644 include/sound/l3.h create mode 100644 include/sound/uda134x.h create mode 100644 sound/soc/codecs/l3.c create mode 100644 sound/soc/codecs/uda134x.c create mode 100644 sound/soc/codecs/uda134x_codec.h diff --git a/include/sound/l3.h b/include/sound/l3.h new file mode 100644 index 00000000000..423a08f0f1b --- /dev/null +++ b/include/sound/l3.h @@ -0,0 +1,18 @@ +#ifndef _L3_H_ +#define _L3_H_ 1 + +struct l3_pins { + void (*setdat)(int); + void (*setclk)(int); + void (*setmode)(int); + int data_hold; + int data_setup; + int clock_high; + int mode_hold; + int mode; + int mode_setup; +}; + +int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len); + +#endif diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h new file mode 100644 index 00000000000..475ef8bb7dc --- /dev/null +++ b/include/sound/uda134x.h @@ -0,0 +1,26 @@ +/* + * uda134x.h -- UDA134x ALSA SoC Codec driver + * + * Copyright 2007 Dension Audio Systems Ltd. + * Author: Zoltan Devai + * + * 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 _UDA134X_H +#define _UDA134X_H + +#include + +struct uda134x_platform_data { + struct l3_pins l3; + void (*power) (int); + int model; +#define UDA134X_UDA1340 1 +#define UDA134X_UDA1341 2 +#define UDA134X_UDA1344 3 +}; + +#endif /* _UDA134X_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8a84460a6f7..04f49f5c3c3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -10,6 +10,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC3X if I2C select SND_SOC_TWL4030 if TWL4030_CORE + select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C select SND_SOC_WM8510 if (I2C || SPI_MASTER) select SND_SOC_WM8580 if I2C @@ -66,6 +67,9 @@ config SND_SOC_CS4270_VD33_ERRATA bool depends on SND_SOC_CS4270 +config SND_SOC_L3 + tristate + config SND_SOC_SSM2602 tristate @@ -85,6 +89,10 @@ config SND_SOC_TWL4030 tristate depends on TWL4030_CORE +config SND_SOC_UDA134X + tristate + select SND_SOC_L3 + config SND_SOC_UDA1380 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7ae17a6ea27..de6572356d1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,11 +3,13 @@ snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o +snd-soc-l3-objs := l3.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-twl4030-objs := twl4030.o +snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o @@ -27,11 +29,13 @@ obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o +obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o +obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c new file mode 100644 index 00000000000..5353af58862 --- /dev/null +++ b/sound/soc/codecs/l3.c @@ -0,0 +1,91 @@ +/* + * L3 code + * + * Copyright (C) 2008, Christian Pellegrin + * + * 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. + * + * + * based on: + * + * L3 bus algorithm module. + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * + */ + +#include +#include +#include + +#include + +/* + * Send one byte of data to the chip. Data is latched into the chip on + * the rising edge of the clock. + */ +static void sendbyte(struct l3_pins *adap, unsigned int byte) +{ + int i; + + for (i = 0; i < 8; i++) { + adap->setclk(0); + udelay(adap->data_hold); + adap->setdat(byte & 1); + udelay(adap->data_setup); + adap->setclk(1); + udelay(adap->clock_high); + byte >>= 1; + } +} + +/* + * Send a set of bytes to the chip. We need to pulse the MODE line + * between each byte, but never at the start nor at the end of the + * transfer. + */ +static void sendbytes(struct l3_pins *adap, const u8 *buf, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (i) { + udelay(adap->mode_hold); + adap->setmode(0); + udelay(adap->mode); + } + adap->setmode(1); + udelay(adap->mode_setup); + sendbyte(adap, buf[i]); + } +} + +int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) +{ + adap->setclk(1); + adap->setdat(1); + adap->setmode(1); + udelay(adap->mode); + + adap->setmode(0); + udelay(adap->mode_setup); + sendbyte(adap, addr); + udelay(adap->mode_hold); + + sendbytes(adap, data, len); + + adap->setclk(1); + adap->setdat(1); + adap->setmode(0); + + return len; +} +EXPORT_SYMBOL_GPL(l3_write); + +MODULE_DESCRIPTION("L3 bit-banging driver"); +MODULE_AUTHOR("Christian Pellegrin "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c new file mode 100644 index 00000000000..04b30da1022 --- /dev/null +++ b/sound/soc/codecs/uda134x.c @@ -0,0 +1,656 @@ +/* + * uda134x.c -- UDA134X ALSA SoC Codec driver + * + * Modifications by Christian Pellegrin + * + * Copyright 2007 Dension Audio Systems Ltd. + * Author: Zoltan Devai + * + * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "uda134x_codec.h" + + +#define POWER_OFF_ON_STANDBY 1 +/* + ALSA SOC usually puts the device in standby mode when it's not used + for sometime. If you define POWER_OFF_ON_STANDBY the driver will + turn off the ADC/DAC when this callback is invoked and turn it back + on when needed. Unfortunately this will result in a very light bump + (it can be audible only with good earphones). If this bothers you + just comment this line, you will have slightly higher power + consumption . Please note that sending the L3 command for ADC is + enough to make the bump, so it doesn't make difference if you + completely take off power from the codec. + */ + +#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 +#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) + +struct uda134x_priv { + int sysclk; + int dai_fmt; + + struct snd_pcm_substream *master_substream; + struct snd_pcm_substream *slave_substream; +}; + +/* In-data addresses are hard-coded into the reg-cache values */ +static const char uda134x_reg[UDA134X_REGS_NUM] = { + /* Extended address registers */ + 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Status, data regs */ + 0x00, 0x83, 0x00, 0x40, 0x80, 0x00, +}; + +/* + * The codec has no support for reading its registers except for peak level... + */ +static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + + if (reg >= UDA134X_REGS_NUM) + return -1; + return cache[reg]; +} + +/* + * Write the register cache + */ +static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec, + u8 reg, unsigned int value) +{ + u8 *cache = codec->reg_cache; + + if (reg >= UDA134X_REGS_NUM) + return; + cache[reg] = value; +} + +/* + * Write to the uda134x registers + * + */ +static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + int ret; + u8 addr; + u8 data = value; + struct uda134x_platform_data *pd = codec->control_data; + + pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); + + if (reg >= UDA134X_REGS_NUM) { + printk(KERN_ERR "%s unkown register: reg: %d", + __func__, reg); + return -EINVAL; + } + + uda134x_write_reg_cache(codec, reg, value); + + switch (reg) { + case UDA134X_STATUS0: + case UDA134X_STATUS1: + addr = UDA134X_STATUS_ADDR; + break; + case UDA134X_DATA000: + case UDA134X_DATA001: + case UDA134X_DATA010: + addr = UDA134X_DATA0_ADDR; + break; + case UDA134X_DATA1: + addr = UDA134X_DATA1_ADDR; + break; + default: + /* It's an extended address register */ + addr = (reg | UDA134X_EXTADDR_PREFIX); + + ret = l3_write(&pd->l3, + UDA134X_DATA0_ADDR, &addr, 1); + if (ret != 1) + return -EIO; + + addr = UDA134X_DATA0_ADDR; + data = (value | UDA134X_EXTDATA_PREFIX); + break; + } + + ret = l3_write(&pd->l3, + addr, &data, 1); + if (ret != 1) + return -EIO; + + return 0; +} + +static inline void uda134x_reset(struct snd_soc_codec *codec) +{ + u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0); + uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6)); + msleep(1); + uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6)); +} + +static int uda134x_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010); + + pr_debug("%s mute: %d\n", __func__, mute); + + if (mute) + mute_reg |= (1<<2); + else + mute_reg &= ~(1<<2); + + uda134x_write(codec, UDA134X_DATA010, mute_reg & ~(1<<2)); + + return 0; +} + +static int uda134x_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct uda134x_priv *uda134x = codec->private_data; + struct snd_pcm_runtime *master_runtime; + + if (uda134x->master_substream) { + master_runtime = uda134x->master_substream->runtime; + + pr_debug("%s constraining to %d bits at %d\n", __func__, + master_runtime->sample_bits, + master_runtime->rate); + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + master_runtime->rate, + master_runtime->rate); + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + master_runtime->sample_bits, + master_runtime->sample_bits); + + uda134x->slave_substream = substream; + } else + uda134x->master_substream = substream; + + return 0; +} + +static void uda134x_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct uda134x_priv *uda134x = codec->private_data; + + if (uda134x->master_substream == substream) + uda134x->master_substream = uda134x->slave_substream; + + uda134x->slave_substream = NULL; +} + +static int uda134x_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_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct uda134x_priv *uda134x = codec->private_data; + u8 hw_params; + + if (substream == uda134x->slave_substream) { + pr_debug("%s ignoring hw_params for slave substream\n", + __func__); + return 0; + } + + hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0); + hw_params &= STATUS0_SYSCLK_MASK; + hw_params &= STATUS0_DAIFMT_MASK; + + pr_debug("%s sysclk: %d, rate:%d\n", __func__, + uda134x->sysclk, params_rate(params)); + + /* set SYSCLK / fs ratio */ + switch (uda134x->sysclk / params_rate(params)) { + case 512: + break; + case 384: + hw_params |= (1<<4); + break; + case 256: + hw_params |= (1<<5); + break; + default: + printk(KERN_ERR "%s unsupported fs\n", __func__); + return -EINVAL; + } + + pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__, + uda134x->dai_fmt, params_format(params)); + + /* set DAI format and word length */ + switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + hw_params |= (1<<1); + break; + case SNDRV_PCM_FORMAT_S18_3LE: + hw_params |= (1<<2); + break; + case SNDRV_PCM_FORMAT_S20_3LE: + hw_params |= ((1<<2) | (1<<1)); + break; + default: + printk(KERN_ERR "%s unsupported format (right)\n", + __func__); + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_LEFT_J: + hw_params |= (1<<3); + break; + default: + printk(KERN_ERR "%s unsupported format\n", __func__); + return -EINVAL; + } + + uda134x_write(codec, UDA134X_STATUS0, hw_params); + + return 0; +} + +static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct uda134x_priv *uda134x = codec->private_data; + + pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__, + clk_id, freq, dir); + + /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable + because the codec is slave. Of course limitations of the clock + master (the IIS controller) apply. + We'll error out on set_hw_params if it's not OK */ + if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { + uda134x->sysclk = freq; + return 0; + } + + printk(KERN_ERR "%s unsupported sysclk\n", __func__); + return -EINVAL; +} + +static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct uda134x_priv *uda134x = codec->private_data; + + pr_debug("%s fmt: %08X\n", __func__, fmt); + + /* codec supports only full slave mode */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + printk(KERN_ERR "%s unsupported slave mode\n", __func__); + return -EINVAL; + } + + /* no support for clock inversion */ + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { + printk(KERN_ERR "%s unsupported clock inversion\n", __func__); + return -EINVAL; + } + + /* We can't setup DAI format here as it depends on the word bit num */ + /* so let's just store the value for later */ + uda134x->dai_fmt = fmt; + + return 0; +} + +static int uda134x_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u8 reg; + struct uda134x_platform_data *pd = codec->control_data; + int i; + u8 *cache = codec->reg_cache; + + pr_debug("%s bias level %d\n", __func__, level); + + switch (level) { + case SND_SOC_BIAS_ON: + /* ADC, DAC on */ + reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); + uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); + break; + case SND_SOC_BIAS_PREPARE: + /* power on */ + if (pd->power) { + pd->power(1); + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++) + codec->write(codec, i, *cache++); + } + break; + case SND_SOC_BIAS_STANDBY: + /* ADC, DAC power off */ + reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); + uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); + break; + case SND_SOC_BIAS_OFF: + /* power off */ + if (pd->power) + pd->power(0); + break; + } + codec->bias_level = level; + return 0; +} + +static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1", + "Minimum2", "Maximum"}; +static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; +static const char *uda134x_mixmode[] = {"Differential", "Analog1", + "Analog2", "Both"}; + +static const struct soc_enum uda134x_mixer_enum[] = { +SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting), +SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph), +SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode), +}; + +static const struct snd_kcontrol_new uda1341_snd_controls[] = { +SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), +SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0), +SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1), +SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1), + +SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0), +SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0), + +SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), +SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), + +SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), +SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), +SOC_ENUM("Input Mux", uda134x_mixer_enum[2]), + +SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0), +SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1), +SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0), + +SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0), +SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0), +SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0), +SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0), +SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0), +SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), +}; + +static const struct snd_kcontrol_new uda1340_snd_controls[] = { +SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), + +SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), +SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), + +SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), +SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), + +SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), +}; + +static int uda134x_add_controls(struct snd_soc_codec *codec) +{ + int err, i, n; + const struct snd_kcontrol_new *ctrls; + struct uda134x_platform_data *pd = codec->control_data; + + switch (pd->model) { + case UDA134X_UDA1340: + case UDA134X_UDA1344: + n = ARRAY_SIZE(uda1340_snd_controls); + ctrls = uda1340_snd_controls; + break; + case UDA134X_UDA1341: + n = ARRAY_SIZE(uda1341_snd_controls); + ctrls = uda1341_snd_controls; + break; + default: + printk(KERN_ERR "%s unkown codec type: %d", + __func__, pd->model); + return -EINVAL; + } + + for (i = 0; i < n; i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&ctrls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +struct snd_soc_dai uda134x_dai = { + .name = "UDA134X", + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = UDA134X_RATES, + .formats = UDA134X_FORMATS, + }, + /* capture capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = UDA134X_RATES, + .formats = UDA134X_FORMATS, + }, + /* pcm operations */ + .ops = { + .startup = uda134x_startup, + .shutdown = uda134x_shutdown, + .hw_params = uda134x_hw_params, + }, + /* DAI operations */ + .dai_ops = { + .digital_mute = uda134x_mute, + .set_sysclk = uda134x_set_dai_sysclk, + .set_fmt = uda134x_set_dai_fmt, + } +}; +EXPORT_SYMBOL(uda134x_dai); + + +static int uda134x_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct uda134x_priv *uda134x; + void *codec_setup_data = socdev->codec_data; + int ret = -ENOMEM; + struct uda134x_platform_data *pd; + + printk(KERN_INFO "UDA134X SoC Audio Codec\n"); + + if (!codec_setup_data) { + printk(KERN_ERR "UDA134X SoC codec: " + "missing L3 bitbang function\n"); + return -ENODEV; + } + + pd = codec_setup_data; + switch (pd->model) { + case UDA134X_UDA1340: + case UDA134X_UDA1341: + case UDA134X_UDA1344: + break; + default: + printk(KERN_ERR "UDA134X SoC codec: " + "unsupported model %d\n", + pd->model); + return -EINVAL; + } + + socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (socdev->codec == NULL) + return ret; + + codec = socdev->codec; + + uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); + if (uda134x == NULL) + goto priv_err; + codec->private_data = uda134x; + + codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg), + GFP_KERNEL); + if (codec->reg_cache == NULL) + goto reg_err; + + mutex_init(&codec->mutex); + + codec->reg_cache_size = sizeof(uda134x_reg); + codec->reg_cache_step = 1; + + codec->name = "UDA134X"; + codec->owner = THIS_MODULE; + codec->dai = &uda134x_dai; + codec->num_dai = 1; + codec->read = uda134x_read_reg_cache; + codec->write = uda134x_write; +#ifdef POWER_OFF_ON_STANDBY + codec->set_bias_level = uda134x_set_bias_level; +#endif + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->control_data = codec_setup_data; + + if (pd->power) + pd->power(1); + + uda134x_reset(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "UDA134X: failed to register pcms\n"); + goto pcm_err; + } + + ret = uda134x_add_controls(codec); + if (ret < 0) { + printk(KERN_ERR "UDA134X: failed to register controls\n"); + goto pcm_err; + } + + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "UDA134X: failed to register card\n"); + goto card_err; + } + + return 0; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); +reg_err: + kfree(codec->private_data); +priv_err: + kfree(codec); + return ret; +} + +/* power down chip */ +static int uda134x_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + kfree(codec->private_data); + kfree(codec->reg_cache); + kfree(codec); + + return 0; +} + +#if defined(CONFIG_PM) +static int uda134x_soc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int uda134x_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); + uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); + return 0; +} +#else +#define uda134x_soc_suspend NULL +#define uda134x_soc_resume NULL +#endif /* CONFIG_PM */ + +struct snd_soc_codec_device soc_codec_dev_uda134x = { + .probe = uda134x_soc_probe, + .remove = uda134x_soc_remove, + .suspend = uda134x_soc_suspend, + .resume = uda134x_soc_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); + +MODULE_DESCRIPTION("UDA134X ALSA soc codec driver"); +MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x_codec.h b/sound/soc/codecs/uda134x_codec.h new file mode 100644 index 00000000000..94f440490b3 --- /dev/null +++ b/sound/soc/codecs/uda134x_codec.h @@ -0,0 +1,36 @@ +#ifndef _UDA134X_CODEC_H +#define _UDA134X_CODEC_H + +#define UDA134X_L3ADDR 5 +#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0) +#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1) +#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2) + +#define UDA134X_EXTADDR_PREFIX 0xC0 +#define UDA134X_EXTDATA_PREFIX 0xE0 + +/* UDA134X registers */ +#define UDA134X_EA000 0 +#define UDA134X_EA001 1 +#define UDA134X_EA010 2 +#define UDA134X_EA011 3 +#define UDA134X_EA100 4 +#define UDA134X_EA101 5 +#define UDA134X_EA110 6 +#define UDA134X_EA111 7 +#define UDA134X_STATUS0 8 +#define UDA134X_STATUS1 9 +#define UDA134X_DATA000 10 +#define UDA134X_DATA001 11 +#define UDA134X_DATA010 12 +#define UDA134X_DATA1 13 + +#define UDA134X_REGS_NUM 14 + +#define STATUS0_DAIFMT_MASK (~(7<<1)) +#define STATUS0_SYSCLK_MASK (~(3<<4)) + +extern struct snd_soc_dai uda134x_dai; +extern struct snd_soc_codec_device soc_codec_dev_uda134x; + +#endif -- cgit v1.2.3 From 7ad933d7a6677c20ce1bdb17425e732cf1ebee8a Mon Sep 17 00:00:00 2001 From: Christian Pellegrin Date: Sat, 15 Nov 2008 08:58:32 +0100 Subject: ASoC: Machine driver for for s3c24xx with uda134x Signed-off-by: Christian Pellegrin Signed-off-by: Mark Brown --- include/sound/s3c24xx_uda134x.h | 14 ++ sound/soc/s3c24xx/Kconfig | 5 + sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/s3c24xx_uda134x.c | 374 ++++++++++++++++++++++++++++++++++++ 4 files changed, 395 insertions(+) create mode 100644 include/sound/s3c24xx_uda134x.h create mode 100644 sound/soc/s3c24xx/s3c24xx_uda134x.c diff --git a/include/sound/s3c24xx_uda134x.h b/include/sound/s3c24xx_uda134x.h new file mode 100644 index 00000000000..33df4cb909d --- /dev/null +++ b/include/sound/s3c24xx_uda134x.h @@ -0,0 +1,14 @@ +#ifndef _S3C24XX_UDA134X_H_ +#define _S3C24XX_UDA134X_H_ 1 + +#include + +struct s3c24xx_uda134x_platform_data { + int l3_clk; + int l3_mode; + int l3_data; + void (*power) (int); + int model; +}; + +#endif diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index b9f2353effe..fcd03acf10f 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -44,3 +44,8 @@ config SND_S3C24XX_SOC_LN2440SBC_ALC650 Say Y if you want to add support for SoC audio on ln2440sbc with the ALC650. +config SND_S3C24XX_SOC_S3C24XX_UDA134X + tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" + depends on SND_S3C24XX_SOC + select SND_S3C24XX_SOC_I2S + select SND_SOC_UDA134X diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 0aa5fb0b970..96b3f3f617d 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -13,7 +13,9 @@ obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o +snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o +obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c new file mode 100644 index 00000000000..29a68132f16 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -0,0 +1,374 @@ +/* + * Modifications by Christian Pellegrin + * + * s3c24xx_uda134x.c -- S3C24XX_UDA134X ALSA SoC Audio board driver + * + * Copyright 2007 Dension Audio Systems Ltd. + * Author: Zoltan Devai + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "s3c24xx-pcm.h" +#include "s3c24xx-i2s.h" +#include "../codecs/uda134x_codec.h" + + +/* #define ENFORCE_RATES 1 */ +/* + Unfortunately the S3C24XX in master mode has a limited capacity of + generating the clock for the codec. If you define this only rates + that are really available will be enforced. But be careful, most + user level application just want the usual sampling frequencies (8, + 11.025, 22.050, 44.1 kHz) and anyway resampling is a costly + operation for embedded systems. So if you aren't very lucky or your + hardware engineer wasn't very forward-looking it's better to leave + this undefined. If you do so an approximate value for the requested + sampling rate in the range -/+ 5% will be chosen. If this in not + possible an error will be returned. +*/ + +static struct clk *xtal; +static struct clk *pclk; +/* this is need because we don't have a place where to keep the + * pointers to the clocks in each substream. We get the clocks only + * when we are actually using them so we don't block stuff like + * frequency change or oscillator power-off */ +static int clk_users; +static DEFINE_MUTEX(clk_lock); + +static unsigned int rates[33 * 2]; +#ifdef ENFORCE_RATES +static struct snd_pcm_hw_constraint_list hw_constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; +#endif + +static struct platform_device *s3c24xx_uda134x_snd_device; + +int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; +#ifdef ENFORCE_RATES + struct snd_pcm_runtime *runtime = substream->runtime;; +#endif + + mutex_lock(&clk_lock); + pr_debug("%s %d\n", __func__, clk_users); + if (clk_users == 0) { + xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal"); + if (!xtal) { + printk(KERN_ERR "%s cannot get xtal\n", __func__); + ret = -EBUSY; + } else { + pclk = clk_get(&s3c24xx_uda134x_snd_device->dev, + "pclk"); + if (!pclk) { + printk(KERN_ERR "%s cannot get pclk\n", + __func__); + clk_put(xtal); + ret = -EBUSY; + } + } + if (!ret) { + int i, j; + + for (i = 0; i < 2; i++) { + int fs = i ? 256 : 384; + + rates[i*33] = clk_get_rate(xtal) / fs; + for (j = 1; j < 33; j++) + rates[i*33 + j] = clk_get_rate(pclk) / + (j * fs); + } + } + } + clk_users += 1; + mutex_unlock(&clk_lock); + if (!ret) { +#ifdef ENFORCE_RATES + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &hw_constraints_rates); + if (ret < 0) + printk(KERN_ERR "%s cannot set constraints\n", + __func__); +#endif + } + return ret; +} + +void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) +{ + mutex_lock(&clk_lock); + pr_debug("%s %d\n", __func__, clk_users); + clk_users -= 1; + if (clk_users == 0) { + clk_put(xtal); + xtal = NULL; + clk_put(pclk); + pclk = NULL; + } + mutex_unlock(&clk_lock); +} + +static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int clk = 0; + int ret = 0; + int clk_source, fs_mode; + unsigned long rate = params_rate(params); + long err, cerr; + unsigned int div; + int i, bi; + + err = 999999; + bi = 0; + for (i = 0; i < 2*33; i++) { + cerr = rates[i] - rate; + if (cerr < 0) + cerr = -cerr; + if (cerr < err) { + err = cerr; + bi = i; + } + } + if (bi / 33 == 1) + fs_mode = S3C2410_IISMOD_256FS; + else + fs_mode = S3C2410_IISMOD_384FS; + if (bi % 33 == 0) { + clk_source = S3C24XX_CLKSRC_MPLL; + div = 1; + } else { + clk_source = S3C24XX_CLKSRC_PCLK; + div = bi % 33; + } + pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi); + + clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate; + pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__, + fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS", + clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK", + div, clk, err); + + if ((err * 100 / rate) > 5) { + printk(KERN_ERR "S3C24XX_UDA134X: effective frequency " + "too different from desired (%ld%%)\n", + err * 100 / rate); + return -EINVAL; + } + + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, clk_source , clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, + fs_mode); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, + S3C2410_IISMOD_32FS); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, + S3C24XX_PRESCALE(div, div)); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, clk, + SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops s3c24xx_uda134x_ops = { + .startup = s3c24xx_uda134x_startup, + .shutdown = s3c24xx_uda134x_shutdown, + .hw_params = s3c24xx_uda134x_hw_params, +}; + +static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { + .name = "UDA134X", + .stream_name = "UDA134X", + .codec_dai = &uda134x_dai, + .cpu_dai = &s3c24xx_i2s_dai, + .ops = &s3c24xx_uda134x_ops, +}; + +static struct snd_soc_machine snd_soc_machine_s3c24xx_uda134x = { + .name = "S3C24XX_UDA134X", + .dai_link = &s3c24xx_uda134x_dai_link, + .num_links = 1, +}; + +static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins; + +static void setdat(int v) +{ + gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0); +} + +static void setclk(int v) +{ + gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0); +} + +static void setmode(int v) +{ + gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0); +} + +static struct uda134x_platform_data s3c24xx_uda134x = { + .l3 = { + .setdat = setdat, + .setclk = setclk, + .setmode = setmode, + .data_hold = 1, + .data_setup = 1, + .clock_high = 1, + .mode_hold = 1, + .mode = 1, + .mode_setup = 1, + }, +}; + +static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { + .machine = &snd_soc_machine_s3c24xx_uda134x, + .platform = &s3c24xx_soc_platform, + .codec_dev = &soc_codec_dev_uda134x, + .codec_data = &s3c24xx_uda134x, +}; + +static int s3c24xx_uda134x_setup_pin(int pin, char *fun) +{ + if (gpio_request(pin, "s3c24xx_uda134x") < 0) { + printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " + "l3 %s pin already in use", fun); + return -EBUSY; + } + gpio_direction_output(pin, 0); + return 0; +} + +static int s3c24xx_uda134x_probe(struct platform_device *pdev) +{ + int ret; + + printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n"); + + s3c24xx_uda134x_l3_pins = pdev->dev.platform_data; + if (s3c24xx_uda134x_l3_pins == NULL) { + printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " + "unable to find platform data\n"); + return -ENODEV; + } + s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power; + s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model; + + if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data, + "data") < 0) + return -EBUSY; + if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk, + "clk") < 0) { + gpio_free(s3c24xx_uda134x_l3_pins->l3_data); + return -EBUSY; + } + if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, + "mode") < 0) { + gpio_free(s3c24xx_uda134x_l3_pins->l3_data); + gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); + return -EBUSY; + } + + s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1); + if (!s3c24xx_uda134x_snd_device) { + printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " + "Unable to register\n"); + return -ENOMEM; + } + + platform_set_drvdata(s3c24xx_uda134x_snd_device, + &s3c24xx_uda134x_snd_devdata); + s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev; + ret = platform_device_add(s3c24xx_uda134x_snd_device); + if (ret) { + printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n"); + platform_device_put(s3c24xx_uda134x_snd_device); + } + + return ret; +} + +static int s3c24xx_uda134x_remove(struct platform_device *pdev) +{ + platform_device_unregister(s3c24xx_uda134x_snd_device); + gpio_free(s3c24xx_uda134x_l3_pins->l3_data); + gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); + gpio_free(s3c24xx_uda134x_l3_pins->l3_mode); + return 0; +} + +static struct platform_driver s3c24xx_uda134x_driver = { + .probe = s3c24xx_uda134x_probe, + .remove = s3c24xx_uda134x_remove, + .driver = { + .name = "s3c24xx_uda134x", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c24xx_uda134x_init(void) +{ + return platform_driver_register(&s3c24xx_uda134x_driver); +} + +static void __exit s3c24xx_uda134x_exit(void) +{ + platform_driver_unregister(&s3c24xx_uda134x_driver); +} + + +module_init(s3c24xx_uda134x_init); +module_exit(s3c24xx_uda134x_exit); + +MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); +MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ba533e95b929c577d69237692ee588001347be8a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Nov 2008 16:59:24 +0000 Subject: ASoC: Allow writes to uncached registers in WM8990 Only fully documented registers are cached in the WM8990 but additional registers exist. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8990.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 572d22b0880..5c84f02c457 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -106,6 +106,7 @@ static const u16 wm8990_reg[] = { 0x0008, /* R60 - PLL1 */ 0x0031, /* R61 - PLL2 */ 0x0026, /* R62 - PLL3 */ + 0x0000, /* R63 - Driver internal */ }; /* @@ -126,10 +127,9 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u16 *cache = codec->reg_cache; - BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); - /* Reset register is uncached */ - if (reg == 0) + /* Reset register and reserved registers are uncached */ + if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1) return; cache[reg] = value; -- cgit v1.2.3 From be1b87c70af69acfadb8a27a7a76dfb61de92643 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Nov 2008 17:09:34 +0000 Subject: ASoC: Enable WM8990 ADC clocking workaround Enable a hardware workaround which avoids problems with the clocking of the ADCs in certain configurations. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8990.c | 6 ++++-- sound/soc/codecs/wm8990.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 5c84f02c457..938e1542920 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1272,9 +1272,11 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); - } else { - /* ON -> standby */ + /* Enable workaround for ADC clocking issue. */ + wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); + wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); + wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); } break; diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h index 0e192f3b078..7114ddc88b4 100644 --- a/sound/soc/codecs/wm8990.h +++ b/sound/soc/codecs/wm8990.h @@ -80,8 +80,8 @@ #define WM8990_PLL3 0x3E #define WM8990_INTDRIVBITS 0x3F -#define WM8990_REGISTER_COUNT 60 -#define WM8990_MAX_REGISTER 0x3F +#define WM8990_EXT_ACCESS_ENA 0x75 +#define WM8990_EXT_CTL1 0x7a /* * Field Definitions. -- cgit v1.2.3 From 2adb9833d1782262c20b21457d645163928cf2a2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Nov 2008 17:11:14 +0000 Subject: ASoC: Manage VMID mode for WM8990 A small additional power saving can be achieved for the WM8990 by maintaining VMID using a 2*250k divider when in standby mode. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8990.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 938e1542920..2d7b0096d92 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1222,8 +1222,14 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: break; + case SND_SOC_BIAS_PREPARE: + /* VMID=2*50k */ + val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & + ~WM8990_VMID_MODE_MASK; + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); break; + case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Enable all output discharge bits */ @@ -1278,6 +1284,11 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); } + + /* VMID=2*250k */ + val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & + ~WM8990_VMID_MODE_MASK; + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); break; case SND_SOC_BIAS_OFF: -- cgit v1.2.3 From 8d702f2376d25ab277c38b57015f4aa990bc7f16 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Nov 2008 21:42:01 +0000 Subject: ASoC: Build tlv320aic23 cleanly Also merge down a couple of last minute style changes that got lost in the shuffle. Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index a95b538b8fe..c903e4f48dc 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -331,10 +331,11 @@ static int find_rate(int mclk, u32 need_adc, u32 need_dac) adc_h = need_adc + (need_adc >> 5); dac_l = need_dac - (need_dac >> 5); dac_h = need_dac + (need_dac >> 5); - for (i = 0; i < 4; i++) { + for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) { int base = mclk / bosr_usb_divisor_table[i]; int mask = sr_valid_mask[i]; - for (j = 0; j < 16; j++, mask >>= 1) { + for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table); + j++, mask >>= 1) { int adc; int dac; int score; @@ -364,6 +365,7 @@ static int find_rate(int mclk, u32 need_adc, u32 need_dac) return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT); } +#ifdef DEBUG static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, u32 *sample_rate_adc, u32 *sample_rate_dac) { @@ -379,6 +381,7 @@ static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, *sample_rate_adc = adc; *sample_rate_dac = dac; } +#endif static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, u32 sample_rate_adc, u32 sample_rate_dac) @@ -391,12 +394,14 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, return -EINVAL; } tlv320aic23_write(codec, TLV320AIC23_SRATE, data); - if (1) { - int adc, dac; +#ifdef DEBUG + { + u32 adc, dac; get_current_sample_rates(codec, mclk, &adc, &dac); printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n", adc, dac, data); } +#endif return 0; } -- cgit v1.2.3 From cb6e2063697e91ca6983f9fe6958d20469b43641 Mon Sep 17 00:00:00 2001 From: Naresh Medisetty Date: Tue, 18 Nov 2008 11:01:03 +0530 Subject: ASoC: DaVinci: Fix audio stall when doing full duplex Fix concurrent capture/playback issue. The issue is caused by re-initialization of control registers used specifically for capture or playback in both capture and playback operations. Signed-off-by: Steve Chen Signed-off-by: Naresh Medisetty Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 8c1bf876031..11c20d0b7bc 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -295,10 +295,14 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, u32 w; /* general line settings */ - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, - DAVINCI_MCBSP_SPCR_RINTM(3) | - DAVINCI_MCBSP_SPCR_XINTM(3) | - DAVINCI_MCBSP_SPCR_FREE); + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } else { + w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); @@ -329,16 +333,19 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + } else { + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + } return 0; } -- cgit v1.2.3 From a11311d71d59145d920c19c0a4eed3fa7e26d222 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 18 Nov 2008 16:18:15 +0800 Subject: ASoC: Blackfin: updates Kconfig for SPORT tweak SPORT range for non-BF54x so we get proper behavior for BF52x parts Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index dc006206f62..3fce18788b7 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -80,7 +80,7 @@ config SND_BF5XX_SPORT_NUM int "Set a SPORT for Sound chip" depends on (SND_BF5XX_I2S || SND_BF5XX_AC97) range 0 3 if BF54x - range 0 1 if (BF53x || BF561) + range 0 1 if !BF54x default 0 help Set the correct SPORT for sound chip. -- cgit v1.2.3 From 9905ed35fdec0ebb3be8a724021ff3b104571667 Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Tue, 18 Nov 2008 16:18:16 +0800 Subject: ASoC: AD1980 codec: add multi-channel function support We added multi-channel function to this codec driver and Blackfin ASoC driver as well. It was tested on Blackfin hardware. Signed-off-by: Cliff Cai Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 1397b8e06c0..410fed953c5 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -85,6 +85,9 @@ SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), +SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1), +SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1), + SOC_ENUM("Capture Source", ad1980_cap_src), SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), @@ -145,7 +148,7 @@ struct snd_soc_dai ad1980_dai = { .playback = { .stream_name = "Playback", .channels_min = 2, - .channels_max = 2, + .channels_max = 6, .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { @@ -192,6 +195,7 @@ static int ad1980_soc_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0; u16 vendor_id2; + u16 ext_status; printk(KERN_INFO "AD1980 SoC Audio Codec\n"); @@ -253,9 +257,16 @@ static int ad1980_soc_probe(struct platform_device *pdev) "supported\n"); } - ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */ - ac97_write(codec, AC97_PCM, 0x0000); /* unmute PCM out volume */ - ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */ + /* unmute captures and playbacks volume */ + ac97_write(codec, AC97_MASTER, 0x0000); + ac97_write(codec, AC97_PCM, 0x0000); + ac97_write(codec, AC97_REC_GAIN, 0x0000); + ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); + ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); + + /*power on LFE/CENTER/Surround DACs*/ + ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); + ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); ad1980_add_controls(codec); ret = snd_soc_register_card(socdev); -- cgit v1.2.3 From 67f854b910613eeffec4fe71e35c0cd8c32c82ec Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Tue, 18 Nov 2008 16:18:17 +0800 Subject: ASoC: Blackfin: add multi-channel function support This patch provides a option for users to enable multi-channel function support in Blackfin ASoC driver. Because Blackfin is without MMU, it is easy for us and the user to enable this function at compiling stage not dynamically on the fly. Signed-off-by: Cliff Cai Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 14 +++- sound/soc/blackfin/bf5xx-ac97-pcm.c | 80 +++++++++++------- sound/soc/blackfin/bf5xx-ac97.c | 156 +++++++++++++++++++++--------------- sound/soc/blackfin/bf5xx-ac97.h | 35 ++++++-- sound/soc/blackfin/bf5xx-sport.h | 2 +- 5 files changed, 184 insertions(+), 103 deletions(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 3fce18788b7..43d89fc253a 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -47,7 +47,7 @@ config SND_BF5XX_AC97 properly with this driver. This driver is known to work with the Analog Devices line of AC97 codecs. -config SND_MMAP_SUPPORT +config SND_BF5XX_MMAP_SUPPORT bool "Enable MMAP Support" depends on SND_BF5XX_AC97 default y @@ -55,9 +55,17 @@ config SND_MMAP_SUPPORT Say y if you want AC97 driver to support mmap mode. We introduce an intermediate buffer to simulate mmap. +config SND_BF5XX_MULTICHAN_SUPPORT + bool "Enable Multichannel Support" + depends on SND_BF5XX_AC97 + default n + help + Say y if you want AC97 driver to support up to 5.1 channel audio. + this mode will consume much more memory for DMA. + config SND_BF5XX_SOC_SPORT tristate - + config SND_BF5XX_SOC_I2S tristate select SND_BF5XX_SOC_SPORT @@ -90,7 +98,7 @@ config SND_BF5XX_HAVE_COLD_RESET depends on SND_BF5XX_AC97 default y if BFIN548_EZKIT default n if !BFIN548_EZKIT - + config SND_BF5XX_RESET_GPIO_NUM int "Set a GPIO for cold reset" depends on SND_BF5XX_HAVE_COLD_RESET diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 25e50d2ea1e..4be1a490f4f 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -43,24 +43,34 @@ #include "bf5xx-ac97.h" #include "bf5xx-sport.h" -#if defined(CONFIG_SND_MMAP_SUPPORT) +static unsigned int ac97_chan_mask[] = { + SP_FL, /* Mono */ + SP_STEREO, /* Stereo */ + SP_2DOT1, /* 2.1*/ + SP_QUAD,/*Quadraquic*/ + SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */ + SP_5DOT1, /* 5.1 */ +}; + +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, snd_pcm_uframes_t count) { struct snd_pcm_runtime *runtime = substream->runtime; struct sport_device *sport = runtime->private_data; + unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - bf5xx_pcm_to_ac97( - (struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos, - (__u32 *)runtime->dma_area + sport->tx_pos, count); + bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf + + sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos * + runtime->channels, count, chan_mask); sport->tx_pos += runtime->period_size; if (sport->tx_pos >= runtime->buffer_size) sport->tx_pos %= runtime->buffer_size; sport->tx_delay_pos = sport->tx_pos; } else { - bf5xx_ac97_to_pcm( - (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, - (__u32 *)runtime->dma_area + sport->rx_pos, count); + bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf + + sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos * + runtime->channels, count); sport->rx_pos += runtime->period_size; if (sport->rx_pos >= runtime->buffer_size) sport->rx_pos %= runtime->buffer_size; @@ -71,7 +81,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, static void bf5xx_dma_irq(void *data) { struct snd_pcm_substream *pcm = data; -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = pcm->runtime; struct sport_device *sport = runtime->private_data; bf5xx_mmap_copy(pcm, runtime->period_size); @@ -90,7 +100,7 @@ static void bf5xx_dma_irq(void *data) * The total rx/tx buffer is for ac97 frame to hold all pcm data * is 0x20000 * sizeof(struct ac97_frame) / 4. */ -#ifdef CONFIG_SND_MMAP_SUPPORT +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static const struct snd_pcm_hardware bf5xx_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | @@ -123,10 +133,20 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) { +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - memset(runtime->dma_area, 0, runtime->buffer_size); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sport->once = 0; + if (runtime->dma_area) + memset(runtime->dma_area, 0, runtime->buffer_size); + memset(sport->tx_dma_buf, 0, runtime->buffer_size * + sizeof(struct ac97_frame)); + } else + memset(sport->rx_dma_buf, 0, runtime->buffer_size * + sizeof(struct ac97_frame)); +#endif snd_pcm_lib_free_pages(substream); return 0; } @@ -139,7 +159,7 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) /* An intermediate buffer is introduced for implementing mmap for * SPORT working in TMD mode(include AC97). */ -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { sport_set_tx_callback(sport, bf5xx_dma_irq, substream); sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, @@ -174,23 +194,21 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { bf5xx_mmap_copy(substream, runtime->period_size); - snd_pcm_period_elapsed(substream); sport->tx_delay_pos = 0; sport_tx_start(sport); - } - else + } else sport_rx_start(sport); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) sport->tx_pos = 0; #endif sport_tx_stop(sport); } else { -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) sport->rx_pos = 0; #endif sport_rx_stop(sport); @@ -208,7 +226,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) struct sport_device *sport = runtime->private_data; unsigned int curr; -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) curr = sport->tx_delay_pos; else @@ -257,14 +275,16 @@ static int bf5xx_pcm_close(struct snd_pcm_substream *substream) pr_debug("%s enter\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { sport->once = 0; - memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + memset(sport->tx_dma_buf, 0, runtime->buffer_size * + sizeof(struct ac97_frame)); } else - memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + memset(sport->rx_dma_buf, 0, runtime->buffer_size * + sizeof(struct ac97_frame)); return 0; } -#ifdef CONFIG_SND_MMAP_SUPPORT +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -286,13 +306,11 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, substream->stream ? "Capture" : "Playback", pos, count); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - bf5xx_pcm_to_ac97( - (struct ac97_frame *)runtime->dma_area + pos, - buf, count); + bf5xx_pcm_to_ac97((struct ac97_frame *)runtime->dma_area + pos, + (__u16 *)buf, count, chan_mask); else - bf5xx_ac97_to_pcm( - (struct ac97_frame *)runtime->dma_area + pos, - buf, count); + bf5xx_ac97_to_pcm((struct ac97_frame *)runtime->dma_area + pos, + (__u16 *)buf, count); return 0; } #endif @@ -306,7 +324,7 @@ struct snd_pcm_ops bf5xx_pcm_ac97_ops = { .prepare = bf5xx_pcm_prepare, .trigger = bf5xx_pcm_trigger, .pointer = bf5xx_pcm_pointer, -#ifdef CONFIG_SND_MMAP_SUPPORT +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) .mmap = bf5xx_pcm_mmap, #else .copy = bf5xx_pcm_copy, @@ -344,7 +362,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) * Need to allocate local buffer when enable * MMAP for SPORT working in TMD mode (include AC97). */ -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (!sport_handle->tx_dma_buf) { sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ @@ -381,7 +399,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; int stream; -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) size_t size = bf5xx_pcm_hardware.buffer_bytes_max * sizeof(struct ac97_frame) / 4; #endif @@ -395,7 +413,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) continue; dma_free_coherent(NULL, buf->bytes, buf->area, 0); buf->area = NULL; -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (sport_handle->tx_dma_buf) dma_free_coherent(NULL, size, \ diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 5e5aafb6485..65c162c4bfa 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -54,71 +54,103 @@ static int *cmd_count; static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; -#if defined(CONFIG_BF54x) +static u16 sport_req[][7] = { + PIN_REQ_SPORT_0, +#ifdef PIN_REQ_SPORT_1 + PIN_REQ_SPORT_1, +#endif +#ifdef PIN_REQ_SPORT_2 + PIN_REQ_SPORT_2, +#endif +#ifdef PIN_REQ_SPORT_3 + PIN_REQ_SPORT_3, +#endif + }; + static struct sport_param sport_params[4] = { { .dma_rx_chan = CH_SPORT0_RX, .dma_tx_chan = CH_SPORT0_TX, - .err_irq = IRQ_SPORT0_ERR, + .err_irq = IRQ_SPORT0_ERROR, .regs = (struct sport_register *)SPORT0_TCR1, }, +#ifdef PIN_REQ_SPORT_1 { .dma_rx_chan = CH_SPORT1_RX, .dma_tx_chan = CH_SPORT1_TX, - .err_irq = IRQ_SPORT1_ERR, + .err_irq = IRQ_SPORT1_ERROR, .regs = (struct sport_register *)SPORT1_TCR1, }, +#endif +#ifdef PIN_REQ_SPORT_2 { .dma_rx_chan = CH_SPORT2_RX, .dma_tx_chan = CH_SPORT2_TX, - .err_irq = IRQ_SPORT2_ERR, + .err_irq = IRQ_SPORT2_ERROR, .regs = (struct sport_register *)SPORT2_TCR1, }, +#endif +#ifdef PIN_REQ_SPORT_3 { .dma_rx_chan = CH_SPORT3_RX, .dma_tx_chan = CH_SPORT3_TX, - .err_irq = IRQ_SPORT3_ERR, + .err_irq = IRQ_SPORT3_ERROR, .regs = (struct sport_register *)SPORT3_TCR1, } -}; -#else -static struct sport_param sport_params[2] = { - { - .dma_rx_chan = CH_SPORT0_RX, - .dma_tx_chan = CH_SPORT0_TX, - .err_irq = IRQ_SPORT0_ERROR, - .regs = (struct sport_register *)SPORT0_TCR1, - }, - { - .dma_rx_chan = CH_SPORT1_RX, - .dma_tx_chan = CH_SPORT1_TX, - .err_irq = IRQ_SPORT1_ERROR, - .regs = (struct sport_register *)SPORT1_TCR1, - } -}; #endif +}; -void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ - size_t count) +void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, + size_t count, unsigned int chan_mask) { while (count--) { - dst->ac97_tag = TAG_VALID | TAG_PCM; - (dst++)->ac97_pcm = *src++; + dst->ac97_tag = TAG_VALID; + if (chan_mask & SP_FL) { + dst->ac97_pcm_r = *src++; + dst->ac97_tag |= TAG_PCM_RIGHT; + } + if (chan_mask & SP_FR) { + dst->ac97_pcm_l = *src++; + dst->ac97_tag |= TAG_PCM_LEFT; + + } +#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) + if (chan_mask & SP_SR) { + dst->ac97_sl = *src++; + dst->ac97_tag |= TAG_PCM_SL; + } + if (chan_mask & SP_SL) { + dst->ac97_sr = *src++; + dst->ac97_tag |= TAG_PCM_SR; + } + if (chan_mask & SP_LFE) { + dst->ac97_lfe = *src++; + dst->ac97_tag |= TAG_PCM_LFE; + } + if (chan_mask & SP_FC) { + dst->ac97_center = *src++; + dst->ac97_tag |= TAG_PCM_CENTER; + } +#endif + dst++; } } EXPORT_SYMBOL(bf5xx_pcm_to_ac97); -void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ +void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, size_t count) { - while (count--) - *(dst++) = (src++)->ac97_pcm; + while (count--) { + *(dst++) = src->ac97_pcm_l; + *(dst++) = src->ac97_pcm_r; + src++; + } } EXPORT_SYMBOL(bf5xx_ac97_to_pcm); static unsigned int sport_tx_curr_frag(struct sport_device *sport) { - return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \ + return sport->tx_curr_frag = sport_curr_offset_tx(sport) / sport->tx_fragsize; } @@ -130,7 +162,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) sport_incfrag(sport, &nextfrag, 1); - nextwrite = (struct ac97_frame *)(sport->tx_buf + \ + nextwrite = (struct ac97_frame *)(sport->tx_buf + nextfrag * sport->tx_fragsize); pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n", sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]); @@ -297,20 +329,15 @@ static int bf5xx_ac97_resume(struct platform_device *pdev, static int bf5xx_ac97_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { - int ret; -#if defined(CONFIG_BF54x) - u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1, - PIN_REQ_SPORT_2, PIN_REQ_SPORT_3}; -#else - u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1}; -#endif + int ret = 0; cmd_count = (int *)get_zeroed_page(GFP_KERNEL); if (cmd_count == NULL) return -ENOMEM; if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { pr_err("Requesting Peripherals failed\n"); - return -EFAULT; + ret = -EFAULT; + goto peripheral_err; } #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET @@ -318,54 +345,52 @@ static int bf5xx_ac97_probe(struct platform_device *pdev, if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { pr_err("Failed to request GPIO_%d for reset\n", CONFIG_SND_BF5XX_RESET_GPIO_NUM); - peripheral_free_list(&sport_req[sport_num][0]); - return -1; + ret = -1; + goto gpio_err; } gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); #endif sport_handle = sport_init(&sport_params[sport_num], 2, \ sizeof(struct ac97_frame), NULL); if (!sport_handle) { - peripheral_free_list(&sport_req[sport_num][0]); -#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); -#endif - return -ENODEV; + ret = -ENODEV; + goto sport_err; } /*SPORT works in TDM mode to simulate AC97 transfers*/ ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); if (ret) { pr_err("SPORT is busy!\n"); - kfree(sport_handle); - peripheral_free_list(&sport_req[sport_num][0]); -#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); -#endif - return -EBUSY; + ret = -EBUSY; + goto sport_config_err; } ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); - kfree(sport_handle); - peripheral_free_list(&sport_req[sport_num][0]); -#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); -#endif - return -EBUSY; + ret = -EBUSY; + goto sport_config_err; } ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); - kfree(sport_handle); - peripheral_free_list(&sport_req[sport_num][0]); + ret = -EBUSY; + goto sport_config_err; + } + +sport_config_err: + kfree(sport_handle); +sport_err: #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); #endif - return -EBUSY; - } - return 0; +gpio_err: + peripheral_free_list(&sport_req[sport_num][0]); +peripheral_err: + free_page((unsigned long)cmd_count); + cmd_count = NULL; + + return ret; } static void bf5xx_ac97_remove(struct platform_device *pdev, @@ -373,6 +398,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, { free_page((unsigned long)cmd_count); cmd_count = NULL; + peripheral_free_list(&sport_req[sport_num][0]); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); #endif @@ -389,7 +415,11 @@ struct snd_soc_dai bfin_ac97_dai = { .playback = { .stream_name = "AC97 Playback", .channels_min = 2, +#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) + .channels_max = 6, +#else .channels_max = 2, +#endif .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h index 3f77cc558dc..3f2a911fe0c 100644 --- a/sound/soc/blackfin/bf5xx-ac97.h +++ b/sound/soc/blackfin/bf5xx-ac97.h @@ -16,21 +16,46 @@ struct ac97_frame { u16 ac97_tag; /* slot 0 */ u16 ac97_addr; /* slot 1 */ u16 ac97_data; /* slot 2 */ - u32 ac97_pcm; /* slot 3 and 4: left and right pcm data */ + u16 ac97_pcm_l; /*slot 3:front left*/ + u16 ac97_pcm_r; /*slot 4:front left*/ +#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) + u16 ac97_mdm_l1; + u16 ac97_center; /*slot 6:center*/ + u16 ac97_sl; /*slot 7:surround left*/ + u16 ac97_sr; /*slot 8:surround right*/ + u16 ac97_lfe; /*slot 9:lfe*/ +#endif } __attribute__ ((packed)); +/* Speaker location */ +#define SP_FL 0x0001 +#define SP_FR 0x0010 +#define SP_FC 0x0002 +#define SP_LFE 0x0020 +#define SP_SL 0x0004 +#define SP_SR 0x0040 + +#define SP_STEREO (SP_FL | SP_FR) +#define SP_2DOT1 (SP_FL | SP_FR | SP_LFE) +#define SP_QUAD (SP_FL | SP_FR | SP_SL | SP_SR) +#define SP_5DOT1 (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR) + #define TAG_VALID 0x8000 #define TAG_CMD 0x6000 #define TAG_PCM_LEFT 0x1000 #define TAG_PCM_RIGHT 0x0800 -#define TAG_PCM (TAG_PCM_LEFT | TAG_PCM_RIGHT) +#define TAG_PCM_MDM_L1 0x0400 +#define TAG_PCM_CENTER 0x0200 +#define TAG_PCM_SL 0x0100 +#define TAG_PCM_SR 0x0080 +#define TAG_PCM_LFE 0x0040 extern struct snd_soc_dai bfin_ac97_dai; -void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ - size_t count); +void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \ + size_t count, unsigned int chan_mask); -void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ +void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \ size_t count); #endif diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index fcadcc081f7..2e63dea73e9 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h @@ -116,7 +116,7 @@ struct sport_device { void *err_data; unsigned char *tx_dma_buf; unsigned char *rx_dma_buf; -#ifdef CONFIG_SND_MMAP_SUPPORT +#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT dma_addr_t tx_dma_phy; dma_addr_t rx_dma_phy; int tx_pos;/*pcm sample count*/ -- cgit v1.2.3 From a89e611a1dfefbf5d21f6def54c958bf6c4971bc Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Tue, 18 Nov 2008 16:18:18 +0800 Subject: ASoC: Blackfin: Fix AD1980/1 build with MMAP support disabled clean up redudent code and correct building problem in non-mmap mode Signed-off-by: Cliff Cai Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97-pcm.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 4be1a490f4f..4d25f73274e 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -193,8 +193,10 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) bf5xx_mmap_copy(substream, runtime->period_size); sport->tx_delay_pos = 0; +#endif sport_tx_start(sport); } else sport_rx_start(sport); @@ -267,23 +269,6 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) return ret; } -static int bf5xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct sport_device *sport = runtime->private_data; - - pr_debug("%s enter\n", __func__); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - sport->once = 0; - memset(sport->tx_dma_buf, 0, runtime->buffer_size * - sizeof(struct ac97_frame)); - } else - memset(sport->rx_dma_buf, 0, runtime->buffer_size * - sizeof(struct ac97_frame)); - - return 0; -} - #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) @@ -301,7 +286,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, void __user *buf, snd_pcm_uframes_t count) { struct snd_pcm_runtime *runtime = substream->runtime; - + unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; pr_debug("%s copy pos:0x%lx count:0x%lx\n", substream->stream ? "Capture" : "Playback", pos, count); @@ -317,7 +302,6 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, struct snd_pcm_ops bf5xx_pcm_ac97_ops = { .open = bf5xx_pcm_open, - .close = bf5xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = bf5xx_pcm_hw_params, .hw_free = bf5xx_pcm_hw_free, -- cgit v1.2.3 From 0cade26e366549adcf211f67200b2934c8220f05 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 18 Nov 2008 16:18:19 +0800 Subject: ASoC: Fix Blackfin AC97 DAI probe function return code A probe function should have a clean return 0 path. Cc: Cliff Cai Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 65c162c4bfa..5dcd3f665ab 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -378,6 +378,8 @@ static int bf5xx_ac97_probe(struct platform_device *pdev, goto sport_config_err; } + return 0; + sport_config_err: kfree(sport_handle); sport_err: -- cgit v1.2.3 From caa45836d6bdfde603f3afd739ec3fc2360b1dac Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 18 Nov 2008 16:18:20 +0800 Subject: ASoC: Blackfin: do not force TWI bus for ssm2602 codec Cc: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 43d89fc253a..f0fd235ca89 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -13,7 +13,6 @@ config SND_BF5XX_SOC_SSM2602 select SND_BF5XX_SOC_I2S select SND_SOC_SSM2602 select I2C - select I2C_BLACKFIN_TWI help Say Y if you want to add support for SoC audio on BF527-EZKIT. -- cgit v1.2.3 From 27b9be5a7894f571bbfb87de19ad7cd8c7737d22 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Tue, 18 Nov 2008 16:18:21 +0800 Subject: ASoC: Blackfin: Simplify the MMAP_SUPPORT macros protected code Cc: Cliff Cai Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97-pcm.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 4d25f73274e..d3d51bcb456 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -100,17 +100,14 @@ static void bf5xx_dma_irq(void *data) * The total rx/tx buffer is for ac97 frame to hold all pcm data * is 0x20000 * sizeof(struct ac97_frame) / 4. */ -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static const struct snd_pcm_hardware bf5xx_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BLOCK_TRANSFER, -#else -static const struct snd_pcm_hardware bf5xx_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, #endif + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_LE, .period_bytes_min = 32, .period_bytes_max = 0x10000, -- cgit v1.2.3 From a0bd65f45faae78bda7a2a07370c40c3e0a2502a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 18 Nov 2008 16:18:22 +0800 Subject: ASoC: Blackfin: always set a default value for that GPIO range Cc: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index f0fd235ca89..e162cbbd3f3 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -104,5 +104,6 @@ config SND_BF5XX_RESET_GPIO_NUM range 0 159 default 19 if BFIN548_EZKIT default 5 if BFIN537_STAMP + default 0 help Set the correct GPIO for RESET the sound chip. -- cgit v1.2.3 From 72f2b894455775b980a5ac7ae70ab560b3d3d247 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 12:25:46 +0000 Subject: ASoC: Move uda134x_codec.h to uda134x.h For consistency with other ASoC codec drivers. Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 2 +- sound/soc/codecs/uda134x.h | 36 ++++++++++++++++++++++++++++++++++++ sound/soc/codecs/uda134x_codec.h | 36 ------------------------------------ sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 +- 4 files changed, 38 insertions(+), 38 deletions(-) create mode 100644 sound/soc/codecs/uda134x.h delete mode 100644 sound/soc/codecs/uda134x_codec.h diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 04b30da1022..69ef521a2ed 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -24,7 +24,7 @@ #include #include -#include "uda134x_codec.h" +#include "uda134x.h" #define POWER_OFF_ON_STANDBY 1 diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h new file mode 100644 index 00000000000..94f440490b3 --- /dev/null +++ b/sound/soc/codecs/uda134x.h @@ -0,0 +1,36 @@ +#ifndef _UDA134X_CODEC_H +#define _UDA134X_CODEC_H + +#define UDA134X_L3ADDR 5 +#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0) +#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1) +#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2) + +#define UDA134X_EXTADDR_PREFIX 0xC0 +#define UDA134X_EXTDATA_PREFIX 0xE0 + +/* UDA134X registers */ +#define UDA134X_EA000 0 +#define UDA134X_EA001 1 +#define UDA134X_EA010 2 +#define UDA134X_EA011 3 +#define UDA134X_EA100 4 +#define UDA134X_EA101 5 +#define UDA134X_EA110 6 +#define UDA134X_EA111 7 +#define UDA134X_STATUS0 8 +#define UDA134X_STATUS1 9 +#define UDA134X_DATA000 10 +#define UDA134X_DATA001 11 +#define UDA134X_DATA010 12 +#define UDA134X_DATA1 13 + +#define UDA134X_REGS_NUM 14 + +#define STATUS0_DAIFMT_MASK (~(7<<1)) +#define STATUS0_SYSCLK_MASK (~(3<<4)) + +extern struct snd_soc_dai uda134x_dai; +extern struct snd_soc_codec_device soc_codec_dev_uda134x; + +#endif diff --git a/sound/soc/codecs/uda134x_codec.h b/sound/soc/codecs/uda134x_codec.h deleted file mode 100644 index 94f440490b3..00000000000 --- a/sound/soc/codecs/uda134x_codec.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _UDA134X_CODEC_H -#define _UDA134X_CODEC_H - -#define UDA134X_L3ADDR 5 -#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0) -#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1) -#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2) - -#define UDA134X_EXTADDR_PREFIX 0xC0 -#define UDA134X_EXTDATA_PREFIX 0xE0 - -/* UDA134X registers */ -#define UDA134X_EA000 0 -#define UDA134X_EA001 1 -#define UDA134X_EA010 2 -#define UDA134X_EA011 3 -#define UDA134X_EA100 4 -#define UDA134X_EA101 5 -#define UDA134X_EA110 6 -#define UDA134X_EA111 7 -#define UDA134X_STATUS0 8 -#define UDA134X_STATUS1 9 -#define UDA134X_DATA000 10 -#define UDA134X_DATA001 11 -#define UDA134X_DATA010 12 -#define UDA134X_DATA1 13 - -#define UDA134X_REGS_NUM 14 - -#define STATUS0_DAIFMT_MASK (~(7<<1)) -#define STATUS0_SYSCLK_MASK (~(3<<4)) - -extern struct snd_soc_dai uda134x_dai; -extern struct snd_soc_codec_device soc_codec_dev_uda134x; - -#endif diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index 29a68132f16..487b010730b 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -26,7 +26,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-i2s.h" -#include "../codecs/uda134x_codec.h" +#include "../codecs/uda134x.h" /* #define ENFORCE_RATES 1 */ -- cgit v1.2.3 From ca3ea02e90d63a6a91c1c2a445d6d71f9031a44a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 20:40:36 +0000 Subject: ASoC: Remove unused snd_soc_machine_config declaration Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index fa1b99b4589..077dfe4e51f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -228,7 +228,6 @@ struct snd_soc_dai_mode; struct snd_soc_pcm_runtime; struct snd_soc_dai; struct snd_soc_codec; -struct snd_soc_machine_config; struct soc_enum; struct snd_soc_ac97_ops; struct snd_soc_clock_info; -- cgit v1.2.3 From 1c0090c280da18f79e3e94168b5f3bfe4eb5f1c8 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Wed, 19 Nov 2008 01:37:31 -0500 Subject: ASoC: Add PCM3008 ALSA SoC driver The PCM3008 is a 16-bit stereo audio codec. It accepts left-justified format for ADC, and right-justified format for DAC. Independent power-down modes for ADC and DAC are provided, as well as a digital de-emphasis filter (4 modes). [Merged Makefile & Kconfig, changed asm/gpio.h to linux/gpio.h -- broonie] Signed-off-by: Hugo Villeneuve Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/pcm3008.c | 201 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/pcm3008.h | 25 ++++++ 4 files changed, 232 insertions(+) create mode 100644 sound/soc/codecs/pcm3008.c create mode 100644 sound/soc/codecs/pcm3008.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 04f49f5c3c3..bf68052d692 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -5,6 +5,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD73311 if I2C select SND_SOC_AK4535 if I2C select SND_SOC_CS4270 if I2C + select SND_SOC_PCM3008 select SND_SOC_SSM2602 if I2C select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER @@ -70,6 +71,9 @@ config SND_SOC_CS4270_VD33_ERRATA config SND_SOC_L3 tristate +config SND_SOC_PCM3008 + tristate + config SND_SOC_SSM2602 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index de6572356d1..9a20fddd09c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -4,6 +4,7 @@ snd-soc-ad73311-objs := ad73311.o snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o snd-soc-l3-objs := l3.o +snd-soc-pcm3008-objs := pcm3008.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o +obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c new file mode 100644 index 00000000000..2b26e1d80c8 --- /dev/null +++ b/sound/soc/codecs/pcm3008.c @@ -0,0 +1,201 @@ +/* + * ALSA Soc PCM3008 codec support + * + * Author: Hugo Villeneuve + * Copyright (C) 2008 Lyrtech inc + * + * Based on AC97 Soc codec, original copyright follow: + * Copyright 2005 Wolfson Microelectronics PLC. + * + * 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. + * + * Generic PCM3008 support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcm3008.h" + +#define PCM3008_VERSION "0.2" + +#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) + +struct snd_soc_dai pcm3008_dai = { + .name = "PCM3008 HiFi", + .type = SND_SOC_DAI_I2S, + .playback = { + .stream_name = "PCM3008 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = PCM3008_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "PCM3008 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = PCM3008_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; +EXPORT_SYMBOL_GPL(pcm3008_dai); + +static void pcm3008_gpio_free(struct pcm3008_setup_data *setup) +{ + gpio_free(setup->dem0_pin); + gpio_free(setup->dem1_pin); + gpio_free(setup->pdad_pin); + gpio_free(setup->pdda_pin); +} + +static int pcm3008_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct pcm3008_setup_data *setup = socdev->codec_data; + int ret = 0; + + printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION); + + socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (!socdev->codec) + return -ENOMEM; + + codec = socdev->codec; + mutex_init(&codec->mutex); + + codec->name = "PCM3008"; + codec->owner = THIS_MODULE; + codec->dai = &pcm3008_dai; + codec->num_dai = 1; + codec->write = NULL; + codec->read = NULL; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + /* Register PCMs. */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "pcm3008: failed to create pcms\n"); + goto pcm_err; + } + + /* Register Card. */ + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "pcm3008: failed to register card\n"); + goto card_err; + } + + /* DEM1 DEM0 DE-EMPHASIS_MODE + * Low Low De-emphasis 44.1 kHz ON + * Low High De-emphasis OFF + * High Low De-emphasis 48 kHz ON + * High High De-emphasis 32 kHz ON + */ + + /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */ + ret = gpio_request(setup->dem0_pin, "codec_dem0"); + if (ret == 0) + ret = gpio_direction_output(setup->dem0_pin, 1); + if (ret != 0) + goto gpio_err; + + /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */ + ret = gpio_request(setup->dem1_pin, "codec_dem1"); + if (ret == 0) + ret = gpio_direction_output(setup->dem1_pin, 0); + if (ret != 0) + goto gpio_err; + + /* Configure PDAD GPIO. */ + ret = gpio_request(setup->pdad_pin, "codec_pdad"); + if (ret == 0) + ret = gpio_direction_output(setup->pdad_pin, 1); + if (ret != 0) + goto gpio_err; + + /* Configure PDDA GPIO. */ + ret = gpio_request(setup->pdda_pin, "codec_pdda"); + if (ret == 0) + ret = gpio_direction_output(setup->pdda_pin, 1); + if (ret != 0) + goto gpio_err; + + return ret; + +gpio_err: + pcm3008_gpio_free(setup); +card_err: + snd_soc_free_pcms(socdev); +pcm_err: + kfree(socdev->codec); + + return ret; +} + +static int pcm3008_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct pcm3008_setup_data *setup = socdev->codec_data; + + if (!codec) + return 0; + + pcm3008_gpio_free(setup); + snd_soc_free_pcms(socdev); + kfree(socdev->codec); + + return 0; +} + +#ifdef CONFIG_PM +static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct pcm3008_setup_data *setup = socdev->codec_data; + + gpio_set_value(setup->pdad_pin, 0); + gpio_set_value(setup->pdda_pin, 0); + + return 0; +} + +static int pcm3008_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct pcm3008_setup_data *setup = socdev->codec_data; + + gpio_set_value(setup->pdad_pin, 1); + gpio_set_value(setup->pdda_pin, 1); + + return 0; +} +#else +#define pcm3008_soc_suspend NULL +#define pcm3008_soc_resume NULL +#endif + +struct snd_soc_codec_device soc_codec_dev_pcm3008 = { + .probe = pcm3008_soc_probe, + .remove = pcm3008_soc_remove, + .suspend = pcm3008_soc_suspend, + .resume = pcm3008_soc_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008); + +MODULE_DESCRIPTION("Soc PCM3008 driver"); +MODULE_AUTHOR("Hugo Villeneuve"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h new file mode 100644 index 00000000000..d04e87d3c06 --- /dev/null +++ b/sound/soc/codecs/pcm3008.h @@ -0,0 +1,25 @@ +/* + * PCM3008 ALSA SoC Layer + * + * Author: Hugo Villeneuve + * Copyright (C) 2008 Lyrtech inc + * + * 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 __LINUX_SND_SOC_PCM3008_H +#define __LINUX_SND_SOC_PCM3008_H + +struct pcm3008_setup_data { + unsigned dem0_pin; + unsigned dem1_pin; + unsigned pdad_pin; + unsigned pdda_pin; +}; + +extern struct snd_soc_codec_device soc_codec_dev_pcm3008; +extern struct snd_soc_dai pcm3008_dai; + +#endif -- cgit v1.2.3 From 08bd16869645f435eba6a612d166532b3047c5f7 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Wed, 19 Nov 2008 01:37:32 -0500 Subject: ASoC: Add driver for the Lyrtech SFFSDR board The PCM3008 is used on the Lyrtech SFFSDR board, in conjunction with an FPGA that generates the bit clock and the master clock [Downgraded the rate debug print to pr_debug() in hw_params, converted asm/gpio.h to linux/gpio.h -- broonie] Signed-off-by: Hugo Villeneuve Signed-off-by: Mark Brown --- sound/soc/davinci/Kconfig | 10 +++ sound/soc/davinci/Makefile | 2 + sound/soc/davinci/davinci-sffsdr.c | 156 +++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 sound/soc/davinci/davinci-sffsdr.c diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 8f7e3383490..b502741692d 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -17,3 +17,13 @@ config SND_DAVINCI_SOC_EVM help Say Y if you want to add support for SoC audio on TI DaVinci EVM platform. + +config SND_DAVINCI_SOC_SFFSDR + tristate "SoC Audio support for SFFSDR" + depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR + select SND_DAVINCI_SOC_I2S + select SND_SOC_PCM3008 + select SFFSDR_FPGA + help + Say Y if you want to add support for SoC audio on + Lyrtech SFFSDR board. diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index ca772e5b463..ca8bae1fc3f 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -7,5 +7,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o # DAVINCI Machine Support snd-soc-evm-objs := davinci-evm.o +snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o +obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c new file mode 100644 index 00000000000..69a8a769f4d --- /dev/null +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -0,0 +1,156 @@ +/* + * ASoC driver for Lyrtech SFFSDR board. + * + * Author: Hugo Villeneuve + * Copyright (C) 2008 Lyrtech inc + * + * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow: + * Copyright: (C) 2007 MontaVista Software, Inc., + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "../codecs/pcm3008.h" +#include "davinci-pcm.h" +#include "davinci-i2s.h" + +static int sffsdr_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->dai->cpu_dai; + int fs; + int ret = 0; + + /* Set cpu DAI configuration: + * CLKX and CLKR are the inputs for the Sample Rate Generator. + * FSX and FSR are outputs, driven by the sample Rate Generator. */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_RIGHT_J | + SND_SOC_DAIFMT_CBM_CFS | + SND_SOC_DAIFMT_IB_NF); + if (ret < 0) + return ret; + + /* Fsref can be 32000, 44100 or 48000. */ + fs = params_rate(params); + + pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); + + return sffsdr_fpga_set_codec_fs(fs); +} + +static struct snd_soc_ops sffsdr_ops = { + .hw_params = sffsdr_hw_params, +}; + +/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link sffsdr_dai = { + .name = "PCM3008", /* Codec name */ + .stream_name = "PCM3008 HiFi", + .cpu_dai = &davinci_i2s_dai, + .codec_dai = &pcm3008_dai, + .ops = &sffsdr_ops, +}; + +/* davinci-sffsdr audio machine driver */ +static struct snd_soc_machine snd_soc_machine_sffsdr = { + .name = "DaVinci SFFSDR", + .dai_link = &sffsdr_dai, + .num_links = 1, +}; + +/* sffsdr audio private data */ +static struct pcm3008_setup_data sffsdr_pcm3008_setup = { + .dem0_pin = GPIO(45), + .dem1_pin = GPIO(46), + .pdad_pin = GPIO(47), + .pdda_pin = GPIO(38), +}; + +/* sffsdr audio subsystem */ +static struct snd_soc_device sffsdr_snd_devdata = { + .machine = &snd_soc_machine_sffsdr, + .platform = &davinci_soc_platform, + .codec_dev = &soc_codec_dev_pcm3008, + .codec_data = &sffsdr_pcm3008_setup, +}; + +static struct resource sffsdr_snd_resources[] = { + { + .start = DAVINCI_MCBSP_BASE, + .end = DAVINCI_MCBSP_BASE + SZ_8K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct evm_snd_platform_data sffsdr_snd_data = { + .tx_dma_ch = DAVINCI_DMA_MCBSP_TX, + .rx_dma_ch = DAVINCI_DMA_MCBSP_RX, +}; + +static struct platform_device *sffsdr_snd_device; + +static int __init sffsdr_init(void) +{ + int ret; + + sffsdr_snd_device = platform_device_alloc("soc-audio", 0); + if (!sffsdr_snd_device) { + printk(KERN_ERR "platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); + sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; + sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data; + + ret = platform_device_add_resources(sffsdr_snd_device, + sffsdr_snd_resources, + ARRAY_SIZE(sffsdr_snd_resources)); + if (ret) { + printk(KERN_ERR "platform device add ressources failed\n"); + goto error; + } + + ret = platform_device_add(sffsdr_snd_device); + if (ret) + goto error; + + return ret; + +error: + platform_device_put(sffsdr_snd_device); + return ret; +} + +static void __exit sffsdr_exit(void) +{ + platform_device_unregister(sffsdr_snd_device); +} + +module_init(sffsdr_init); +module_exit(sffsdr_exit); + +MODULE_AUTHOR("Hugo Villeneuve"); +MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From df573d2fd1b077b98ffc3eb62a9908075e69e578 Mon Sep 17 00:00:00 2001 From: Arun KS Date: Wed, 19 Nov 2008 17:45:19 +0530 Subject: ASoC: Add support for omap2evm board This patch adds twl4030 audio support on omap2evm Signed-off-by: Arun KS Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 9 +++ sound/soc/omap/Makefile | 2 + sound/soc/omap/omap2evm.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 sound/soc/omap/omap2evm.c diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index cf40e42954a..6c56277e160 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -30,4 +30,13 @@ config SND_OMAP_SOC_OVERO help Say Y if you want to add support for SoC audio on the Gumstix Overo. +config SND_OMAP_SOC_OMAP2EVM + tristate "SoC Audio support for OMAP2EVM board" + depends on SND_OMAP_SOC && MACH_OMAP2EVM + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the omap2evm board. + + diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index fefc9bed053..f5da3cc764a 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -9,8 +9,10 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o +snd-soc-omap2evm-objs := omap2evm.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o +obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c new file mode 100644 index 00000000000..c37621357d0 --- /dev/null +++ b/sound/soc/omap/omap2evm.c @@ -0,0 +1,150 @@ +/* + * omap2evm.c -- SoC audio machine driver for omap2evm board + * + * Author: Arun KS + * + * Based on sound/soc/omap/overo.c by Steve Sakoman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int omap2evm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops omap2evm_ops = { + .hw_params = omap2evm_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap2evm_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap2evm_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_omap2evm = { + .name = "omap2evm", + .dai_link = &omap2evm_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device omap2evm_snd_devdata = { + .machine = &snd_soc_machine_omap2evm, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap2evm_snd_device; + +static int __init omap2evm_soc_init(void) +{ + int ret; + + if (!machine_is_omap2evm()) { + pr_debug("Not omap2evm!\n"); + return -ENODEV; + } + printk(KERN_INFO "omap2evm SoC init\n"); + + omap2evm_snd_device = platform_device_alloc("soc-audio", -1); + if (!omap2evm_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata); + omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev; + *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(omap2evm_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(omap2evm_snd_device); + + return ret; +} +module_init(omap2evm_soc_init); + +static void __exit omap2evm_soc_exit(void) +{ + platform_device_unregister(omap2evm_snd_device); +} +module_exit(omap2evm_soc_exit); + +MODULE_AUTHOR("Arun KS "); +MODULE_DESCRIPTION("ALSA SoC omap2evm"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From d0c36631bbee9eb89f2fe4251e0e9583f37156cd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 21:57:17 +0000 Subject: ASoC: s3c24xx_uda134x DAI accessor functions and static cleanup Missed these during review. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx_uda134x.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index 487b010730b..92d90f2f690 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -63,7 +63,7 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = { static struct platform_device *s3c24xx_uda134x_snd_device; -int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) +static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) { int ret = 0; #ifdef ENFORCE_RATES @@ -115,7 +115,7 @@ int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) return ret; } -void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) +static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) { mutex_lock(&clk_lock); pr_debug("%s %d\n", __func__, clk_users); @@ -180,39 +180,38 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, clk_source , clk, - SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk, + SND_SOC_CLOCK_IN); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, - fs_mode); + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, - S3C2410_IISMOD_32FS); + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, + S3C2410_IISMOD_32FS); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, - S3C24XX_PRESCALE(div, div)); + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, + S3C24XX_PRESCALE(div, div)); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ - ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, clk, - SND_SOC_CLOCK_OUT); + ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, + SND_SOC_CLOCK_OUT); if (ret < 0) return ret; -- cgit v1.2.3 From 9b0db7e7fd20d5a38844e9435f7d4246ea44978a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 22:17:49 +0000 Subject: ASoC: Convert blackfin machines to use DAI accessor functions Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ad73311.c | 2 +- sound/soc/blackfin/bf5xx-ssm2602.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 622c9b90953..47da49b9aea 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -168,7 +168,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream, params_format(params)); /* set cpu DAI configuration */ - ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index e15f67fd776..744a90e765d 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -92,17 +92,17 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, */ /* set codec DAI configuration */ - ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; - ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk, + ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk, SND_SOC_CLOCK_IN); if (ret < 0) return ret; -- cgit v1.2.3 From 875065491fba8eb13219f16c36e79a6fb4e15c68 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 20:50:34 +0000 Subject: ASoC: Rename snd_soc_card to snd_soc_machine One of the issues with the ASoC v1 API which has been addressed in the ASoC v2 work that Liam Girdwood has done is that the ALSA card provided by ASoC is distributed around the ASoC structures. For example, machine wide data such as the struct snd_card are maintained as part of the CODEC data structure, preventing the use of multiple codecs. This has been addressed by refactoring the data structures so that all the data for the ALSA card is contained in a single structure snd_soc_card which replaces the existing snd_soc_machine and snd_soc_device. Begin the process of backporting this by renaming struct snd_soc_machine to struct snd_soc_card, better reflecting its function and bringing it closer to standard ALSA terminology. Signed-off-by: Mark Brown --- Documentation/sound/alsa/soc/machine.txt | 8 +-- include/sound/soc.h | 8 +-- sound/soc/atmel/playpaq_wm8510.c | 4 +- sound/soc/atmel/sam9g20_wm8731.c | 4 +- sound/soc/au1x/sample-ac97.c | 4 +- sound/soc/blackfin/bf5xx-ad1980.c | 6 +-- sound/soc/blackfin/bf5xx-ad73311.c | 6 +-- sound/soc/blackfin/bf5xx-ssm2602.c | 6 +-- sound/soc/davinci/davinci-evm.c | 4 +- sound/soc/davinci/davinci-i2s.c | 8 +-- sound/soc/davinci/davinci-sffsdr.c | 4 +- sound/soc/fsl/fsl_dma.c | 2 +- sound/soc/fsl/mpc8610_hpcd.c | 6 +-- sound/soc/fsl/soc-of-simple.c | 10 ++-- sound/soc/omap/n810.c | 4 +- sound/soc/omap/omap2evm.c | 4 +- sound/soc/omap/omap3beagle.c | 4 +- sound/soc/omap/osk5912.c | 4 +- sound/soc/omap/overo.c | 4 +- sound/soc/pxa/corgi.c | 4 +- sound/soc/pxa/e800_wm9712.c | 6 +-- sound/soc/pxa/em-x270.c | 4 +- sound/soc/pxa/palm27x.c | 4 +- sound/soc/pxa/poodle.c | 4 +- sound/soc/pxa/spitz.c | 4 +- sound/soc/pxa/tosa.c | 6 +-- sound/soc/s3c24xx/ln2440sbc_alc650.c | 6 +-- sound/soc/s3c24xx/neo1973_wm8753.c | 6 +-- sound/soc/s3c24xx/s3c24xx_uda134x.c | 4 +- sound/soc/s3c24xx/smdk2443_wm9710.c | 6 +-- sound/soc/sh/sh7760-ac97.c | 4 +- sound/soc/soc-core.c | 90 ++++++++++++++++---------------- sound/soc/soc-dapm.c | 6 +-- 33 files changed, 127 insertions(+), 127 deletions(-) diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index f370e7db86a..4a9f51e2905 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -9,7 +9,7 @@ the audio subsystem with the kernel as a platform device and is represented by the following struct:- /* SoC machine */ -struct snd_soc_machine { +struct snd_soc_card {_ char *name; int (*probe)(struct platform_device *pdev); @@ -67,10 +67,10 @@ static struct snd_soc_dai_link corgi_dai = { .ops = &corgi_ops, }; -struct snd_soc_machine then sets up the machine with it's DAIs. e.g. +struct snd_soc_card then sets up the machine with it's DAIs. e.g. /* corgi audio machine driver */ -static struct snd_soc_machine snd_soc_machine_corgi = { +static struct snd_soc_card snd_soc_corgi = { .name = "Corgi", .dai_link = &corgi_dai, .num_links = 1, @@ -90,7 +90,7 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { - .machine = &snd_soc_machine_corgi, + .machine = &snd_soc_corgi, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, diff --git a/include/sound/soc.h b/include/sound/soc.h index 077dfe4e51f..3be17b3c650 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -482,8 +482,8 @@ struct snd_soc_dai_link { struct snd_pcm *pcm; }; -/* SoC machine */ -struct snd_soc_machine { +/* SoC card */ +struct snd_soc_card { char *name; int (*probe)(struct platform_device *pdev); @@ -497,7 +497,7 @@ struct snd_soc_machine { int (*resume_post)(struct platform_device *pdev); /* callbacks */ - int (*set_bias_level)(struct snd_soc_machine *, + int (*set_bias_level)(struct snd_soc_card *, enum snd_soc_bias_level level); /* CPU <--> Codec DAI links */ @@ -508,7 +508,7 @@ struct snd_soc_machine { /* SoC Device - the audio subsystem */ struct snd_soc_device { struct device *dev; - struct snd_soc_machine *machine; + struct snd_soc_card *card; struct snd_soc_platform *platform; struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index ea7935d2a66..d40b5a52a8d 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -361,7 +361,7 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = { -static struct snd_soc_machine snd_soc_machine_playpaq = { +static struct snd_soc_card snd_soc_playpaq = { .name = "LRS_PlayPaq_WM8510", .dai_link = &playpaq_wm8510_dai, .num_links = 1, @@ -377,7 +377,7 @@ static struct wm8510_setup_data playpaq_wm8510_setup = { static struct snd_soc_device playpaq_wm8510_snd_devdata = { - .machine = &snd_soc_machine_playpaq, + .card = &snd_soc_playpaq, .platform = &at32_soc_platform, .codec_dev = &soc_codec_dev_wm8510, .codec_data = &playpaq_wm8510_setup, diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 710addcc66b..fdc1d0206e0 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -242,7 +242,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = { .ops = &at91sam9g20ek_ops, }; -static struct snd_soc_machine snd_soc_machine_at91sam9g20ek = { +static struct snd_soc_card snd_soc_at91sam9g20ek = { .name = "WM8731", .dai_link = &at91sam9g20ek_dai, .num_links = 1, @@ -254,7 +254,7 @@ static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { }; static struct snd_soc_device at91sam9g20ek_snd_devdata = { - .machine = &snd_soc_machine_at91sam9g20ek, + .card = &snd_soc_at91sam9g20ek, .platform = &atmel_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &at91sam9g20ek_wm8731_setup, diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c index f75ae7f62c3..27683eb7905 100644 --- a/sound/soc/au1x/sample-ac97.c +++ b/sound/soc/au1x/sample-ac97.c @@ -42,14 +42,14 @@ static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { .ops = NULL, }; -static struct snd_soc_machine au1xpsc_sample_ac97_machine = { +static struct snd_soc_card au1xpsc_sample_ac97_machine = { .name = "Au1xxx PSC AC97 Audio", .dai_link = &au1xpsc_sample_ac97_dai, .num_links = 1, }; static struct snd_soc_device au1xpsc_sample_ac97_devdata = { - .machine = &au1xpsc_sample_ac97_machine, + .card = &au1xpsc_sample_ac97_machine, .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index 124425d2232..36c569a43ce 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c @@ -43,7 +43,7 @@ #include "bf5xx-ac97-pcm.h" #include "bf5xx-ac97.h" -static struct snd_soc_machine bf5xx_board; +static struct snd_soc_card bf5xx_board; static int bf5xx_board_startup(struct snd_pcm_substream *substream) { @@ -67,14 +67,14 @@ static struct snd_soc_dai_link bf5xx_board_dai = { .ops = &bf5xx_board_ops, }; -static struct snd_soc_machine bf5xx_board = { +static struct snd_soc_card bf5xx_board = { .name = "bf5xx-board", .dai_link = &bf5xx_board_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_board_snd_devdata = { - .machine = &bf5xx_board, + .card = &bf5xx_board, .platform = &bf5xx_ac97_soc_platform, .codec_dev = &soc_codec_dev_ad1980, }; diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 47da49b9aea..57da1479937 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -65,7 +65,7 @@ #define GPIO_SE CONFIG_SND_BFIN_AD73311_SE -static struct snd_soc_machine bf5xx_ad73311; +static struct snd_soc_card bf5xx_ad73311; static int snd_ad73311_startup(void) { @@ -190,7 +190,7 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai = { .ops = &bf5xx_ad73311_ops, }; -static struct snd_soc_machine bf5xx_ad73311 = { +static struct snd_soc_card bf5xx_ad73311 = { .name = "bf5xx_ad73311", .probe = bf5xx_probe, .dai_link = &bf5xx_ad73311_dai, @@ -198,7 +198,7 @@ static struct snd_soc_machine bf5xx_ad73311 = { }; static struct snd_soc_device bf5xx_ad73311_snd_devdata = { - .machine = &bf5xx_ad73311, + .card = &bf5xx_ad73311, .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ad73311, }; diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index 744a90e765d..0078dfcd95b 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -44,7 +44,7 @@ #include "bf5xx-i2s-pcm.h" #include "bf5xx-i2s.h" -static struct snd_soc_machine bf5xx_ssm2602; +static struct snd_soc_card bf5xx_ssm2602; static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream) { @@ -135,14 +135,14 @@ static struct ssm2602_setup_data bf5xx_ssm2602_setup = { .i2c_address = 0x1b, }; -static struct snd_soc_machine bf5xx_ssm2602 = { +static struct snd_soc_card bf5xx_ssm2602 = { .name = "bf5xx_ssm2602", .dai_link = &bf5xx_ssm2602_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { - .machine = &bf5xx_ssm2602, + .card = &bf5xx_ssm2602, .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ssm2602, .codec_data = &bf5xx_ssm2602_setup, diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 9e6062cd6b5..2ce34d44b15 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -128,7 +128,7 @@ static struct snd_soc_dai_link evm_dai = { }; /* davinci-evm audio machine driver */ -static struct snd_soc_machine snd_soc_machine_evm = { +static struct snd_soc_card snd_soc_card_evm = { .name = "DaVinci EVM", .dai_link = &evm_dai, .num_links = 1, @@ -142,7 +142,7 @@ static struct aic3x_setup_data evm_aic3x_setup = { /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { - .machine = &snd_soc_machine_evm, + .card = &snd_soc_card_evm, .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &evm_aic3x_setup, diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 11c20d0b7bc..95df51e803b 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -375,8 +375,8 @@ static int davinci_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; + struct snd_soc_card *card = socdev->card; + struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea; struct evm_snd_platform_data *pdata; @@ -437,8 +437,8 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; + struct snd_soc_card *card = socdev->card; + struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev = cpu_dai->private_data; struct resource *mem; diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 69a8a769f4d..fa38f9cd350 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -73,7 +73,7 @@ static struct snd_soc_dai_link sffsdr_dai = { }; /* davinci-sffsdr audio machine driver */ -static struct snd_soc_machine snd_soc_machine_sffsdr = { +static struct snd_soc_card snd_soc_sffsdr = { .name = "DaVinci SFFSDR", .dai_link = &sffsdr_dai, .num_links = 1, @@ -89,7 +89,7 @@ static struct pcm3008_setup_data sffsdr_pcm3008_setup = { /* sffsdr audio subsystem */ static struct snd_soc_device sffsdr_snd_devdata = { - .machine = &snd_soc_machine_sffsdr, + .card = &snd_soc_sffsdr, .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_pcm3008, .codec_data = &sffsdr_pcm3008_setup, diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index d2d3da9729f..bf92331b476 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -284,7 +284,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * fsl_dma_new: initialize this PCM driver. * * This function is called when the codec driver calls snd_soc_new_pcms(), - * once for each .dai_link in the machine driver's snd_soc_machine + * once for each .dai_link in the machine driver's snd_soc_card * structure. */ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 94f89debde1..1cf4d6eeb53 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -29,7 +29,7 @@ struct mpc8610_hpcd_data { struct snd_soc_device sound_devdata; struct snd_soc_dai_link dai; - struct snd_soc_machine machine; + struct snd_soc_card machine; unsigned int dai_format; unsigned int codec_clk_direction; unsigned int cpu_clk_direction; @@ -185,7 +185,7 @@ static struct snd_soc_ops mpc8610_hpcd_ops = { /** * mpc8610_hpcd_machine: ASoC machine data */ -static struct snd_soc_machine mpc8610_hpcd_machine = { +static struct snd_soc_card mpc8610_hpcd_machine = { .probe = mpc8610_hpcd_machine_probe, .remove = mpc8610_hpcd_machine_remove, .name = "MPC8610 HPCD", @@ -465,7 +465,7 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, goto error; } - machine_data->sound_devdata.machine = &mpc8610_hpcd_machine; + machine_data->sound_devdata.card = &mpc8610_hpcd_machine; machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; machine_data->sound_devdata.platform = &fsl_soc_platform; diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c index 0382fdac51c..53be6491320 100644 --- a/sound/soc/fsl/soc-of-simple.c +++ b/sound/soc/fsl/soc-of-simple.c @@ -31,7 +31,7 @@ struct of_snd_soc_device { int id; struct list_head list; struct snd_soc_device device; - struct snd_soc_machine machine; + struct snd_soc_card card; struct snd_soc_dai_link dai_link; struct platform_device *pdev; struct device_node *platform_node; @@ -58,9 +58,9 @@ of_snd_soc_get_device(struct device_node *codec_node) /* Initialize the structure and add it to the global list */ of_soc->codec_node = codec_node; of_soc->id = of_snd_soc_next_index++; - of_soc->machine.dai_link = &of_soc->dai_link; - of_soc->machine.num_links = 1; - of_soc->device.machine = &of_soc->machine; + of_soc->card.dai_link = &of_soc->dai_link; + of_soc->card.num_links = 1; + of_soc->device.card = &of_soc->card; of_soc->dai_link.ops = &of_snd_soc_ops; list_add(&of_soc->list, &of_snd_soc_device_list); @@ -159,7 +159,7 @@ int of_snd_soc_register_platform(struct snd_soc_platform *platform, of_soc->platform_node = node; of_soc->dai_link.cpu_dai = cpu_dai; of_soc->device.platform = platform; - of_soc->machine.name = of_soc->dai_link.cpu_dai->name; + of_soc->card.name = of_soc->dai_link.cpu_dai->name; /* Now try to register the SoC device */ of_snd_soc_register_device(of_soc); diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index fae3ad36e0b..d216b4f9e14 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -282,7 +282,7 @@ static struct snd_soc_dai_link n810_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_n810 = { +static struct snd_soc_card snd_soc_n810 = { .name = "N810", .dai_link = &n810_dai, .num_links = 1, @@ -298,7 +298,7 @@ static struct aic3x_setup_data n810_aic33_setup = { /* Audio subsystem */ static struct snd_soc_device n810_snd_devdata = { - .machine = &snd_soc_machine_n810, + .card = &snd_soc_n810, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &n810_aic33_setup, diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index c37621357d0..5bea31157a9 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -90,7 +90,7 @@ static struct snd_soc_dai_link omap2evm_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_omap2evm = { +static struct snd_soc_card snd_soc_omap2evm = { .name = "omap2evm", .dai_link = &omap2evm_dai, .num_links = 1, @@ -98,7 +98,7 @@ static struct snd_soc_machine snd_soc_machine_omap2evm = { /* Audio subsystem */ static struct snd_soc_device omap2evm_snd_devdata = { - .machine = &snd_soc_machine_omap2evm, + .card = &snd_soc_omap2evm, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index ec84a9bbc56..3ed25464627 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -88,7 +88,7 @@ static struct snd_soc_dai_link omap3beagle_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_omap3beagle = { +static struct snd_soc_card snd_soc_omap3beagle = { .name = "omap3beagle", .dai_link = &omap3beagle_dai, .num_links = 1, @@ -96,7 +96,7 @@ static struct snd_soc_machine snd_soc_machine_omap3beagle = { /* Audio subsystem */ static struct snd_soc_device omap3beagle_snd_devdata = { - .machine = &snd_soc_machine_omap3beagle, + .card = &snd_soc_omap3beagle, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 0fe73379689..7a8f14d0c77 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -143,7 +143,7 @@ static struct snd_soc_dai_link osk_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_osk = { +static struct snd_soc_card snd_soc_card_osk = { .name = "OSK5912", .dai_link = &osk_dai, .num_links = 1, @@ -151,7 +151,7 @@ static struct snd_soc_machine snd_soc_machine_osk = { /* Audio subsystem */ static struct snd_soc_device osk_snd_devdata = { - .machine = &snd_soc_machine_osk, + .card = &snd_soc_card_osk, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_tlv320aic23, }; diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index c26d1de7da5..eea0c372bb3 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -88,7 +88,7 @@ static struct snd_soc_dai_link overo_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_overo = { +static struct snd_soc_card snd_soc_card_overo = { .name = "overo", .dai_link = &overo_dai, .num_links = 1, @@ -96,7 +96,7 @@ static struct snd_soc_machine snd_soc_machine_overo = { /* Audio subsystem */ static struct snd_soc_device overo_snd_devdata = { - .machine = &snd_soc_machine_overo, + .card = &snd_soc_card_overo, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 2718eaf7895..647f056a3cb 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -314,7 +314,7 @@ static struct snd_soc_dai_link corgi_dai = { }; /* corgi audio machine driver */ -static struct snd_soc_machine snd_soc_machine_corgi = { +static struct snd_soc_card snd_soc_corgi = { .name = "Corgi", .dai_link = &corgi_dai, .num_links = 1, @@ -328,7 +328,7 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { - .machine = &snd_soc_machine_corgi, + .card = &snd_soc_corgi, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 6781c5be242..60c64861512 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -29,7 +29,7 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static struct snd_soc_machine e800; +static struct snd_soc_card e800; static struct snd_soc_dai_link e800_dai[] = { { @@ -40,14 +40,14 @@ static struct snd_soc_dai_link e800_dai[] = { }, }; -static struct snd_soc_machine e800 = { +static struct snd_soc_card e800 = { .name = "Toshiba e800", .dai_link = e800_dai, .num_links = ARRAY_SIZE(e800_dai), }; static struct snd_soc_device e800_snd_devdata = { - .machine = &e800, + .card = &e800, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index e6ff6929ab4..4a61925c310 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -53,14 +53,14 @@ static struct snd_soc_dai_link em_x270_dai[] = { }, }; -static struct snd_soc_machine em_x270 = { +static struct snd_soc_card em_x270 = { .name = "EM-X270", .dai_link = em_x270_dai, .num_links = ARRAY_SIZE(em_x270_dai), }; static struct snd_soc_device em_x270_snd_devdata = { - .machine = &em_x270, + .card = &em_x270, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index e364abc700d..3bb8879ac8a 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -189,14 +189,14 @@ static struct snd_soc_dai_link palm27x_dai[] = { }, }; -static struct snd_soc_machine palm27x_asoc = { +static struct snd_soc_card palm27x_asoc = { .name = "Palm/PXA27x", .dai_link = palm27x_dai, .num_links = ARRAY_SIZE(palm27x_dai), }; static struct snd_soc_device palm27x_snd_devdata = { - .machine = &palm27x_asoc, + .card = &palm27x_asoc, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 4d9930c5278..03b510ab282 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = { }; /* poodle audio machine driver */ -static struct snd_soc_machine snd_soc_machine_poodle = { +static struct snd_soc_card snd_soc_poodle = { .name = "Poodle", .dai_link = &poodle_dai, .num_links = 1, @@ -290,7 +290,7 @@ static struct wm8731_setup_data poodle_wm8731_setup = { /* poodle audio subsystem */ static struct snd_soc_device poodle_snd_devdata = { - .machine = &snd_soc_machine_poodle, + .card = &snd_soc_poodle, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &poodle_wm8731_setup, diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index d307b6757e9..579d93368f1 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -319,7 +319,7 @@ static struct snd_soc_dai_link spitz_dai = { }; /* spitz audio machine driver */ -static struct snd_soc_machine snd_soc_machine_spitz = { +static struct snd_soc_card snd_soc_spitz = { .name = "Spitz", .dai_link = &spitz_dai, .num_links = 1, @@ -333,7 +333,7 @@ static struct wm8750_setup_data spitz_wm8750_setup = { /* spitz audio subsystem */ static struct snd_soc_device spitz_snd_devdata = { - .machine = &snd_soc_machine_spitz, + .card = &snd_soc_spitz, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8750, .codec_data = &spitz_wm8750_setup, diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index afefe41b8c4..9d9be5a14d1 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -38,7 +38,7 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static struct snd_soc_machine tosa; +static struct snd_soc_card tosa; #define TOSA_HP 0 #define TOSA_MIC_INT 1 @@ -230,14 +230,14 @@ static struct snd_soc_dai_link tosa_dai[] = { }, }; -static struct snd_soc_machine tosa = { +static struct snd_soc_card tosa = { .name = "Tosa", .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), }; static struct snd_soc_device tosa_snd_devdata = { - .machine = &tosa, + .card = &tosa, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index 4eab2c19c45..a70cbc0fa07 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -27,7 +27,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-ac97.h" -static struct snd_soc_machine ln2440sbc; +static struct snd_soc_card ln2440sbc; static struct snd_soc_dai_link ln2440sbc_dai[] = { { @@ -38,14 +38,14 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { }, }; -static struct snd_soc_machine ln2440sbc = { +static struct snd_soc_card ln2440sbc = { .name = "LN2440SBC", .dai_link = ln2440sbc_dai, .num_links = ARRAY_SIZE(ln2440sbc_dai), }; static struct snd_soc_device ln2440sbc_snd_ac97_devdata = { - .machine = &ln2440sbc, + .card = &ln2440sbc, .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 87ddfefcc2f..528fc3f1b45 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -59,7 +59,7 @@ #define NEO_CAPTURE_HEADSET 7 #define NEO_CAPTURE_BLUETOOTH 8 -static struct snd_soc_machine neo1973; +static struct snd_soc_card neo1973; static struct i2c_client *i2c; static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, @@ -579,7 +579,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { }, }; -static struct snd_soc_machine neo1973 = { +static struct snd_soc_card neo1973 = { .name = "neo1973", .dai_link = neo1973_dai, .num_links = ARRAY_SIZE(neo1973_dai), @@ -591,7 +591,7 @@ static struct wm8753_setup_data neo1973_wm8753_setup = { }; static struct snd_soc_device neo1973_snd_devdata = { - .machine = &neo1973, + .card = &neo1973, .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_wm8753, .codec_data = &neo1973_wm8753_setup, diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index 92d90f2f690..23325fca1f6 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -232,7 +232,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { .ops = &s3c24xx_uda134x_ops, }; -static struct snd_soc_machine snd_soc_machine_s3c24xx_uda134x = { +static struct snd_soc_card snd_soc_s3c24xx_uda134x = { .name = "S3C24XX_UDA134X", .dai_link = &s3c24xx_uda134x_dai_link, .num_links = 1, @@ -270,7 +270,7 @@ static struct uda134x_platform_data s3c24xx_uda134x = { }; static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { - .machine = &snd_soc_machine_s3c24xx_uda134x, + .card = &snd_soc_s3c24xx_uda134x, .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_uda134x, .codec_data = &s3c24xx_uda134x, diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index 8515d6ff03f..3d2e6a0417e 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -23,7 +23,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-ac97.h" -static struct snd_soc_machine smdk2443; +static struct snd_soc_card smdk2443; static struct snd_soc_dai_link smdk2443_dai[] = { { @@ -34,14 +34,14 @@ static struct snd_soc_dai_link smdk2443_dai[] = { }, }; -static struct snd_soc_machine smdk2443 = { +static struct snd_soc_card smdk2443 = { .name = "SMDK2443", .dai_link = smdk2443_dai, .num_links = ARRAY_SIZE(smdk2443_dai), }; static struct snd_soc_device smdk2443_snd_ac97_devdata = { - .machine = &smdk2443, + .card = &smdk2443, .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index 92bfaf4774a..8b44f9c8a9f 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c @@ -38,14 +38,14 @@ static struct snd_soc_dai_link sh7760_ac97_dai = { .ops = NULL, }; -static struct snd_soc_machine sh7760_ac97_soc_machine = { +static struct snd_soc_card sh7760_ac97_soc_machine = { .name = "SH7760 AC97", .dai_link = &sh7760_ac97_dai, .num_links = 1, }; static struct snd_soc_device sh7760_ac97_snd_devdata = { - .machine = &sh7760_ac97_soc_machine, + .card = &sh7760_ac97_soc_machine, .platform = &sh7760_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9feaa7b6dc3..c5cb9516fea 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -620,7 +620,7 @@ static struct snd_pcm_ops soc_pcm_ops = { static int soc_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; @@ -644,14 +644,14 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) } /* suspend all pcms */ - for (i = 0; i < machine->num_links; i++) - snd_pcm_suspend_all(machine->dai_link[i].pcm); + for (i = 0; i < card->num_links; i++) + snd_pcm_suspend_all(card->dai_link[i].pcm); - if (machine->suspend_pre) - machine->suspend_pre(pdev, state); + if (card->suspend_pre) + card->suspend_pre(pdev, state); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) @@ -676,14 +676,14 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) if (codec_dev->suspend) codec_dev->suspend(pdev, state); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) cpu_dai->suspend(pdev, cpu_dai); } - if (machine->suspend_post) - machine->suspend_post(pdev, state); + if (card->suspend_post) + card->suspend_post(pdev, state); return 0; } @@ -696,7 +696,7 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_device *socdev = container_of(work, struct snd_soc_device, deferred_resume_work); - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; @@ -709,11 +709,11 @@ static void soc_resume_deferred(struct work_struct *work) dev_info(socdev->dev, "starting resume work\n"); - if (machine->resume_pre) - machine->resume_pre(pdev); + if (card->resume_pre) + card->resume_pre(pdev); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) cpu_dai->resume(pdev, cpu_dai); } @@ -739,16 +739,16 @@ static void soc_resume_deferred(struct work_struct *work) dai->dai_ops.digital_mute(dai, 0); } - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) cpu_dai->resume(pdev, cpu_dai); if (platform->resume) platform->resume(pdev, cpu_dai); } - if (machine->resume_post) - machine->resume_post(pdev); + if (card->resume_post) + card->resume_post(pdev); dev_info(socdev->dev, "resume work completed\n"); @@ -779,18 +779,18 @@ static int soc_probe(struct platform_device *pdev) { int ret = 0, i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - if (machine->probe) { - ret = machine->probe(pdev); + if (card->probe) { + ret = card->probe(pdev); if (ret < 0) return ret; } - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->probe) { ret = cpu_dai->probe(pdev, cpu_dai); if (ret < 0) @@ -825,13 +825,13 @@ platform_err: cpu_dai_err: for (i--; i >= 0; i--) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev, cpu_dai); } - if (machine->remove) - machine->remove(pdev); + if (card->remove) + card->remove(pdev); return ret; } @@ -841,7 +841,7 @@ static int soc_remove(struct platform_device *pdev) { int i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; @@ -853,14 +853,14 @@ static int soc_remove(struct platform_device *pdev) if (codec_dev->remove) codec_dev->remove(pdev); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev, cpu_dai); } - if (machine->remove) - machine->remove(pdev); + if (card->remove) + card->remove(pdev); return 0; } @@ -1212,7 +1212,7 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; int ret = 0, i; mutex_lock(&codec->mutex); @@ -1231,11 +1231,11 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); /* create the pcms */ - for (i = 0; i < machine->num_links; i++) { - ret = soc_new_pcm(socdev, &machine->dai_link[i], i); + for (i = 0; i < card->num_links; i++) { + ret = soc_new_pcm(socdev, &card->dai_link[i], i); if (ret < 0) { printk(KERN_ERR "asoc: can't create pcm %s\n", - machine->dai_link[i].stream_name); + card->dai_link[i].stream_name); mutex_unlock(&codec->mutex); return ret; } @@ -1258,26 +1258,26 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms); int snd_soc_register_card(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; int ret = 0, i, ac97 = 0, err = 0; - for (i = 0; i < machine->num_links; i++) { - if (socdev->machine->dai_link[i].init) { - err = socdev->machine->dai_link[i].init(codec); + for (i = 0; i < card->num_links; i++) { + if (card->dai_link[i].init) { + err = card->dai_link[i].init(codec); if (err < 0) { printk(KERN_ERR "asoc: failed to init %s\n", - socdev->machine->dai_link[i].stream_name); + card->dai_link[i].stream_name); continue; } } - if (socdev->machine->dai_link[i].codec_dai->type == + if (card->dai_link[i].codec_dai->type == SND_SOC_DAI_AC97_BUS) ac97 = 1; } snprintf(codec->card->shortname, sizeof(codec->card->shortname), - "%s", machine->name); + "%s", card->name); snprintf(codec->card->longname, sizeof(codec->card->longname), - "%s (%s)", machine->name, codec->name); + "%s (%s)", card->name, codec->name); ret = snd_card_register(codec->card); if (ret < 0) { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0fecbb44726..61d7d85aa57 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1402,11 +1402,11 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, enum snd_soc_bias_level level) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; int ret = 0; - if (machine->set_bias_level) - ret = machine->set_bias_level(machine, level); + if (card->set_bias_level) + ret = card->set_bias_level(card, level); if (ret == 0 && codec->set_bias_level) ret = codec->set_bias_level(codec, level); -- cgit v1.2.3 From bd903bde7e0ad017cb87a228f451e05011e6d302 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 19 Nov 2008 19:16:05 +0000 Subject: ASoC: Add abbreviation to maintainers for searchability Signed-off-by: Mark Brown --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 16202c8ac68..0c71569634d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3907,7 +3907,7 @@ M: tiwai@suse.de L: alsa-devel@alsa-project.org (subscribers-only) S: Maintained -SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT +SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC) P: Liam Girdwood M: lrg@slimlogic.co.uk P: Mark Brown -- cgit v1.2.3 From faab5a32f4d0784d6bde57963267be0453be3546 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Thu, 20 Nov 2008 15:39:27 +0100 Subject: ASoC: ssm2602: Fix priv substreams refs Clean up our record of the active streams in shutdown(), fixing subsequent failures of snd_pcm_hw_constraints_complete after closure of a stream. NOTE: - The ssm2602 allows pairs of non-matching PB/REC rates. - This is a fix for less evil: The logic is flawed (e.g. the slave might startup before the master's rate and sample_bits are set). Signed-off-by: Karl Beldan Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 44ef0dacd56..0e522e718df 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -292,9 +292,15 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct ssm2602_priv *ssm2602 = codec->private_data; + struct i2c_client *i2c = codec->control_data; u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; int i = get_coeff(ssm2602->sysclk, params_rate(params)); + if (substream == ssm2602->slave_substream) { + dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); + return 0; + } + /*no match is found*/ if (i == ARRAY_SIZE(coeff_div)) return -EINVAL; @@ -330,13 +336,19 @@ static int ssm2602_startup(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct ssm2602_priv *ssm2602 = codec->private_data; + struct i2c_client *i2c = codec->control_data; struct snd_pcm_runtime *master_runtime; /* The DAI has shared clocks so if we already have a playback or * capture going then constrain this substream to match it. + * TODO: the ssm2602 allows pairs of non-matching PB/REC rates */ if (ssm2602->master_substream) { master_runtime = ssm2602->master_substream->runtime; + dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", + master_runtime->sample_bits, + master_runtime->rate); + snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, master_runtime->rate, @@ -370,9 +382,15 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; + struct ssm2602_priv *ssm2602 = codec->private_data; /* deactivate */ if (!codec->active) ssm2602_write(codec, SSM2602_ACTIVE, 0); + + if (ssm2602->master_substream == substream) + ssm2602->master_substream = ssm2602->slave_substream; + + ssm2602->slave_substream = NULL; } static int ssm2602_mute(struct snd_soc_dai *dai, int mute) -- cgit v1.2.3 From 5de27b6cc0a8a1d27158ec9047cb5981745edfc0 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Thu, 20 Nov 2008 15:39:31 +0100 Subject: ASoC: ssm2602: Update supported stream formats Signed-off-by: Karl Beldan Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 0e522e718df..56dc1c9c7c5 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -514,6 +514,9 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000) +#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + struct snd_soc_dai ssm2602_dai = { .name = "SSM2602", .playback = { @@ -521,13 +524,13 @@ struct snd_soc_dai ssm2602_dai = { .channels_min = 2, .channels_max = 2, .rates = SSM2602_RATES, - .formats = SNDRV_PCM_FMTBIT_S32_LE,}, + .formats = SSM2602_FORMATS,}, .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SSM2602_RATES, - .formats = SNDRV_PCM_FMTBIT_S32_LE,}, + .formats = SSM2602_FORMATS,}, .ops = { .startup = ssm2602_startup, .prepare = ssm2602_pcm_prepare, -- cgit v1.2.3 From a47cbe7263236691ee0bbc392f7fd4ec0da1159f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 23 Jul 2008 14:03:07 +0100 Subject: ASoC: Move DAI structure definitions into new soc-dai.h ASoC v2 factors most of the contents of soc.h out into separate headers, including soc-dai.h for the DAI. Factor the existing DAI API out into this file in order to prepare for backporting of the ASoC v2 DAI API. Also backport some of Liam's improvements to the documentation. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 209 ++++++++++++++++++++++++++++++++++++++++++++++++ include/sound/soc.h | 148 +--------------------------------- 2 files changed, 211 insertions(+), 146 deletions(-) create mode 100644 include/sound/soc-dai.h diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h new file mode 100644 index 00000000000..08b8f7025c6 --- /dev/null +++ b/include/sound/soc-dai.h @@ -0,0 +1,209 @@ +/* + * linux/sound/soc-dai.h -- ALSA SoC Layer + * + * Copyright: 2005-2008 Wolfson Microelectronics. PLC. + * + * 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. + * + * Digital Audio Interface (DAI) API. + */ + +#ifndef __LINUX_SND_SOC_DAI_H +#define __LINUX_SND_SOC_DAI_H + + +#include + +struct snd_pcm_substream; + +/* + * DAI hardware audio formats. + * + * Describes the physical PCM data formating and clocking. Add new formats + * to the end. + */ +#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ +#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right Justified mode */ +#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ +#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM LRC */ +#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM LRC */ +#define SND_SOC_DAIFMT_AC97 5 /* AC97 */ + +/* left and right justified also known as MSB and LSB respectively */ +#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J +#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J + +/* + * DAI Clock gating. + * + * DAI bit clocks can be be gated (disabled) when not the DAI is not + * sending or receiving PCM data in a frame. This can be used to save power. + */ +#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ +#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated */ + +/* + * DAI Left/Right Clocks. + * + * Specifies whether the DAI can support different samples for similtanious + * playback and capture. This usually requires a seperate physical frame + * clock for playback and capture. + */ +#define SND_SOC_DAIFMT_SYNC (0 << 5) /* Tx FRM = Rx FRM */ +#define SND_SOC_DAIFMT_ASYNC (1 << 5) /* Tx FRM ~ Rx FRM */ + +/* + * TDM + * + * Time Division Multiplexing. Allows PCM data to be multplexed with other + * data on the DAI. + */ +#define SND_SOC_DAIFMT_TDM (1 << 6) + +/* + * DAI hardware signal inversions. + * + * Specifies whether the DAI can also support inverted clocks for the specified + * format. + */ +#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ +#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ +#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ +#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ + +/* + * DAI hardware clock masters. + * + * This is wrt the codec, the inverse is true for the interface + * i.e. if the codec is clk and frm master then the interface is + * clk and frame slave. + */ +#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ +#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ +#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ +#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ + +#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f +#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 +#define SND_SOC_DAIFMT_INV_MASK 0x0f00 +#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 + +/* + * Master Clock Directions + */ +#define SND_SOC_CLOCK_IN 0 +#define SND_SOC_CLOCK_OUT 1 + +struct snd_soc_dai_ops; +struct snd_soc_dai; +struct snd_ac97_bus_ops; + +/* Digital Audio Interface clocking API.*/ +int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir); + +int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, + int div_id, int div); + +int snd_soc_dai_set_pll(struct snd_soc_dai *dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + +/* Digital Audio interface formatting */ +int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); + +int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int mask, int slots); + +int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); + +/* Digital Audio Interface mute */ +int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); + +/* + * Digital Audio Interface. + * + * Describes the Digital Audio Interface in terms of it's ALSA, DAI and AC97 + * operations an capabilities. Codec and platfom drivers will register a this + * structure for every DAI they have. + * + * This structure covers the clocking, formating and ALSA operations for each + * interface a + */ +struct snd_soc_dai_ops { + /* + * DAI clocking configuration, all optional. + * Called by soc_card drivers, normally in their hw_params. + */ + int (*set_sysclk)(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir); + int (*set_pll)(struct snd_soc_dai *dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); + + /* + * DAI format configuration + * Called by soc_card drivers, normally in their hw_params. + */ + int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); + int (*set_tdm_slot)(struct snd_soc_dai *dai, + unsigned int mask, int slots); + int (*set_tristate)(struct snd_soc_dai *dai, int tristate); + + /* + * DAI digital mute - optional. + * Called by soc-core to minimise any pops. + */ + int (*digital_mute)(struct snd_soc_dai *dai, int mute); +}; + +/* + * Digital Audio Interface runtime data. + * + * Holds runtime data for a DAI. + */ +struct snd_soc_dai { + /* DAI description */ + char *name; + unsigned int id; + unsigned char type; + + /* DAI callbacks */ + int (*probe)(struct platform_device *pdev, + struct snd_soc_dai *dai); + void (*remove)(struct platform_device *pdev, + struct snd_soc_dai *dai); + int (*suspend)(struct platform_device *pdev, + struct snd_soc_dai *dai); + int (*resume)(struct platform_device *pdev, + struct snd_soc_dai *dai); + + /* ops */ + struct snd_soc_ops ops; + struct snd_soc_dai_ops dai_ops; + + /* DAI capabilities */ + struct snd_soc_pcm_stream capture; + struct snd_soc_pcm_stream playback; + + /* DAI runtime info */ + struct snd_pcm_runtime *runtime; + struct snd_soc_codec *codec; + unsigned int active; + unsigned char pop_wait:1; + void *dma_data; + + /* DAI private data */ + void *private_data; + + /* parent codec/platform */ + union { + struct snd_soc_codec *codec; + struct snd_soc_platform *platform; + }; + + struct list_head list; +}; + +#endif diff --git a/include/sound/soc.h b/include/sound/soc.h index 3be17b3c650..e4465f73aa4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -151,76 +151,6 @@ enum snd_soc_bias_level { #define SND_SOC_DAI_PCM 0x4 #define SND_SOC_DAI_AC97_BUS 0x8 /* for custom i.e. non ac97_codec.c */ -/* - * DAI hardware audio formats - */ -#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ -#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right justified mode */ -#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ -#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM or LRC */ -#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM or LRC */ -#define SND_SOC_DAIFMT_AC97 5 /* AC97 */ - -#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J -#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J - -/* - * DAI Gating - */ -#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ -#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */ - -/* - * DAI Sync - * Synchronous LR (Left Right) clocks and Frame signals. - */ -#define SND_SOC_DAIFMT_SYNC (0 << 5) /* Tx FRM = Rx FRM */ -#define SND_SOC_DAIFMT_ASYNC (1 << 5) /* Tx FRM ~ Rx FRM */ - -/* - * TDM - */ -#define SND_SOC_DAIFMT_TDM (1 << 6) - -/* - * DAI hardware signal inversions - */ -#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bclk + frm */ -#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ -#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ -#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ - -/* - * DAI hardware clock masters - * This is wrt the codec, the inverse is true for the interface - * i.e. if the codec is clk and frm master then the interface is - * clk and frame slave. - */ -#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ -#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ -#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ -#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ - -#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f -#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 -#define SND_SOC_DAIFMT_INV_MASK 0x0f00 -#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 - - -/* - * Master Clock Directions - */ -#define SND_SOC_CLOCK_IN 0 -#define SND_SOC_CLOCK_OUT 1 - -/* - * AC97 codec ID's bitmask - */ -#define SND_SOC_DAI_AC97_ID0 (1 << 0) -#define SND_SOC_DAI_AC97_ID1 (1 << 1) -#define SND_SOC_DAI_AC97_ID2 (1 << 2) -#define SND_SOC_DAI_AC97_ID3 (1 << 3) - struct snd_soc_device; struct snd_soc_pcm_stream; struct snd_soc_ops; @@ -260,27 +190,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, struct snd_ac97_bus_ops *ops, int num); void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); -/* Digital Audio Interface clocking API.*/ -int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir); - -int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, - int div_id, int div); - -int snd_soc_dai_set_pll(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out); - -/* Digital Audio interface formatting */ -int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); - -int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots); - -int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); - -/* Digital Audio Interface mute */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); - /* *Controls */ @@ -338,61 +247,6 @@ struct snd_soc_ops { int (*trigger)(struct snd_pcm_substream *, int); }; -/* ASoC DAI ops */ -struct snd_soc_dai_ops { - /* DAI clocking configuration */ - int (*set_sysclk)(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir); - int (*set_pll)(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out); - int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); - - /* DAI format configuration */ - int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); - int (*set_tdm_slot)(struct snd_soc_dai *dai, - unsigned int mask, int slots); - int (*set_tristate)(struct snd_soc_dai *dai, int tristate); - - /* digital mute */ - int (*digital_mute)(struct snd_soc_dai *dai, int mute); -}; - -/* SoC DAI (Digital Audio Interface) */ -struct snd_soc_dai { - /* DAI description */ - char *name; - unsigned int id; - unsigned char type; - - /* DAI callbacks */ - int (*probe)(struct platform_device *pdev, - struct snd_soc_dai *dai); - void (*remove)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*suspend)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*resume)(struct platform_device *pdev, - struct snd_soc_dai *dai); - - /* ops */ - struct snd_soc_ops ops; - struct snd_soc_dai_ops dai_ops; - - /* DAI capabilities */ - struct snd_soc_pcm_stream capture; - struct snd_soc_pcm_stream playback; - - /* DAI runtime info */ - struct snd_pcm_runtime *runtime; - struct snd_soc_codec *codec; - unsigned int active; - unsigned char pop_wait:1; - void *dma_data; - - /* DAI private data */ - void *private_data; -}; - /* SoC Audio Codec */ struct snd_soc_codec { char *name; @@ -543,4 +397,6 @@ struct soc_enum { void *dapm; }; +#include + #endif -- cgit v1.2.3 From dee89c4d94433520e4e3977ae203d4cfbfe385fb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 22:11:38 +0000 Subject: ASoC: Merge snd_soc_ops into snd_soc_dai_ops Liam Girdwood's ASoC v2 work avoids having two different ops structures for DAIs by merging the members of struct snd_soc_ops into struct snd_soc_dai_ops, allowing per DAI configuration for everything. Backport this change. This paves the way for future work allowing any combination of DAIs to be connected rather than having fixed purpose CODEC and CPU DAIs and only allowing CODEC<->CPU interconnections. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 20 +++++++++-- sound/soc/atmel/atmel_ssc_dai.c | 21 +++++------ sound/soc/au1x/psc-ac97.c | 5 +-- sound/soc/au1x/psc-i2s.c | 8 ++--- sound/soc/blackfin/bf5xx-i2s.c | 12 ++++--- sound/soc/codecs/ac97.c | 3 +- sound/soc/codecs/ak4535.c | 5 ++- sound/soc/codecs/cs4270.c | 11 +++--- sound/soc/codecs/ssm2602.c | 14 ++++---- sound/soc/codecs/tlv320aic23.c | 19 +++++----- sound/soc/codecs/tlv320aic26.c | 5 ++- sound/soc/codecs/tlv320aic3x.c | 5 ++- sound/soc/codecs/twl4030.c | 5 ++- sound/soc/codecs/uda134x.c | 12 +++---- sound/soc/codecs/uda1380.c | 15 ++++---- sound/soc/codecs/wm8510.c | 5 ++- sound/soc/codecs/wm8580.c | 12 +++---- sound/soc/codecs/wm8728.c | 5 ++- sound/soc/codecs/wm8731.c | 11 +++--- sound/soc/codecs/wm8750.c | 5 ++- sound/soc/codecs/wm8753.c | 25 ++++++------- sound/soc/codecs/wm8900.c | 5 ++- sound/soc/codecs/wm8903.c | 11 +++--- sound/soc/codecs/wm8971.c | 5 ++- sound/soc/codecs/wm8990.c | 6 ++-- sound/soc/codecs/wm9712.c | 6 ++-- sound/soc/codecs/wm9713.c | 21 +++++------ sound/soc/davinci/davinci-i2s.c | 12 ++++--- sound/soc/davinci/davinci-sffsdr.c | 3 +- sound/soc/fsl/fsl_ssi.c | 14 ++++---- sound/soc/fsl/mpc5200_psc_i2s.c | 17 +++++---- sound/soc/omap/omap-mcbsp.c | 14 ++++---- sound/soc/omap/omap2evm.c | 3 +- sound/soc/pxa/pxa-ssp.c | 20 +++++------ sound/soc/pxa/pxa2xx-ac97.c | 9 +++-- sound/soc/pxa/pxa2xx-i2s.c | 15 ++++---- sound/soc/s3c24xx/s3c2412-i2s.c | 8 ++--- sound/soc/s3c24xx/s3c2443-ac97.c | 8 +++-- sound/soc/s3c24xx/s3c24xx-i2s.c | 9 ++--- sound/soc/sh/hac.c | 3 +- sound/soc/sh/ssi.c | 16 ++++----- sound/soc/soc-core.c | 74 +++++++++++++++++++------------------- 42 files changed, 265 insertions(+), 237 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 08b8f7025c6..f51cb55902f 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -156,6 +156,23 @@ struct snd_soc_dai_ops { * Called by soc-core to minimise any pops. */ int (*digital_mute)(struct snd_soc_dai *dai, int mute); + + /* + * ALSA PCM audio operations - all optional. + * Called by soc-core during audio PCM operations. + */ + int (*startup)(struct snd_pcm_substream *, + struct snd_soc_dai *); + void (*shutdown)(struct snd_pcm_substream *, + struct snd_soc_dai *); + int (*hw_params)(struct snd_pcm_substream *, + struct snd_pcm_hw_params *, struct snd_soc_dai *); + int (*hw_free)(struct snd_pcm_substream *, + struct snd_soc_dai *); + int (*prepare)(struct snd_pcm_substream *, + struct snd_soc_dai *); + int (*trigger)(struct snd_pcm_substream *, int, + struct snd_soc_dai *); }; /* @@ -180,8 +197,7 @@ struct snd_soc_dai { struct snd_soc_dai *dai); /* ops */ - struct snd_soc_ops ops; - struct snd_soc_dai_ops dai_ops; + struct snd_soc_dai_ops ops; /* DAI capabilities */ struct snd_soc_pcm_stream capture; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index d290b789491..916f73b9a18 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -202,7 +202,8 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) /* * Startup. Only that one substream allowed in each direction. */ -static int atmel_ssc_startup(struct snd_pcm_substream *substream) +static int atmel_ssc_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; @@ -231,7 +232,8 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream) * Shutdown. Clear DMA parameters and shutdown the SSC if there * are no other substreams open. */ -static void atmel_ssc_shutdown(struct snd_pcm_substream *substream) +static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; @@ -332,7 +334,8 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, * Configure the SSC. */ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); int id = rtd->dai->cpu_dai->id; @@ -600,7 +603,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, } -static int atmel_ssc_prepare(struct snd_pcm_substream *substream) +static int atmel_ssc_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; @@ -715,8 +719,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { .startup = atmel_ssc_startup, .shutdown = atmel_ssc_shutdown, .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params,}, - .dai_ops = { + .hw_params = atmel_ssc_hw_params, .set_fmt = atmel_ssc_set_dai_fmt, .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, .private_data = &ssc_info[0], @@ -741,8 +744,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { .startup = atmel_ssc_startup, .shutdown = atmel_ssc_shutdown, .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params,}, - .dai_ops = { + .hw_params = atmel_ssc_hw_params, .set_fmt = atmel_ssc_set_dai_fmt, .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, .private_data = &ssc_info[1], @@ -766,8 +768,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { .startup = atmel_ssc_startup, .shutdown = atmel_ssc_shutdown, .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params,}, - .dai_ops = { + .hw_params = atmel_ssc_hw_params, .set_fmt = atmel_ssc_set_dai_fmt, .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, .private_data = &ssc_info[2], diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 57facbad682..ad60a6042ca 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -160,7 +160,8 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; @@ -210,7 +211,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, } static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, - int cmd) + int cmd, struct snd_soc_dai *dai) { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 9384702c7eb..05a5acbb16a 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -116,7 +116,8 @@ out: } static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; @@ -240,7 +241,8 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) return 0; } -static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; int ret, stype = SUBSTREAM_TYPE(substream); @@ -389,8 +391,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = { .ops = { .trigger = au1xpsc_i2s_trigger, .hw_params = au1xpsc_i2s_hw_params, - }, - .dai_ops = { .set_fmt = au1xpsc_i2s_set_fmt, }, }; diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index e020c160ee4..4e675b55b18 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -132,7 +132,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return ret; } -static int bf5xx_i2s_startup(struct snd_pcm_substream *substream) +static int bf5xx_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); @@ -142,7 +143,8 @@ static int bf5xx_i2s_startup(struct snd_pcm_substream *substream) } static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { int ret = 0; @@ -193,7 +195,8 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream) +static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); bf5xx_i2s.counter--; @@ -307,8 +310,7 @@ struct snd_soc_dai bf5xx_i2s_dai = { .ops = { .startup = bf5xx_i2s_startup, .shutdown = bf5xx_i2s_shutdown, - .hw_params = bf5xx_i2s_hw_params,}, - .dai_ops = { + .hw_params = bf5xx_i2s_hw_params, .set_fmt = bf5xx_i2s_set_dai_fmt, }, }; diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index bd1ebdc6c86..8a93aff359d 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -24,7 +24,8 @@ #define AC97_VERSION "0.6" -static int ac97_prepare(struct snd_pcm_substream *substream) +static int ac97_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 2a89b5888e1..c742290e553 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -339,7 +339,8 @@ static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, } static int ak4535_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -451,8 +452,6 @@ struct snd_soc_dai ak4535_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .hw_params = ak4535_hw_params, - }, - .dai_ops = { .set_fmt = ak4535_set_dai_fmt, .digital_mute = ak4535_mute, .set_sysclk = ak4535_set_dai_sysclk, diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 0ff476d7057..7507d468b20 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -360,13 +360,14 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, /* * Program the CS4270 with the given hardware parameters. * - * The .dai_ops functions are used to provide board-specific data, like + * The .ops functions are used to provide board-specific data, like * input frequencies, to this driver. This function takes that information, * combines it with the hardware parameters provided, and programs the * hardware accordingly. */ static int cs4270_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -710,10 +711,10 @@ static int cs4270_probe(struct platform_device *pdev) if (codec->control_data) { /* Initialize codec ops */ cs4270_dai.ops.hw_params = cs4270_hw_params; - cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk; - cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt; + cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk; + cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt; #ifdef CONFIG_SND_SOC_CS4270_HWMUTE - cs4270_dai.dai_ops.digital_mute = cs4270_mute; + cs4270_dai.ops.digital_mute = cs4270_mute; #endif } else printk(KERN_INFO "cs4270: no I2C device found, " diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 56dc1c9c7c5..0c5884ea1b0 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -285,7 +285,8 @@ static inline int get_coeff(int mclk, int rate) } static int ssm2602_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { u16 srate; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -330,7 +331,8 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, return 0; } -static int ssm2602_startup(struct snd_pcm_substream *substream) +static int ssm2602_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -366,7 +368,8 @@ static int ssm2602_startup(struct snd_pcm_substream *substream) return 0; } -static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) +static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -377,7 +380,8 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static void ssm2602_shutdown(struct snd_pcm_substream *substream) +static void ssm2602_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -536,8 +540,6 @@ struct snd_soc_dai ssm2602_dai = { .prepare = ssm2602_pcm_prepare, .hw_params = ssm2602_hw_params, .shutdown = ssm2602_shutdown, - }, - .dai_ops = { .digital_mute = ssm2602_mute, .set_sysclk = ssm2602_set_dai_sysclk, .set_fmt = ssm2602_set_dai_fmt, diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index c903e4f48dc..a4e13d0688c 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -418,7 +418,8 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) } static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -465,7 +466,8 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, return 0; } -static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream) +static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -477,7 +479,8 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static void tlv320aic23_shutdown(struct snd_pcm_substream *substream) +static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -613,12 +616,10 @@ struct snd_soc_dai tlv320aic23_dai = { .prepare = tlv320aic23_pcm_prepare, .hw_params = tlv320aic23_hw_params, .shutdown = tlv320aic23_shutdown, - }, - .dai_ops = { - .digital_mute = tlv320aic23_mute, - .set_fmt = tlv320aic23_set_dai_fmt, - .set_sysclk = tlv320aic23_set_dai_sysclk, - } + .digital_mute = tlv320aic23_mute, + .set_fmt = tlv320aic23_set_dai_fmt, + .set_sysclk = tlv320aic23_set_dai_sysclk, + } }; EXPORT_SYMBOL_GPL(tlv320aic23_dai); diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index bed8a9e63dd..6b7ddfc9257 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -125,7 +125,8 @@ static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, * Digital Audio Interface Operations */ static int aic26_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -287,8 +288,6 @@ struct snd_soc_dai aic26_dai = { }, .ops = { .hw_params = aic26_hw_params, - }, - .dai_ops = { .digital_mute = aic26_mute, .set_sysclk = aic26_set_sysclk, .set_fmt = aic26_set_fmt, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index cff276ee261..b76bcc3c411 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -694,7 +694,8 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) } static int aic3x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1009,8 +1010,6 @@ struct snd_soc_dai aic3x_dai = { .formats = AIC3X_FORMATS,}, .ops = { .hw_params = aic3x_hw_params, - }, - .dai_ops = { .digital_mute = aic3x_mute, .set_sysclk = aic3x_set_dai_sysclk, .set_fmt = aic3x_set_dai_fmt, diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c778eb446a5..33489515b92 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -343,7 +343,8 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, } static int twl4030_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -523,8 +524,6 @@ struct snd_soc_dai twl4030_dai = { .formats = TWL4030_FORMATS,}, .ops = { .hw_params = twl4030_hw_params, - }, - .dai_ops = { .set_sysclk = twl4030_set_dai_sysclk, .set_fmt = twl4030_set_dai_fmt, } diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 69ef521a2ed..91f333cdc7c 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -168,7 +168,8 @@ static int uda134x_mute(struct snd_soc_dai *dai, int mute) return 0; } -static int uda134x_startup(struct snd_pcm_substream *substream) +static int uda134x_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -200,7 +201,8 @@ static int uda134x_startup(struct snd_pcm_substream *substream) return 0; } -static void uda134x_shutdown(struct snd_pcm_substream *substream) +static void uda134x_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -214,7 +216,8 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream) } static int uda134x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -484,9 +487,6 @@ struct snd_soc_dai uda134x_dai = { .startup = uda134x_startup, .shutdown = uda134x_shutdown, .hw_params = uda134x_hw_params, - }, - /* DAI operations */ - .dai_ops = { .digital_mute = uda134x_mute, .set_sysclk = uda134x_set_dai_sysclk, .set_fmt = uda134x_set_dai_fmt, diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index a69ee72a7af..330877c7069 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -407,7 +407,8 @@ static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, * when the DAI is being clocked by the CPU DAI. It's up to the * machine and cpu DAI driver to do this before we are called. */ -static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) +static int uda1380_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -439,7 +440,8 @@ static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) } static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -477,7 +479,8 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) +static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -560,8 +563,6 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { .digital_mute = uda1380_mute, .set_fmt = uda1380_set_dai_fmt, }, @@ -579,8 +580,6 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { .digital_mute = uda1380_mute, .set_fmt = uda1380_set_dai_fmt, }, @@ -598,8 +597,6 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { .set_fmt = uda1380_set_dai_fmt, }, }, diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index d8ca2da8d63..173b66c0c76 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -463,7 +463,8 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -585,8 +586,6 @@ struct snd_soc_dai wm8510_dai = { .formats = WM8510_FORMATS,}, .ops = { .hw_params = wm8510_pcm_hw_params, - }, - .dai_ops = { .digital_mute = wm8510_mute, .set_fmt = wm8510_set_dai_fmt, .set_clkdiv = wm8510_set_dai_clkdiv, diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index cbcd7c324ab..220d4b68904 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -548,13 +548,13 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai_link *dai = rtd->dai; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id); + u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); paifb &= ~WM8580_AIF_LENGTH_MASK; /* bit size */ @@ -574,7 +574,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb); + wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb); return 0; } @@ -798,8 +798,6 @@ struct snd_soc_dai wm8580_dai[] = { }, .ops = { .hw_params = wm8580_paif_hw_params, - }, - .dai_ops = { .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, @@ -818,8 +816,6 @@ struct snd_soc_dai wm8580_dai[] = { }, .ops = { .hw_params = wm8580_paif_hw_params, - }, - .dai_ops = { .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 3e39dea6124..71949bd320d 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -147,7 +147,8 @@ static int wm8728_mute(struct snd_soc_dai *dai, int mute) } static int wm8728_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -269,8 +270,6 @@ struct snd_soc_dai wm8728_dai = { }, .ops = { .hw_params = wm8728_hw_params, - }, - .dai_ops = { .digital_mute = wm8728_mute, .set_fmt = wm8728_set_dai_fmt, } diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7f8a7e36b33..c0f277053bb 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -264,7 +264,8 @@ static inline int get_coeff(int mclk, int rate) } static int wm8731_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -293,7 +294,8 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) +static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -305,7 +307,8 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static void wm8731_shutdown(struct snd_pcm_substream *substream) +static void wm8731_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -461,8 +464,6 @@ struct snd_soc_dai wm8731_dai = { .prepare = wm8731_pcm_prepare, .hw_params = wm8731_hw_params, .shutdown = wm8731_shutdown, - }, - .dai_ops = { .digital_mute = wm8731_mute, .set_sysclk = wm8731_set_dai_sysclk, .set_fmt = wm8731_set_dai_fmt, diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 9b7296ee5b0..860a1d56830 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -614,7 +614,8 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -709,8 +710,6 @@ struct snd_soc_dai wm8750_dai = { .formats = WM8750_FORMATS,}, .ops = { .hw_params = wm8750_pcm_hw_params, - }, - .dai_ops = { .digital_mute = wm8750_mute, .set_fmt = wm8750_set_dai_fmt, .set_sysclk = wm8750_set_dai_sysclk, diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d426eaa2218..5e4cd3bb824 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -922,7 +922,8 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1155,7 +1156,8 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1323,16 +1325,15 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, + .formats = WM8753_FORMATS}, .capture = { /* dummy for fast DAI switching */ .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, + .formats = WM8753_FORMATS}, .ops = { - .hw_params = wm8753_i2s_hw_params,}, - .dai_ops = { + .hw_params = wm8753_i2s_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode1h_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1356,8 +1357,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_pcm_hw_params,}, - .dai_ops = { + .hw_params = wm8753_pcm_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode1v_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1385,8 +1385,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_pcm_hw_params,}, - .dai_ops = { + .hw_params = wm8753_pcm_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode2_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1410,8 +1409,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params,}, - .dai_ops = { + .hw_params = wm8753_i2s_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode3_4_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1439,8 +1437,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params,}, - .dai_ops = { + .hw_params = wm8753_i2s_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode3_4_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index de016f41e04..d1326be91c8 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -727,7 +727,8 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec) } static int wm8900_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1117,8 +1118,6 @@ struct snd_soc_dai wm8900_dai = { }, .ops = { .hw_params = wm8900_hw_params, - }, - .dai_ops = { .set_clkdiv = wm8900_set_dai_clkdiv, .set_pll = wm8900_set_dai_pll, .set_fmt = wm8900_set_dai_fmt, diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index ce40d787760..efbe8927b7d 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1257,7 +1257,8 @@ static struct { { 0, 0 }, }; -static int wm8903_startup(struct snd_pcm_substream *substream) +static int wm8903_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1298,7 +1299,8 @@ static int wm8903_startup(struct snd_pcm_substream *substream) return 0; } -static void wm8903_shutdown(struct snd_pcm_substream *substream) +static void wm8903_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1317,7 +1319,8 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream) } static int wm8903_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1515,8 +1518,6 @@ struct snd_soc_dai wm8903_dai = { .startup = wm8903_startup, .shutdown = wm8903_shutdown, .hw_params = wm8903_hw_params, - }, - .dai_ops = { .digital_mute = wm8903_digital_mute, .set_fmt = wm8903_set_dai_fmt, .set_sysclk = wm8903_set_dai_sysclk diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index f41a578ddd4..26edcc9d6e8 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -541,7 +541,8 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -634,8 +635,6 @@ struct snd_soc_dai wm8971_dai = { .formats = WM8971_FORMATS,}, .ops = { .hw_params = wm8971_pcm_hw_params, - }, - .dai_ops = { .digital_mute = wm8971_mute, .set_fmt = wm8971_set_dai_fmt, .set_sysclk = wm8971_set_dai_sysclk, diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 2d7b0096d92..13926516d16 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1172,7 +1172,8 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8990_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1362,8 +1363,7 @@ struct snd_soc_dai wm8990_dai = { .rates = WM8990_RATES, .formats = WM8990_FORMATS,}, .ops = { - .hw_params = wm8990_hw_params,}, - .dai_ops = { + .hw_params = wm8990_hw_params, .digital_mute = wm8990_mute, .set_fmt = wm8990_set_dai_fmt, .set_clkdiv = wm8990_set_dai_clkdiv, diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index ffb471e420e..81c38e7ad34 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -487,7 +487,8 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } -static int ac97_prepare(struct snd_pcm_substream *substream) +static int ac97_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -507,7 +508,8 @@ static int ac97_prepare(struct snd_pcm_substream *substream) return ac97_write(codec, reg, runtime->rate); } -static int ac97_aux_prepare(struct snd_pcm_substream *substream) +static int ac97_aux_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 740bf3cde18..a0cc5ac969a 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -928,7 +928,8 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -954,7 +955,8 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) +static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -969,7 +971,8 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) ac97_write(codec, AC97_EXTENDED_MID, status); } -static int ac97_hifi_prepare(struct snd_pcm_substream *substream) +static int ac97_hifi_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -989,7 +992,8 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream) return ac97_write(codec, reg, runtime->rate); } -static int ac97_aux_prepare(struct snd_pcm_substream *substream) +static int ac97_aux_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -1042,8 +1046,7 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { - .prepare = ac97_hifi_prepare,}, - .dai_ops = { + .prepare = ac97_hifi_prepare, .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll,}, }, @@ -1056,8 +1059,7 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { - .prepare = ac97_aux_prepare,}, - .dai_ops = { + .prepare = ac97_aux_prepare, .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll,}, }, @@ -1077,8 +1079,7 @@ struct snd_soc_dai wm9713_dai[] = { .formats = WM9713_PCM_FORMATS,}, .ops = { .hw_params = wm9713_pcm_hw_params, - .shutdown = wm9713_voiceshutdown,}, - .dai_ops = { + .shutdown = wm9713_voiceshutdown, .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll, .set_fmt = wm9713_set_dai_fmt, diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 95df51e803b..7a17cd0ecf6 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -188,7 +188,8 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); } -static int davinci_i2s_startup(struct snd_pcm_substream *substream) +static int davinci_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -285,7 +286,8 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, } static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; @@ -349,7 +351,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int ret = 0; @@ -473,8 +476,7 @@ struct snd_soc_dai davinci_i2s_dai = { .ops = { .startup = davinci_i2s_startup, .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params,}, - .dai_ops = { + .hw_params = davinci_i2s_hw_params, .set_fmt = davinci_i2s_set_dai_fmt, }, }; diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index fa38f9cd350..e95fde1766b 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -34,7 +34,8 @@ #include "davinci-i2s.h" static int sffsdr_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 157a7895ffa..52c290bb47b 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -266,7 +266,8 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) * If this is the first stream open, then grab the IRQ and program most of * the SSI registers. */ -static int fsl_ssi_startup(struct snd_pcm_substream *substream) +static int fsl_ssi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -411,7 +412,8 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream) * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the * clock master. */ -static int fsl_ssi_prepare(struct snd_pcm_substream *substream) +static int fsl_ssi_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -441,7 +443,8 @@ static int fsl_ssi_prepare(struct snd_pcm_substream *substream) * The DMA channel is in external master start and pause mode, which * means the SSI completely controls the flow of data. */ -static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd) +static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -490,7 +493,8 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd) * * Shutdown the SSI if there are no other substreams open. */ -static void fsl_ssi_shutdown(struct snd_pcm_substream *substream) +static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -578,8 +582,6 @@ static struct snd_soc_dai fsl_ssi_dai_template = { .prepare = fsl_ssi_prepare, .shutdown = fsl_ssi_shutdown, .trigger = fsl_ssi_trigger, - }, - .dai_ops = { .set_sysclk = fsl_ssi_set_sysclk, .set_fmt = fsl_ssi_set_fmt, }, diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 94a02eaa482..e2c172f3897 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -187,7 +187,8 @@ static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream) * If this is the first stream open, then grab the IRQ and program most of * the PSC registers. */ -static int psc_i2s_startup(struct snd_pcm_substream *substream) +static int psc_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -220,7 +221,8 @@ static int psc_i2s_startup(struct snd_pcm_substream *substream) } static int psc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -256,7 +258,8 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int psc_i2s_hw_free(struct snd_pcm_substream *substream) +static int psc_i2s_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; @@ -268,7 +271,8 @@ static int psc_i2s_hw_free(struct snd_pcm_substream *substream) * This function is called by ALSA to start, stop, pause, and resume the DMA * transfer of data. */ -static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -383,7 +387,8 @@ static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) * * Shutdown the PSC if there are no other substreams open. */ -static void psc_i2s_shutdown(struct snd_pcm_substream *substream) +static void psc_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -483,8 +488,6 @@ static struct snd_soc_dai psc_i2s_dai_template = { .hw_free = psc_i2s_hw_free, .shutdown = psc_i2s_shutdown, .trigger = psc_i2s_trigger, - }, - .dai_ops = { .set_sysclk = psc_i2s_set_sysclk, .set_fmt = psc_i2s_set_fmt, }, diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 3d4060b00eb..6013898f49b 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -138,7 +138,8 @@ static const unsigned long omap34xx_mcbsp_port[][2] = { static const unsigned long omap34xx_mcbsp_port[][2] = {}; #endif -static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) +static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -151,7 +152,8 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) return err; } -static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) +static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -163,7 +165,8 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) } } -static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) +static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -192,7 +195,8 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) } static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -470,8 +474,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, .shutdown = omap_mcbsp_dai_shutdown, \ .trigger = omap_mcbsp_dai_trigger, \ .hw_params = omap_mcbsp_dai_hw_params, \ - }, \ - .dai_ops = { \ .set_fmt = omap_mcbsp_dai_set_dai_fmt, \ .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \ .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \ diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index 5bea31157a9..7b160f9d83f 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -38,7 +38,8 @@ #include "../codecs/twl4030.h" static int omap2evm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index e2b54b88c38..d0dd6245a20 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -212,7 +212,8 @@ static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = { }, }; -static int pxa_ssp_startup(struct snd_pcm_substream *substream) +static int pxa_ssp_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -228,7 +229,8 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream) return ret; } -static void pxa_ssp_shutdown(struct snd_pcm_substream *substream) +static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -604,7 +606,8 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, * Can be called multiple times by oss emulation. */ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -678,7 +681,8 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, return 0; } -static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd) +static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -806,8 +810,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, .hw_params = pxa_ssp_hw_params, - }, - .dai_ops = { .set_sysclk = pxa_ssp_set_dai_sysclk, .set_clkdiv = pxa_ssp_set_dai_clkdiv, .set_pll = pxa_ssp_set_dai_pll, @@ -840,8 +842,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, .hw_params = pxa_ssp_hw_params, - }, - .dai_ops = { .set_sysclk = pxa_ssp_set_dai_sysclk, .set_clkdiv = pxa_ssp_set_dai_clkdiv, .set_pll = pxa_ssp_set_dai_pll, @@ -875,8 +875,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, .hw_params = pxa_ssp_hw_params, - }, - .dai_ops = { .set_sysclk = pxa_ssp_set_dai_sysclk, .set_clkdiv = pxa_ssp_set_dai_clkdiv, .set_pll = pxa_ssp_set_dai_pll, @@ -910,8 +908,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, .hw_params = pxa_ssp_hw_params, - }, - .dai_ops = { .set_sysclk = pxa_ssp_set_dai_sysclk, .set_clkdiv = pxa_ssp_set_dai_clkdiv, .set_pll = pxa_ssp_set_dai_pll, diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index a7a3a9c5c6f..86667d2f1b7 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -117,7 +117,8 @@ static void pxa2xx_ac97_remove(struct platform_device *pdev, } static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -131,7 +132,8 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, } static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -145,7 +147,8 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, } static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index e758034db5c..9a3e55b4812 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -121,7 +121,8 @@ static struct pxa2xx_gpio gpio_bus[] = { }, }; -static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) +static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -187,7 +188,8 @@ static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, } static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -248,7 +250,8 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int ret = 0; @@ -269,7 +272,8 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) +static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { SACR1 |= SACR1_DRPL; @@ -353,8 +357,7 @@ struct snd_soc_dai pxa_i2s_dai = { .startup = pxa2xx_i2s_startup, .shutdown = pxa2xx_i2s_shutdown, .trigger = pxa2xx_i2s_trigger, - .hw_params = pxa2xx_i2s_hw_params,}, - .dai_ops = { + .hw_params = pxa2xx_i2s_hw_params, .set_fmt = pxa2xx_i2s_set_dai_fmt, .set_sysclk = pxa2xx_i2s_set_dai_sysclk, }, diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index ded7d995a92..360cc2a49d9 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -343,7 +343,8 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; @@ -373,7 +374,8 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; @@ -730,8 +732,6 @@ struct snd_soc_dai s3c2412_i2s_dai = { .ops = { .trigger = s3c2412_i2s_trigger, .hw_params = s3c2412_i2s_hw_params, - }, - .dai_ops = { .set_fmt = s3c2412_i2s_set_fmt, .set_clkdiv = s3c2412_i2s_set_clkdiv, .set_sysclk = s3c2412_i2s_set_sysclk, diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 19c5c3cf5d8..31377821b2c 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -271,7 +271,8 @@ static void s3c2443_ac97_remove(struct platform_device *pdev, } static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -313,7 +314,8 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd) } static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -327,7 +329,7 @@ static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, } static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, - int cmd) + int cmd, struct snd_soc_dai *dai) { u32 ac_glbctrl; diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index c18977bceaf..1bac9dd3dbd 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -243,7 +243,8 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; @@ -279,7 +280,8 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int ret = 0; @@ -475,8 +477,7 @@ struct snd_soc_dai s3c24xx_i2s_dai = { .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .trigger = s3c24xx_i2s_trigger, - .hw_params = s3c24xx_i2s_hw_params,}, - .dai_ops = { + .hw_params = s3c24xx_i2s_hw_params, .set_fmt = s3c24xx_i2s_set_fmt, .set_clkdiv = s3c24xx_i2s_set_clkdiv, .set_sysclk = s3c24xx_i2s_set_sysclk, diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index df7bc345c32..3318071dc80 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -236,7 +236,8 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); static int hac_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id]; diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 55c3464163a..52a233840d2 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -89,7 +89,8 @@ struct ssi_priv { * track usage of the SSI; it is simplex-only so prevent attempts of * concurrent playback + capture. FIXME: any locking required? */ -static int ssi_startup(struct snd_pcm_substream *substream) +static int ssi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -101,7 +102,8 @@ static int ssi_startup(struct snd_pcm_substream *substream) return 0; } -static void ssi_shutdown(struct snd_pcm_substream *substream) +static void ssi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -109,7 +111,8 @@ static void ssi_shutdown(struct snd_pcm_substream *substream) ssi->inuse = 0; } -static int ssi_trigger(struct snd_pcm_substream *substream, int cmd) +static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -129,7 +132,8 @@ static int ssi_trigger(struct snd_pcm_substream *substream, int cmd) } static int ssi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -354,8 +358,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { .shutdown = ssi_shutdown, .trigger = ssi_trigger, .hw_params = ssi_hw_params, - }, - .dai_ops = { .set_sysclk = ssi_set_sysclk, .set_clkdiv = ssi_set_clkdiv, .set_fmt = ssi_set_fmt, @@ -383,8 +385,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { .shutdown = ssi_shutdown, .trigger = ssi_trigger, .hw_params = ssi_hw_params, - }, - .dai_ops = { .set_sysclk = ssi_set_sysclk, .set_clkdiv = ssi_set_clkdiv, .set_fmt = ssi_set_fmt, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c5cb9516fea..43f4060dbe7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -134,7 +134,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) /* startup the audio subsystem */ if (cpu_dai->ops.startup) { - ret = cpu_dai->ops.startup(substream); + ret = cpu_dai->ops.startup(substream, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't open interface %s\n", cpu_dai->name); @@ -151,7 +151,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } if (codec_dai->ops.startup) { - ret = codec_dai->ops.startup(substream); + ret = codec_dai->ops.startup(substream, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't open codec %s\n", codec_dai->name); @@ -248,7 +248,7 @@ codec_dai_err: platform_err: if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream); + cpu_dai->ops.shutdown(substream, cpu_dai); out: mutex_unlock(&pcm_mutex); return ret; @@ -339,10 +339,10 @@ static int soc_codec_close(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(codec_dai, 1); if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream); + cpu_dai->ops.shutdown(substream, cpu_dai); if (codec_dai->ops.shutdown) - codec_dai->ops.shutdown(substream); + codec_dai->ops.shutdown(substream, codec_dai); if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); @@ -406,7 +406,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } if (codec_dai->ops.prepare) { - ret = codec_dai->ops.prepare(substream); + ret = codec_dai->ops.prepare(substream, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: codec DAI prepare error\n"); goto out; @@ -414,7 +414,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } if (cpu_dai->ops.prepare) { - ret = cpu_dai->ops.prepare(substream); + ret = cpu_dai->ops.prepare(substream, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: cpu DAI prepare error\n"); goto out; @@ -491,7 +491,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } if (codec_dai->ops.hw_params) { - ret = codec_dai->ops.hw_params(substream, params); + ret = codec_dai->ops.hw_params(substream, params, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't set codec %s hw params\n", codec_dai->name); @@ -500,7 +500,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } if (cpu_dai->ops.hw_params) { - ret = cpu_dai->ops.hw_params(substream, params); + ret = cpu_dai->ops.hw_params(substream, params, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: interface %s hw params failed\n", cpu_dai->name); @@ -523,11 +523,11 @@ out: platform_err: if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream); + cpu_dai->ops.hw_free(substream, cpu_dai); interface_err: if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream); + codec_dai->ops.hw_free(substream, codec_dai); codec_err: if (machine->ops && machine->ops->hw_free) @@ -566,10 +566,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) /* now free hw params for the DAI's */ if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream); + codec_dai->ops.hw_free(substream, codec_dai); if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream); + cpu_dai->ops.hw_free(substream, cpu_dai); mutex_unlock(&pcm_mutex); return 0; @@ -586,7 +586,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) int ret; if (codec_dai->ops.trigger) { - ret = codec_dai->ops.trigger(substream, cmd); + ret = codec_dai->ops.trigger(substream, cmd, codec_dai); if (ret < 0) return ret; } @@ -598,7 +598,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } if (cpu_dai->ops.trigger) { - ret = cpu_dai->ops.trigger(substream, cmd); + ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai); if (ret < 0) return ret; } @@ -637,10 +637,10 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot); /* mute any active DAC's */ - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; - if (dai->dai_ops.digital_mute && dai->playback.active) - dai->dai_ops.digital_mute(dai, 1); + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *dai = card->dai_link[i].codec_dai; + if (dai->ops.digital_mute && dai->playback.active) + dai->ops.digital_mute(dai, 1); } /* suspend all pcms */ @@ -733,10 +733,10 @@ static void soc_resume_deferred(struct work_struct *work) } /* unmute any active DACs */ - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; - if (dai->dai_ops.digital_mute && dai->playback.active) - dai->dai_ops.digital_mute(dai, 0); + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *dai = card->dai_link[i].codec_dai; + if (dai->ops.digital_mute && dai->playback.active) + dai->ops.digital_mute(dai, 0); } for (i = 0; i < card->num_links; i++) { @@ -1849,8 +1849,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir); + if (dai->ops.set_sysclk) + return dai->ops.set_sysclk(dai, clk_id, freq, dir); else return -EINVAL; } @@ -1869,8 +1869,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - if (dai->dai_ops.set_clkdiv) - return dai->dai_ops.set_clkdiv(dai, div_id, div); + if (dai->ops.set_clkdiv) + return dai->ops.set_clkdiv(dai, div_id, div); else return -EINVAL; } @@ -1888,8 +1888,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { - if (dai->dai_ops.set_pll) - return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out); + if (dai->ops.set_pll) + return dai->ops.set_pll(dai, pll_id, freq_in, freq_out); else return -EINVAL; } @@ -1905,8 +1905,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->dai_ops.set_fmt) - return dai->dai_ops.set_fmt(dai, fmt); + if (dai->ops.set_fmt) + return dai->ops.set_fmt(dai, fmt); else return -EINVAL; } @@ -1924,8 +1924,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int mask, int slots) { - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_tdm_slot(dai, mask, slots); + if (dai->ops.set_sysclk) + return dai->ops.set_tdm_slot(dai, mask, slots); else return -EINVAL; } @@ -1940,8 +1940,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); */ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) { - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_tristate(dai, tristate); + if (dai->ops.set_sysclk) + return dai->ops.set_tristate(dai, tristate); else return -EINVAL; } @@ -1956,8 +1956,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); */ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) { - if (dai->dai_ops.digital_mute) - return dai->dai_ops.digital_mute(dai, mute); + if (dai->ops.digital_mute) + return dai->ops.digital_mute(dai, mute); else return -EINVAL; } -- cgit v1.2.3 From 2dac9217b26fd0a0a1712386ce2ea1411835ffb7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Nov 2008 14:01:41 +0000 Subject: ASoC: Add Marvell Zylonite machine support Implement support for the Marvell Zylonite PXA3xx reference platform, supporting standard AC97 stereo and AUX interfaces together with the auxiliary I2S interface of the WM9713. The board has two options for the MCLK of the WM9713: either the standard AC97 system clock can be used or the 13MHz CLK_POUT output of the PXA3xx can be used, selected via SW15 on the board. Currently only the AC97 system clock is supported by this driver. Signed-off-by: Mark Brown --- sound/soc/pxa/Makefile | 2 + sound/soc/pxa/zylonite.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 sound/soc/pxa/zylonite.c diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 1a3a36e75bf..08a9f279772 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -17,6 +17,7 @@ snd-soc-e800-objs := e800_wm9712.o snd-soc-spitz-objs := spitz.o snd-soc-em-x270-objs := em-x270.o snd-soc-palm27x-objs := palm27x.o +snd-soc-zylonite-objs := zylonite.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -25,3 +26,4 @@ obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o +obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c new file mode 100644 index 00000000000..842d6500d61 --- /dev/null +++ b/sound/soc/pxa/zylonite.c @@ -0,0 +1,219 @@ +/* + * zylonite.c -- SoC audio for Zylonite + * + * Copyright 2008 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 +#include +#include +#include +#include +#include + +#include "../codecs/wm9713.h" +#include "pxa2xx-pcm.h" +#include "pxa2xx-ac97.h" +#include "pxa-ssp.h" + +static struct snd_soc_card zylonite; + +static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Microphone", NULL), + SND_SOC_DAPM_MIC("Handset Microphone", NULL), + SND_SOC_DAPM_SPK("Multiactor", NULL), + SND_SOC_DAPM_SPK("Headset Earpiece", NULL), +}; + +/* Currently supported audio map */ +static const struct snd_soc_dapm_route audio_map[] = { + + /* Headphone output connected to HPL/HPR */ + { "Headphone", NULL, "HPL" }, + { "Headphone", NULL, "HPR" }, + + /* On-board earpiece */ + { "Headset Earpiece", NULL, "OUT3" }, + + /* Headphone mic */ + { "MIC2A", NULL, "Mic Bias" }, + { "Mic Bias", NULL, "Headset Microphone" }, + + /* On-board mic */ + { "MIC1", NULL, "Mic Bias" }, + { "Mic Bias", NULL, "Handset Microphone" }, + + /* Multiactor differentially connected over SPKL/SPKR */ + { "Multiactor", NULL, "SPKL" }, + { "Multiactor", NULL, "SPKR" }, +}; + +static int zylonite_wm9713_init(struct snd_soc_codec *codec) +{ + /* Currently we only support use of the AC97 clock here. If + * CLK_POUT is selected by SW15 then the clock API will need + * to be used to request and enable it here. + */ + + snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, + ARRAY_SIZE(zylonite_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + /* Static setup for now */ + snd_soc_dapm_enable_pin(codec, "Headphone"); + snd_soc_dapm_enable_pin(codec, "Headset Earpiece"); + + snd_soc_dapm_sync(codec); + return 0; +} + +static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int pll_out = 0; + unsigned int acds = 0; + unsigned int wm9713_div = 0; + int ret = 0; + + switch (params_rate(params)) { + case 8000: + wm9713_div = 12; + pll_out = 2048000; + break; + case 16000: + wm9713_div = 6; + pll_out = 4096000; + break; + case 48000: + default: + wm9713_div = 2; + pll_out = 12288000; + acds = 1; + break; + } + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_tdm_slot(cpu_dai, + params_channels(params), + params_channels(params)); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); + if (ret < 0) + return ret; + + /* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs + * to be set instead. + */ + ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, + WM9713_PCMDIV(wm9713_div)); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops zylonite_voice_ops = { + .hw_params = zylonite_voice_hw_params, +}; + +static struct snd_soc_dai_link zylonite_dai[] = { +{ + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], + .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], + .init = zylonite_wm9713_init, +}, +{ + .name = "AC97 Aux", + .stream_name = "AC97 Aux", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], + .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX], +}, +{ + .name = "WM9713 Voice", + .stream_name = "WM9713 Voice", + .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3], + .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE], + .ops = &zylonite_voice_ops, +}, +}; + +static struct snd_soc_card zylonite = { + .name = "Zylonite", + .dai_link = zylonite_dai, + .num_links = ARRAY_SIZE(zylonite_dai), +}; + +static struct snd_soc_device zylonite_snd_ac97_devdata = { + .card = &zylonite, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm9713, +}; + +static struct platform_device *zylonite_snd_ac97_device; + +static int __init zylonite_init(void) +{ + int ret; + + zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1); + if (!zylonite_snd_ac97_device) + return -ENOMEM; + + platform_set_drvdata(zylonite_snd_ac97_device, + &zylonite_snd_ac97_devdata); + zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev; + + ret = platform_device_add(zylonite_snd_ac97_device); + if (ret != 0) + platform_device_put(zylonite_snd_ac97_device); + + return ret; +} + +static void __exit zylonite_exit(void) +{ + platform_device_unregister(zylonite_snd_ac97_device); +} + +module_init(zylonite_init); +module_exit(zylonite_exit); + +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 0c758bdd678860fff3c4b600ec6f134e43526850 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 21 Nov 2008 14:31:33 +0200 Subject: ASoC: OMAP: Fix preprocessor filled DAI name in McBSP DAI Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6013898f49b..2eeb135c1e4 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -454,7 +454,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, #define OMAP_MCBSP_DAI_BUILDER(link_id) \ { \ - .name = "omap-mcbsp-dai-(link_id)", \ + .name = "omap-mcbsp-dai-"#link_id, \ .id = (link_id), \ .type = SND_SOC_DAI_I2S, \ .playback = { \ -- cgit v1.2.3 From 0e734ad5d16ad1d87a428a30d117bb3541a8e24d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Nov 2008 14:05:48 +0000 Subject: ASoC: Staticise pxa2xx_pcm_ops It's not exported. Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index afcd892cd2f..0f6b7bb2d44 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -69,7 +69,7 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -struct snd_pcm_ops pxa2xx_pcm_ops = { +static struct snd_pcm_ops pxa2xx_pcm_ops = { .open = __pxa2xx_pcm_open, .close = __pxa2xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, -- cgit v1.2.3 From 39639faba98eafeb327a30bc10b7d921c398a59a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Nov 2008 14:28:49 +0000 Subject: ASoC: Improve error reporting for AC97 reset failures Print something a bit more verbose to help make errors a little more obvious. Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 2 +- sound/soc/codecs/wm9712.c | 2 +- sound/soc/codecs/wm9713.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 410fed953c5..1a3ea059a6d 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -238,7 +238,7 @@ static int ad1980_soc_probe(struct platform_device *pdev) ret = ad1980_reset(codec, 0); if (ret < 0) { - printk(KERN_ERR "AC97 link error\n"); + printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); goto reset_err; } diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 81c38e7ad34..6e3e0f34017 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -690,7 +690,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) ret = wm9712_reset(codec, 0); if (ret < 0) { - printk(KERN_ERR "AC97 link error\n"); + printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n"); goto reset_err; } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index a0cc5ac969a..7be811a3b02 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1243,7 +1243,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) wm9713_reset(codec, 0); ret = wm9713_reset(codec, 1); if (ret < 0) { - printk(KERN_ERR "AC97 link error\n"); + printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n"); goto reset_err; } -- cgit v1.2.3 From 4f904735c809e44c11f57cd4f82446aac1243e0e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Nov 2008 15:08:23 +0000 Subject: ALSA: ASoC: Fix typo in snd_soc_card update documentation Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/soc/machine.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index 4a9f51e2905..bab7711ce96 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -9,7 +9,7 @@ the audio subsystem with the kernel as a platform device and is represented by the following struct:- /* SoC machine */ -struct snd_soc_card {_ +struct snd_soc_card { char *name; int (*probe)(struct platform_device *pdev); -- cgit v1.2.3 From 55b8bac50a494871594e81a05b37c15e7283f868 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 14:05:29 +0000 Subject: ASoC: Use supplied DAI for WM9713 rather than substream Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 7be811a3b02..a502667fca7 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -931,9 +931,7 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = dai->codec; u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3; switch (params_format(params)) { @@ -958,9 +956,7 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = dai->codec; u16 status; /* Gracefully shut down the voice interface. */ @@ -974,10 +970,8 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, static int ac97_hifi_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; int reg; u16 vra; @@ -995,10 +989,8 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream, static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; u16 vra, xsle; vra = ac97_read(codec, AC97_EXTENDED_STATUS); -- cgit v1.2.3 From f8d05bdbb07458e5f2c6a8281bde08056836fea6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Nov 2008 08:25:45 +0200 Subject: ASoC: TWL4030: Disable soft-volume Keep Soft-volume disabled for now, since if it is enabled the FGAIN volume controls are not working in the current configuration: CODEC_MODE:OPT_MODE = 1 OPTION:ARXR2_EN = 1 OPTION:ARXL2_EN = 1 OPTION:ARXR1_EN = 0 OPTION:ARXL1_VRX_EN = 0 RX_PATH_SEL:RXL1_SEL = 0x0 (or 0x1) RX_PATH_SEL:RXR1_SEL = 0x0 (or 0x1) After the patch, FGAIN volume control works. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 33489515b92..49c7da39497 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -87,7 +87,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_ALC_SET1 (0x2C) */ 0x00, /* REG_ALC_SET2 (0x2D) */ 0x00, /* REG_BOOST_CTL (0x2E) */ - 0x01, /* REG_SOFTVOL_CTL (0x2F) */ + 0x00, /* REG_SOFTVOL_CTL (0x2F) */ 0x00, /* REG_DTMF_FREQSEL (0x30) */ 0x00, /* REG_DTMF_TONEXT1H (0x31) */ 0x00, /* REG_DTMF_TONEXT1L (0x32) */ -- cgit v1.2.3 From c10b82cf085c38f2568609ffb10a6d725130f389 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Nov 2008 13:49:35 +0200 Subject: ASoC: TWL4030: Change the Master volume control to TLV TWL4030 FGAIN volume control has a range: -62 to 0 dB in 1 dB steps, 0 in the FGAIN means mute. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 49c7da39497..498c42f7c6e 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "twl4030.h" @@ -189,10 +190,16 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } +/* + * FGAIN volume control: + * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) + */ +static DECLARE_TLV_DB_SCALE(master_tlv, -6300, 100, 1); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { - SOC_DOUBLE_R("Master Playback Volume", + SOC_DOUBLE_R_TLV("Master Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 0, 0x3f, 0), + 0, 0x3f, 0, master_tlv), SOC_DOUBLE_R("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, 0, 0x1f, 0), -- cgit v1.2.3 From 0d33ea0b0f954dddd3996597c663c111249d4df9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Nov 2008 13:49:36 +0200 Subject: ASoC: TWL4030: Add CGAIN volume control Add CGAIN (Coarse gain control) to TWL4030 codec. The range of the CGAIN is: 0 dB to 12 dB in 6 dB steps. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 498c42f7c6e..91effd341c0 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -196,10 +196,20 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) */ static DECLARE_TLV_DB_SCALE(master_tlv, -6300, 100, 1); +/* + * CGAIN volume control: + * 0 dB to 12 dB in 6 dB steps + * value 2 and 3 means 12 dB + */ +static DECLARE_TLV_DB_SCALE(master_coarse_tlv, 0, 600, 0); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("Master Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, 0, 0x3f, 0, master_tlv), + SOC_DOUBLE_R_TLV("Master PCM Playback Volume", + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, + 6, 0x2, 0, master_coarse_tlv), SOC_DOUBLE_R("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, 0, 0x1f, 0), -- cgit v1.2.3 From b0bd53a7399f65e2d1b37cd44c5003e55b886c1e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Nov 2008 13:49:38 +0200 Subject: ASoC: TWL4030: Add helper function for output gain controls Some of the gain controls in TWL (mostly those which are associated with the outputs) are implemented in an interesting way: 0x0 : Power down (mute) 0x1 : 6dB 0x2 : 0 dB 0x3 : -6 dB Inverting not going to help with these. Custom volsw and volsw_2r get/put functions to handle these gains. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 157 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 91effd341c0..41362314789 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -190,6 +190,163 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } +/* + * Some of the gain controls in TWL (mostly those which are associated with + * the outputs) are implemented in an interesting way: + * 0x0 : Power down (mute) + * 0x1 : 6dB + * 0x2 : 0 dB + * 0x3 : -6 dB + * Inverting not going to help with these. + * Custom volsw and volsw_2r get/put functions to handle these gain bits. + */ +#define SOC_DOUBLE_TLV_TWL4030(xname, xreg, shift_left, shift_right, xmax,\ + xinvert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, \ + .get = snd_soc_get_volsw_twl4030, \ + .put = snd_soc_put_volsw_twl4030, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ + .max = xmax, .invert = xinvert} } +#define SOC_DOUBLE_R_TLV_TWL4030(xname, reg_left, reg_right, xshift, xmax,\ + xinvert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_2r, \ + .get = snd_soc_get_volsw_r2_twl4030,\ + .put = snd_soc_put_volsw_r2_twl4030, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ + .max = xmax, .invert = xinvert} } +#define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \ + SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \ + xinvert, tlv_array) + +static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int rshift = mc->rshift; + int max = mc->max; + int mask = (1 << fls(max)) - 1; + + ucontrol->value.integer.value[0] = + (snd_soc_read(codec, reg) >> shift) & mask; + if (ucontrol->value.integer.value[0]) + ucontrol->value.integer.value[0] = + max + 1 - ucontrol->value.integer.value[0]; + + if (shift != rshift) { + ucontrol->value.integer.value[1] = + (snd_soc_read(codec, reg) >> rshift) & mask; + if (ucontrol->value.integer.value[1]) + ucontrol->value.integer.value[1] = + max + 1 - ucontrol->value.integer.value[1]; + } + + return 0; +} + +static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int rshift = mc->rshift; + int max = mc->max; + int mask = (1 << fls(max)) - 1; + unsigned short val, val2, val_mask; + + val = (ucontrol->value.integer.value[0] & mask); + + val_mask = mask << shift; + if (val) + val = max + 1 - val; + val = val << shift; + if (shift != rshift) { + val2 = (ucontrol->value.integer.value[1] & mask); + val_mask |= mask << rshift; + if (val2) + val2 = max + 1 - val2; + val |= val2 << rshift; + } + return snd_soc_update_bits(codec, reg, val_mask, val); +} + +static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = mc->reg; + unsigned int reg2 = mc->rreg; + unsigned int shift = mc->shift; + int max = mc->max; + int mask = (1<value.integer.value[0] = + (snd_soc_read(codec, reg) >> shift) & mask; + ucontrol->value.integer.value[1] = + (snd_soc_read(codec, reg2) >> shift) & mask; + + if (ucontrol->value.integer.value[0]) + ucontrol->value.integer.value[0] = + max + 1 - ucontrol->value.integer.value[0]; + if (ucontrol->value.integer.value[1]) + ucontrol->value.integer.value[1] = + max + 1 - ucontrol->value.integer.value[1]; + + return 0; +} + +static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = mc->reg; + unsigned int reg2 = mc->rreg; + unsigned int shift = mc->shift; + int max = mc->max; + int mask = (1 << fls(max)) - 1; + int err; + unsigned short val, val2, val_mask; + + val_mask = mask << shift; + val = (ucontrol->value.integer.value[0] & mask); + val2 = (ucontrol->value.integer.value[1] & mask); + + if (val) + val = max + 1 - val; + if (val2) + val2 = max + 1 - val2; + + val = val << shift; + val2 = val2 << shift; + + err = snd_soc_update_bits(codec, reg, val_mask, val); + if (err < 0) + return err; + + err = snd_soc_update_bits(codec, reg2, val_mask, val2); + return err; +} + /* * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) -- cgit v1.2.3 From 3ba9e10a6d3b6abf5f5952572cff8f8d5a35ae54 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 18:01:05 +0000 Subject: ASoC: Remove DAI type information DAI type information is only ever used within ASoC in order to special case AC97 and for diagnostic purposes. Since modern CPUs and codecs support multi function DAIs which can be configured for several modes it is more trouble than it's worth to maintain anything other than a flag identifying AC97 DAIs so remove the type field and replace it with an ac97_control flag. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- include/sound/soc.h | 8 -------- sound/soc/atmel/atmel_ssc_dai.c | 3 --- sound/soc/au1x/psc-ac97.c | 2 +- sound/soc/au1x/psc-i2s.c | 1 - sound/soc/blackfin/bf5xx-ac97.c | 2 +- sound/soc/blackfin/bf5xx-i2s.c | 1 - sound/soc/codecs/ac97.c | 2 +- sound/soc/codecs/pcm3008.c | 1 - sound/soc/codecs/wm9712.c | 2 +- sound/soc/codecs/wm9713.c | 2 +- sound/soc/davinci/davinci-i2s.c | 1 - sound/soc/fsl/mpc5200_psc_i2s.c | 1 - sound/soc/omap/omap-mcbsp.c | 1 - sound/soc/pxa/pxa-ssp.c | 4 ---- sound/soc/pxa/pxa2xx-ac97.c | 6 +++--- sound/soc/pxa/pxa2xx-i2s.c | 1 - sound/soc/s3c24xx/neo1973_wm8753.c | 1 - sound/soc/s3c24xx/s3c2412-i2s.c | 1 - sound/soc/s3c24xx/s3c2443-ac97.c | 4 ++-- sound/soc/s3c24xx/s3c24xx-i2s.c | 1 - sound/soc/sh/hac.c | 4 ++-- sound/soc/sh/ssi.c | 2 -- sound/soc/soc-core.c | 31 ++++++++----------------------- 24 files changed, 21 insertions(+), 63 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index f51cb55902f..a01a24b1019 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -184,7 +184,7 @@ struct snd_soc_dai { /* DAI description */ char *name; unsigned int id; - unsigned char type; + int ac97_control; /* DAI callbacks */ int (*probe)(struct platform_device *pdev, diff --git a/include/sound/soc.h b/include/sound/soc.h index e4465f73aa4..444f9c21137 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -143,14 +143,6 @@ enum snd_soc_bias_level { SND_SOC_BIAS_OFF, }; -/* - * Digital Audio Interface (DAI) types - */ -#define SND_SOC_DAI_AC97 0x1 -#define SND_SOC_DAI_I2S 0x2 -#define SND_SOC_DAI_PCM 0x4 -#define SND_SOC_DAI_AC97_BUS 0x8 /* for custom i.e. non ac97_codec.c */ - struct snd_soc_device; struct snd_soc_pcm_stream; struct snd_soc_ops; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 916f73b9a18..0bb18dfa949 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -702,7 +702,6 @@ static int atmel_ssc_resume(struct platform_device *pdev, struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { { .name = "atmel-ssc0", .id = 0, - .type = SND_SOC_DAI_PCM, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -727,7 +726,6 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { #if NUM_SSC_DEVICES == 3 { .name = "atmel-ssc1", .id = 1, - .type = SND_SOC_DAI_PCM, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -751,7 +749,6 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { }, { .name = "atmel-ssc2", .id = 2, - .type = SND_SOC_DAI_PCM, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index ad60a6042ca..a0bcfeaf5f8 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -346,7 +346,7 @@ static int au1xpsc_ac97_resume(struct platform_device *pdev, struct snd_soc_dai au1xpsc_ac97_dai = { .name = "au1xpsc_ac97", - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .probe = au1xpsc_ac97_probe, .remove = au1xpsc_ac97_remove, .suspend = au1xpsc_ac97_suspend, diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 05a5acbb16a..f4217e70a78 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -371,7 +371,6 @@ static int au1xpsc_i2s_resume(struct platform_device *pdev, struct snd_soc_dai au1xpsc_i2s_dai = { .name = "au1xpsc_i2s", - .type = SND_SOC_DAI_I2S, .probe = au1xpsc_i2s_probe, .remove = au1xpsc_i2s_remove, .suspend = au1xpsc_i2s_suspend, diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 5dcd3f665ab..709bdf08e39 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -409,7 +409,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, struct snd_soc_dai bfin_ac97_dai = { .name = "bf5xx-ac97", .id = 0, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .probe = bf5xx_ac97_probe, .remove = bf5xx_ac97_remove, .suspend = bf5xx_ac97_suspend, diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 4e675b55b18..6e5036bf924 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -292,7 +292,6 @@ static int bf5xx_i2s_resume(struct platform_device *pdev, struct snd_soc_dai bf5xx_i2s_dai = { .name = "bf5xx-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = bf5xx_i2s_probe, .remove = bf5xx_i2s_remove, .suspend = bf5xx_i2s_suspend, diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 8a93aff359d..c4208c8210c 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -43,7 +43,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai ac97_dai = { .name = "AC97 HiFi", - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .playback = { .stream_name = "AC97 Playback", .channels_min = 1, diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 2b26e1d80c8..651a15eb8c2 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -33,7 +33,6 @@ struct snd_soc_dai pcm3008_dai = { .name = "PCM3008 HiFi", - .type = SND_SOC_DAI_I2S, .playback = { .stream_name = "PCM3008 Playback", .channels_min = 1, diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 6e3e0f34017..40f14061fb7 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -535,7 +535,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai wm9712_dai[] = { { .name = "AC97 HiFi", - .type = SND_SOC_DAI_AC97_BUS, + .ac97_control = 1, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index a502667fca7..9dad0bffcb0 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1024,7 +1024,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai wm9713_dai[] = { { .name = "AC97 HiFi", - .type = SND_SOC_DAI_AC97_BUS, + .ac97_control = 1, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 7a17cd0ecf6..cf31b3bb96c 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -460,7 +460,6 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai davinci_i2s_dai = { .name = "davinci-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = davinci_i2s_probe, .remove = davinci_i2s_remove, .playback = { diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index e2c172f3897..9ad8f9a2d8e 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -469,7 +469,6 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) * psc_i2s_dai_template: template CPU Digital Audio Interface */ static struct snd_soc_dai psc_i2s_dai_template = { - .type = SND_SOC_DAI_I2S, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 2eeb135c1e4..252bc7ebb19 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -456,7 +456,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, { \ .name = "omap-mcbsp-dai-"#link_id, \ .id = (link_id), \ - .type = SND_SOC_DAI_I2S, \ .playback = { \ .channels_min = 2, \ .channels_max = 2, \ diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d0dd6245a20..402fc5ba65e 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -788,7 +788,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { { .name = "pxa2xx-ssp1", .id = 0, - .type = SND_SOC_DAI_PCM, .probe = pxa_ssp_probe, .remove = pxa_ssp_remove, .suspend = pxa_ssp_suspend, @@ -820,7 +819,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { }, { .name = "pxa2xx-ssp2", .id = 1, - .type = SND_SOC_DAI_PCM, .probe = pxa_ssp_probe, .remove = pxa_ssp_remove, .suspend = pxa_ssp_suspend, @@ -853,7 +851,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { { .name = "pxa2xx-ssp3", .id = 2, - .type = SND_SOC_DAI_PCM, .probe = pxa_ssp_probe, .remove = pxa_ssp_remove, .suspend = pxa_ssp_suspend, @@ -886,7 +883,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { { .name = "pxa2xx-ssp4", .id = 3, - .type = SND_SOC_DAI_PCM, .probe = pxa_ssp_probe, .remove = pxa_ssp_remove, .suspend = pxa_ssp_suspend, diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 86667d2f1b7..bffbe288634 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -173,7 +173,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97", .id = 0, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .probe = pxa2xx_ac97_probe, .remove = pxa2xx_ac97_remove, .suspend = pxa2xx_ac97_suspend, @@ -196,7 +196,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97-aux", .id = 1, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .playback = { .stream_name = "AC97 Aux Playback", .channels_min = 1, @@ -215,7 +215,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97-mic", .id = 2, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 9a3e55b4812..f9a9e2ebafa 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -340,7 +340,6 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev, struct snd_soc_dai pxa_i2s_dai = { .name = "pxa2xx-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .suspend = pxa2xx_i2s_suspend, .resume = pxa2xx_i2s_resume, .playback = { diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 528fc3f1b45..3df2224a672 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -548,7 +548,6 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) static struct snd_soc_dai bt_dai = { .name = "Bluetooth", .id = 0, - .type = SND_SOC_DAI_PCM, .playback = { .channels_min = 1, .channels_max = 1, diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 360cc2a49d9..1c741047ae3 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -713,7 +713,6 @@ static int s3c2412_i2s_resume(struct platform_device *pdev, struct snd_soc_dai s3c2412_i2s_dai = { .name = "s3c2412-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = s3c2412_i2s_probe, .suspend = s3c2412_i2s_suspend, .resume = s3c2412_i2s_resume, diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 31377821b2c..41bde6a3883 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -358,7 +358,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { { .name = "s3c2443-ac97", .id = 0, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .probe = s3c2443_ac97_probe, .remove = s3c2443_ac97_remove, .playback = { @@ -380,7 +380,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { { .name = "pxa2xx-ac97-mic", .id = 1, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 1bac9dd3dbd..8d9135f41bc 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -461,7 +461,6 @@ static int s3c24xx_i2s_resume(struct platform_device *pdev, struct snd_soc_dai s3c24xx_i2s_dai = { .name = "s3c24xx-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = s3c24xx_i2s_probe, .suspend = s3c24xx_i2s_suspend, .resume = s3c24xx_i2s_resume, diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 3318071dc80..c435913c60e 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -271,7 +271,7 @@ struct snd_soc_dai sh4_hac_dai[] = { { .name = "HAC0", .id = 0, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, @@ -291,8 +291,8 @@ struct snd_soc_dai sh4_hac_dai[] = { #ifdef CONFIG_CPU_SUBTYPE_SH7760 { .name = "HAC1", + .ac97_control = 1, .id = 1, - .type = SND_SOC_DAI_AC97, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 52a233840d2..fed544a3def 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -340,7 +340,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { { .name = "SSI0", .id = 0, - .type = SND_SOC_DAI_I2S, .playback = { .rates = SSI_RATES, .formats = SSI_FMTS, @@ -367,7 +366,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { { .name = "SSI1", .id = 1, - .type = SND_SOC_DAI_I2S, .playback = { .rates = SSI_RATES, .formats = SSI_FMTS, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 43f4060dbe7..0d47696ccd0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -100,20 +100,6 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) } #endif -static inline const char *get_dai_name(int type) -{ - switch (type) { - case SND_SOC_DAI_AC97_BUS: - case SND_SOC_DAI_AC97: - return "AC97"; - case SND_SOC_DAI_I2S: - return "I2S"; - case SND_SOC_DAI_PCM: - return "PCM"; - } - return NULL; -} - /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -652,7 +638,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) + if (cpu_dai->suspend && !cpu_dai->ac97_control) cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) platform->suspend(pdev, cpu_dai); @@ -678,7 +664,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) + if (cpu_dai->suspend && cpu_dai->ac97_control) cpu_dai->suspend(pdev, cpu_dai); } @@ -714,7 +700,7 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) + if (cpu_dai->resume && cpu_dai->ac97_control) cpu_dai->resume(pdev, cpu_dai); } @@ -741,7 +727,7 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) + if (cpu_dai->resume && !cpu_dai->ac97_control) cpu_dai->resume(pdev, cpu_dai); if (platform->resume) platform->resume(pdev, cpu_dai); @@ -898,8 +884,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, codec_dai->codec = socdev->codec; /* check client and interface hw capabilities */ - sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name, - get_dai_name(cpu_dai->type), num); + sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, + num); if (codec_dai->playback.channels_min) playback = 1; @@ -1270,8 +1256,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) continue; } } - if (card->dai_link[i].codec_dai->type == - SND_SOC_DAI_AC97_BUS) + if (card->dai_link[i].codec_dai->ac97_control) ac97 = 1; } snprintf(codec->card->shortname, sizeof(codec->card->shortname), @@ -1335,7 +1320,7 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { + if (codec_dai->ac97_control && codec->ac97) { soc_ac97_dev_unregister(codec); goto free_card; } -- cgit v1.2.3 From 67c91513b81a101800f113013234d2ab06bc5e52 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 17:45:26 +0000 Subject: ASoC: Flag AD1980 as an AC97 interface Special handling is required for suspend and resume of AC97 codecs due to the control path going over the data bus. Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 1a3ea059a6d..a9a268112d3 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -145,6 +145,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, struct snd_soc_dai ad1980_dai = { .name = "AC97", + .ac97_control = 1, .playback = { .stream_name = "Playback", .channels_min = 2, -- cgit v1.2.3 From fde22f272dad4fef7ba611e3f75fa94f7b43fae6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 18:08:18 +0000 Subject: ASoC: Lower priority of resume work logging Now that the ASoC resume has been punted to a workqueue for a release cycle without attracting bug reports it should be safe to make the log messages associated with it debug level, reducing noise and kernel size in production configurations. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0d47696ccd0..dbd92e12e86 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -693,7 +693,7 @@ static void soc_resume_deferred(struct work_struct *work) * so userspace apps are blocked from touching us */ - dev_info(socdev->dev, "starting resume work\n"); + dev_dbg(socdev->dev, "starting resume work\n"); if (card->resume_pre) card->resume_pre(pdev); @@ -736,7 +736,7 @@ static void soc_resume_deferred(struct work_struct *work) if (card->resume_post) card->resume_post(pdev); - dev_info(socdev->dev, "resume work completed\n"); + dev_dbg(socdev->dev, "resume work completed\n"); /* userspace can access us now we are back as we were before */ snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0); @@ -747,10 +747,10 @@ static int soc_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - dev_info(socdev->dev, "scheduling resume work\n"); + dev_dbg(socdev->dev, "scheduling resume work\n"); if (!schedule_work(&socdev->deferred_resume_work)) - dev_err(socdev->dev, "work item may be lost\n"); + dev_err(socdev->dev, "resume work item may be lost\n"); return 0; } -- cgit v1.2.3 From 0be43050d4da08295b985cb23347ecc1003cb8d6 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 25 Nov 2008 12:45:08 +0200 Subject: ASoC: OMAP: Apply channel constrains to N810 machine driver Prepare for upcoming McBSP DAI update adding support for mono links by restricting number of channels to 2 in N810. This is due tlv320aic3x which claims channels_min = 1 and playing pure mono audio over I2S would cause it to be played only from left channel if both cpu and codec DAI's claim to support mono. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/n810.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index d216b4f9e14..18e2062e3a1 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -70,9 +70,13 @@ static void n810_ext_control(struct snd_soc_codec *codec) static int n810_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->socdev->codec; + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); + n810_ext_control(codec); return clk_enable(sys_clkout2); } -- cgit v1.2.3 From 375e8a7c943d5aa8716be229e398473b23709ce9 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 25 Nov 2008 12:45:09 +0200 Subject: ASoC: OMAP: Add support for mono audio links in McBSP DAI Patch adds support for mono audio links so that McBSP DAI can operate with real mono codecs. In I2S, the signalling remains the same but only first frame (left channel) is transmitting audio data and second frame having null data. In DSP_A, only first frame is transmitted. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 252bc7ebb19..e8f1314762d 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -203,7 +203,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; - int wlen; + int wlen, channels; unsigned long port; if (cpu_class_is_omap1()) { @@ -232,12 +232,17 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return 0; } - switch (params_channels(params)) { + channels = params_channels(params); + switch (channels) { case 2: - /* Set 1 word per (McBPSP) frame and use dual-phase frames */ - regs->rcr2 |= RFRLEN2(1 - 1) | RPHASE; + /* Use dual-phase frames */ + regs->rcr2 |= RPHASE; + regs->xcr2 |= XPHASE; + case 1: + /* Set 1 word per (McBSP) frame */ + regs->rcr2 |= RFRLEN2(1 - 1); regs->rcr1 |= RFRLEN1(1 - 1); - regs->xcr2 |= XFRLEN2(1 - 1) | XPHASE; + regs->xcr2 |= XFRLEN2(1 - 1); regs->xcr1 |= XFRLEN1(1 - 1); break; default: @@ -266,8 +271,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, regs->srgr1 |= FWID(wlen - 1); break; case SND_SOC_DAIFMT_DSP_A: - regs->srgr2 |= FPER(wlen * 2 - 1); - regs->srgr1 |= FWID(wlen * 2 - 2); + regs->srgr2 |= FPER(wlen * channels - 1); + regs->srgr1 |= FWID(wlen * channels - 2); break; } @@ -457,13 +462,13 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, .name = "omap-mcbsp-dai-"#link_id, \ .id = (link_id), \ .playback = { \ - .channels_min = 2, \ + .channels_min = 1, \ .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ - .channels_min = 2, \ + .channels_min = 1, \ .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ -- cgit v1.2.3 From 9c8f1a0e6ed48f2ecf08ac0fb7fb043f8c34dc63 Mon Sep 17 00:00:00 2001 From: Arun KS Date: Tue, 25 Nov 2008 09:56:12 +0530 Subject: ASoC: Fix TWL4030 Kconfig dependency Fixes Kconfig dependency of TWL4030 audio codec driver with TWL4030 core driver on both overo and omap2evm boards Signed-off-by: Arun KS Acked-by: David Brownell Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 6c56277e160..090043702e8 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -24,7 +24,7 @@ config SND_OMAP_SOC_OSK5912 config SND_OMAP_SOC_OVERO tristate "SoC Audio support for Gumstix Overo" - depends on SND_OMAP_SOC && MACH_OVERO + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO select SND_OMAP_SOC_MCBSP select SND_SOC_TWL4030 help @@ -32,7 +32,7 @@ config SND_OMAP_SOC_OVERO config SND_OMAP_SOC_OMAP2EVM tristate "SoC Audio support for OMAP2EVM board" - depends on SND_OMAP_SOC && MACH_OMAP2EVM + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM select SND_OMAP_SOC_MCBSP select SND_SOC_TWL4030 help -- cgit v1.2.3 From 4451582f7e9fc2860b289aca60a6065286439bb8 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Mon, 24 Nov 2008 22:21:23 -0600 Subject: ASoC: Add support for TI SDP3430 This patch add ASoC support for TI SDP3430. It's based on Gumstix Overo SoC code by Steve Sakoman. Signed-off-by: Misael Lopez Cruz Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 7 +++ sound/soc/omap/Makefile | 3 +- sound/soc/omap/sdp3430.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 sound/soc/omap/sdp3430.c diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 090043702e8..1cd0176811c 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -38,5 +38,12 @@ config SND_OMAP_SOC_OMAP2EVM help Say Y if you want to add support for SoC audio on the omap2evm board. +config SND_OMAP_SOC_SDP3430 + tristate "SoC Audio support for Texas Instruments SDP3430" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on Texas Instruments SDP3430. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index f5da3cc764a..29cf3a856c8 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -10,9 +10,10 @@ snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o snd-soc-omap2evm-objs := omap2evm.o +snd-soc-sdp3430-objs := sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o - +obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c new file mode 100644 index 00000000000..85fd160bca1 --- /dev/null +++ b/sound/soc/omap/sdp3430.c @@ -0,0 +1,152 @@ +/* + * sdp3430.c -- SoC audio for TI OMAP3430 SDP + * + * Author: Misael Lopez Cruz + * + * Based on: + * Author: Steve Sakoman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int sdp3430_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops sdp3430_ops = { + .hw_params = sdp3430_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link sdp3430_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &sdp3430_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_sdp3430 = { + .name = "SDP3430", + .dai_link = &sdp3430_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device sdp3430_snd_devdata = { + .machine = &snd_soc_machine_sdp3430, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *sdp3430_snd_device; + +static int __init sdp3430_soc_init(void) +{ + int ret; + + if (!machine_is_omap_3430sdp()) { + pr_debug("Not SDP3430!\n"); + return -ENODEV; + } + printk(KERN_INFO "SDP3430 SoC init\n"); + + sdp3430_snd_device = platform_device_alloc("soc-audio", -1); + if (!sdp3430_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata); + sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev; + *(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(sdp3430_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(sdp3430_snd_device); + + return ret; +} +module_init(sdp3430_soc_init); + +static void __exit sdp3430_soc_exit(void) +{ + platform_device_unregister(sdp3430_snd_device); +} +module_exit(sdp3430_soc_exit); + +MODULE_AUTHOR("Misael Lopez Cruz "); +MODULE_DESCRIPTION("ALSA SoC SDP3430"); +MODULE_LICENSE("GPL"); + -- cgit v1.2.3 From 5c0d7bb797a975691ca8bbc38e53da03c6e151bb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 25 Nov 2008 09:35:21 +0300 Subject: ASoC: tosa: move gpio probing to machine callbacks Signed-off-by: Dmitry Baryshkov Signed-off-by: Mark Brown --- sound/soc/pxa/tosa.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 9d9be5a14d1..48242b32a28 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -230,10 +230,32 @@ static struct snd_soc_dai_link tosa_dai[] = { }, }; +static int tosa_probe(struct platform_device *dev) +{ + int ret; + + ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); + if (ret) + return ret; + ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0); + if (ret) + gpio_free(TOSA_GPIO_L_MUTE); + + return ret; +} + +static int tosa_remove(struct platform_device *dev) +{ + gpio_free(TOSA_GPIO_L_MUTE); + return 0; +} + static struct snd_soc_card tosa = { .name = "Tosa", .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), + .probe = tosa_probe, + .remove = tosa_remove, }; static struct snd_soc_device tosa_snd_devdata = { @@ -251,11 +273,6 @@ static int __init tosa_init(void) if (!machine_is_tosa()) return -ENODEV; - ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); - if (ret) - return ret; - gpio_direction_output(TOSA_GPIO_L_MUTE, 0); - tosa_snd_device = platform_device_alloc("soc-audio", -1); if (!tosa_snd_device) { ret = -ENOMEM; @@ -272,15 +289,12 @@ static int __init tosa_init(void) platform_device_put(tosa_snd_device); err_alloc: - gpio_free(TOSA_GPIO_L_MUTE); - return ret; } static void __exit tosa_exit(void) { platform_device_unregister(tosa_snd_device); - gpio_free(TOSA_GPIO_L_MUTE); } module_init(tosa_init); -- cgit v1.2.3 From 9e0f1b7f6bc5265847e995540981642c857f15b6 Mon Sep 17 00:00:00 2001 From: Qinghuang Feng Date: Tue, 25 Nov 2008 23:24:54 +0800 Subject: ASoC: Clean up kernel-doc for snd_soc_dai_set_fmt There is no argument named @clk_id in snd_soc_dai_set_fmt, remove its' comment. Signed-off-by: Qinghuang Feng Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dbd92e12e86..00fccdd41bb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1883,7 +1883,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); /** * snd_soc_dai_set_fmt - configure DAI hardware audio format. * @dai: DAI - * @clk_id: DAI specific clock ID * @fmt: SND_SOC_DAIFMT_ format value. * * Configures the DAI hardware format and clocking. -- cgit v1.2.3 From 414ff491b2ab68359c7a2037b30ccfea20d829d4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Nov 2008 10:32:26 +0000 Subject: ASoC: Fix word wrapping in OMAP Kconfig Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 1cd0176811c..9a869390abb 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -44,6 +44,5 @@ config SND_OMAP_SOC_SDP3430 select SND_OMAP_SOC_MCBSP select SND_SOC_TWL4030 help - Say Y if you want to add support for SoC audio on Texas Instruments SDP3430. - - + Say Y if you want to add support for SoC audio on Texas Instruments + SDP3430. -- cgit v1.2.3 From 54f01916297bafc18bd7df4e2300a0544a84fce3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 26 Nov 2008 17:47:36 +0100 Subject: ASoC: Allow more routing features for tlv320aic3x This patch enables more routing functions for tlv320aic3x codecs. It is now possible to - control the volume of the PGA bypass path for the HPL, HPR, HPLCOM and HPRCOM outputs individually - route right line1 input to the left ADC channel - route left line1 input to the right ADC channel - route right mic3 input to left DAC channel - route left mic3 input to right DAC channel - route left line1 input to right line1 output - route right line1 input to left line1 output Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 96 +++++++++++++++++++++++++++++------------- sound/soc/codecs/tlv320aic3x.h | 12 ++++++ 2 files changed, 78 insertions(+), 30 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b76bcc3c411..255e784c805 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -272,8 +272,10 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPROUT_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, - PGAR_2_HPROUT_VOL, 0, 0x7f, 1), + SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, + 0, 0x7f, 1), + SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL, + 0, 0x7f, 1), SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, 0, 0x7f, 1), @@ -281,8 +283,10 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPRCOM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, - PGAR_2_HPRCOM_VOL, 0, 0x7f, 1), + SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, + 0, 0x7f, 1), + SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL, + 0, 0x7f, 1), SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1), @@ -333,7 +337,8 @@ SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); /* Left DAC_L1 Mixer */ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), @@ -341,7 +346,8 @@ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { /* Right DAC_R1 Mixer */ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), @@ -350,14 +356,18 @@ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { /* Left PGA Mixer */ static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1), }; /* Right PGA Mixer */ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1), SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), }; @@ -379,34 +389,42 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); /* Left PGA Bypass Mixer */ static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), }; /* Right PGA Bypass Mixer */ static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), }; /* Left Line2 Bypass Mixer */ static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), }; /* Right Line2 Bypass Mixer */ static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), }; static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { @@ -439,22 +457,26 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { /* Mono Output */ SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), - /* Left Inputs to Left ADC */ + /* Inputs to Left ADC */ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, &aic3x_left_pga_mixer_controls[0], ARRAY_SIZE(aic3x_left_pga_mixer_controls)), SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line1_mux_controls), + SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, + &aic3x_left_line1_mux_controls), SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line2_mux_controls), - /* Right Inputs to Right ADC */ + /* Inputs to Right ADC */ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", LINE1R_2_RADC_CTRL, 2, 0), SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, &aic3x_right_pga_mixer_controls[0], ARRAY_SIZE(aic3x_right_pga_mixer_controls)), + SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, + &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, @@ -531,7 +553,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left DAC Mux", "DAC_L2", "Left DAC"}, {"Left DAC Mux", "DAC_L3", "Left DAC"}, - {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"}, + {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"}, + {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, @@ -557,7 +580,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right DAC Mux", "DAC_R2", "Right DAC"}, {"Right DAC Mux", "DAC_R3", "Right DAC"}, - {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"}, + {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"}, + {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, @@ -592,8 +616,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left Line2L Mux", "differential", "LINE2L"}, {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, + {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"}, {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, + {"Left PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Left ADC", NULL, "Left PGA Mixer"}, {"Left ADC", NULL, "GPIO1 dmic modclk"}, @@ -605,18 +631,23 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right Line2R Mux", "single-ended", "LINE2R"}, {"Right Line2R Mux", "differential", "LINE2R"}, + {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"}, {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, + {"Right PGA Mixer", "Mic3L Switch", "MIC3L"}, {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Right ADC", NULL, "Right PGA Mixer"}, {"Right ADC", NULL, "GPIO1 dmic modclk"}, /* Left PGA Bypass */ - {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"}, {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"}, {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, @@ -627,10 +658,13 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, /* Right PGA Bypass */ - {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"}, {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"}, {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, @@ -643,10 +677,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, /* Left Line2 Bypass */ - {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"}, {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"}, {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, @@ -657,10 +692,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, /* Right Line2 Bypass */ - {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"}, {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"}, {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 00a195aa02e..7e982acf399 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -48,7 +48,9 @@ #define MIC3LR_2_RADC_CTRL 18 /* Line1 Input control registers */ #define LINE1L_2_LADC_CTRL 19 +#define LINE1R_2_LADC_CTRL 21 #define LINE1R_2_RADC_CTRL 22 +#define LINE1L_2_RADC_CTRL 24 /* Line2 Input control registers */ #define LINE2L_2_LADC_CTRL 20 #define LINE2R_2_RADC_CTRL 23 @@ -79,6 +81,8 @@ #define LINE2L_2_HPLOUT_VOL 45 #define LINE2R_2_HPROUT_VOL 62 #define PGAL_2_HPLOUT_VOL 46 +#define PGAL_2_HPROUT_VOL 60 +#define PGAR_2_HPLOUT_VOL 49 #define PGAR_2_HPROUT_VOL 63 #define DACL1_2_HPLOUT_VOL 47 #define DACR1_2_HPROUT_VOL 64 @@ -88,6 +92,8 @@ #define LINE2L_2_HPLCOM_VOL 52 #define LINE2R_2_HPRCOM_VOL 69 #define PGAL_2_HPLCOM_VOL 53 +#define PGAR_2_HPLCOM_VOL 56 +#define PGAL_2_HPRCOM_VOL 67 #define PGAR_2_HPRCOM_VOL 70 #define DACL1_2_HPLCOM_VOL 54 #define DACR1_2_HPRCOM_VOL 71 @@ -103,11 +109,17 @@ #define MONOLOPM_CTRL 79 /* Line Output Plus/Minus control registers */ #define LINE2L_2_LLOPM_VOL 80 +#define LINE2L_2_RLOPM_VOL 87 +#define LINE2R_2_LLOPM_VOL 83 #define LINE2R_2_RLOPM_VOL 90 #define PGAL_2_LLOPM_VOL 81 +#define PGAL_2_RLOPM_VOL 88 +#define PGAR_2_LLOPM_VOL 84 #define PGAR_2_RLOPM_VOL 91 #define DACL1_2_LLOPM_VOL 82 +#define DACL1_2_RLOPM_VOL 89 #define DACR1_2_RLOPM_VOL 92 +#define DACR1_2_LLOPM_VOL 85 #define LLOPM_CTRL 86 #define RLOPM_CTRL 93 /* GPIO/IRQ registers */ -- cgit v1.2.3 From 9171e5e6a20a9cd4992ff9c7cbee13c6fdf7b0b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 15:39:13 +0100 Subject: ALSA: soc - Fix compile warnings in wm8903.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hide annoying uninitialized warnings: sound/soc/codecs/wm8903.c:382: warning: ‘reg’ may be used uninitialized in this function sound/soc/codecs/wm8903.c:383: warning: ‘shift’ may be used uninitialized in this function Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8903.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index efbe8927b7d..78070b2cd48 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -379,8 +379,8 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, struct wm8903_priv *wm8903 = codec->private_data; struct i2c_client *i2c = codec->control_data; u16 val; - u16 reg; - int shift; + u16 uninitialized_var(reg); + int uninitialized_var(shift); u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0); switch (w->reg) { -- cgit v1.2.3 From f5d4c67e41a262f0cdfaec1bb0fa8e5952187ef9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 16:29:47 +0100 Subject: ALSA: soc - Remove obsoleted sound/driver.h inclusion Signed-off-by: Takashi Iwai --- sound/soc/pxa/em-x270.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index 4a61925c310..d6884b755d5 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include -- cgit v1.2.3 From 2caf6a1f9c8bcdc81ba580cfbf512d073c9444be Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 17:56:06 +0100 Subject: ALSA: ASoC: Remove superfluous dependency on SND_SOC The dependency on SND_SOC is already fulfilled in sound/soc/Kconfig, thus no more need in Kconfig of each sub directory. Signed-off-by: Takashi Iwai --- sound/soc/blackfin/Kconfig | 4 ++-- sound/soc/fsl/Kconfig | 2 +- sound/soc/omap/Kconfig | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index e162cbbd3f3..0a2f8f9eff5 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -1,6 +1,6 @@ config SND_BF5XX_I2S tristate "SoC I2S Audio for the ADI BF5xx chip" - depends on BLACKFIN && SND_SOC + depends on BLACKFIN help Say Y or M if you want to add support for codecs attached to the Blackfin SPORT (synchronous serial ports) interface in I2S @@ -34,7 +34,7 @@ config SND_BFIN_AD73311_SE config SND_BF5XX_AC97 tristate "SoC AC97 Audio for the ADI BF5xx chip" - depends on BLACKFIN && SND_SOC + depends on BLACKFIN help Say Y or M if you want to add support for codecs attached to the Blackfin SPORT (synchronous serial ports) interface in slot 16 diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 8d73edc5610..95c12b26fe3 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -20,7 +20,7 @@ config SND_SOC_MPC8610_HPCD config SND_SOC_MPC5200_I2S tristate "Freescale MPC5200 PSC in I2S mode driver" - depends on SND_SOC && PPC_MPC52xx && PPC_BESTCOMM + depends on PPC_MPC52xx && PPC_BESTCOMM select SND_SOC_OF_SIMPLE select PPC_BESTCOMM_GEN_BD help diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 9a869390abb..da39f27c661 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -1,6 +1,6 @@ config SND_OMAP_SOC tristate "SoC Audio for the Texas Instruments OMAP chips" - depends on ARCH_OMAP && SND_SOC + depends on ARCH_OMAP config SND_OMAP_SOC_MCBSP tristate -- cgit v1.2.3 From 0bc286e2ac72e483d2b5a6dac0dafb05e9f047c8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 19:59:35 +0100 Subject: Revert "ALSA: soc - Fix compile warnings in wm8903.c" This reverts commit 9171e5e6a20a9cd4992ff9c7cbee13c6fdf7b0b1. I can't reproduce the compile warnings any more. The warnings might be some weird cross-compiling set up. Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8903.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 78070b2cd48..efbe8927b7d 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -379,8 +379,8 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, struct wm8903_priv *wm8903 = codec->private_data; struct i2c_client *i2c = codec->control_data; u16 val; - u16 uninitialized_var(reg); - int uninitialized_var(shift); + u16 reg; + int shift; u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0); switch (w->reg) { -- cgit v1.2.3 From 5220ed6b321639d68a66bad2082456c1b273f3ea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 20:00:47 +0100 Subject: ALSA: ASoC: Fix compile warnings on corgi.c Fix the wrong shutdown callback type. Also removed the unused variables there: sound/soc/pxa/corgi.c: In function 'corgi_shutdown': sound/soc/pxa/corgi.c:114: warning: unused variable 'codec' sound/soc/pxa/corgi.c: At top level: sound/soc/pxa/corgi.c:175: warning: initialization from incompatible pointer type Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/pxa/corgi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 647f056a3cb..e56bf4b6c2a 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -108,15 +108,11 @@ static int corgi_startup(struct snd_pcm_substream *substream) } /* we need to unmute the HP at shutdown as the mute burns power on corgi */ -static int corgi_shutdown(struct snd_pcm_substream *substream) +static void corgi_shutdown(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->socdev->codec; - /* set = unmute headphone */ gpio_set_value(CORGI_GPIO_MUTE_L, 1); gpio_set_value(CORGI_GPIO_MUTE_R, 1); - return 0; } static int corgi_hw_params(struct snd_pcm_substream *substream, -- cgit v1.2.3 From 682d5874f3d654b5d13d9b8dd56b9e05cfadd01b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 20:03:54 +0100 Subject: ALSA: ASoC: Fix old-style trigger callback in s3c2443-ac97.c Fix the old-style trigger callback in s3c2443-ac97.c: sound/soc/s3c24xx/s3c2443-ac97.c:378: warning: initialization from incompatible pointer type Signed-off-by: Takashi Iwai --- sound/soc/s3c24xx/s3c2443-ac97.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 41bde6a3883..f0bc9b7e084 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -285,7 +285,8 @@ static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd) +static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { u32 ac_glbctrl; -- cgit v1.2.3 From 968a6025aa9f909d487988efb542217a126023a0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 28 Nov 2008 11:49:07 +0000 Subject: ASoC: Rename snd_soc_register_card() to snd_soc_init_card() Currently ASoC card initialisation is completed by a function called snd_soc_register_card(). As part of the work to allow independant registration of cards, codecs and machines in ASoC v2 a new function of the same name has been added so rename the existing function to facilitate the merge of v2. Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- sound/soc/codecs/ac97.c | 2 +- sound/soc/codecs/ad1980.c | 2 +- sound/soc/codecs/ad73311.c | 2 +- sound/soc/codecs/ak4535.c | 2 +- sound/soc/codecs/cs4270.c | 2 +- sound/soc/codecs/pcm3008.c | 2 +- sound/soc/codecs/ssm2602.c | 2 +- sound/soc/codecs/tlv320aic23.c | 2 +- sound/soc/codecs/tlv320aic26.c | 2 +- sound/soc/codecs/tlv320aic3x.c | 2 +- sound/soc/codecs/twl4030.c | 2 +- sound/soc/codecs/uda134x.c | 2 +- sound/soc/codecs/uda1380.c | 2 +- sound/soc/codecs/wm8510.c | 2 +- sound/soc/codecs/wm8580.c | 2 +- sound/soc/codecs/wm8728.c | 2 +- sound/soc/codecs/wm8731.c | 2 +- sound/soc/codecs/wm8750.c | 2 +- sound/soc/codecs/wm8753.c | 2 +- sound/soc/codecs/wm8900.c | 2 +- sound/soc/codecs/wm8903.c | 2 +- sound/soc/codecs/wm8971.c | 2 +- sound/soc/codecs/wm8990.c | 2 +- sound/soc/codecs/wm9712.c | 2 +- sound/soc/codecs/wm9713.c | 2 +- sound/soc/soc-core.c | 6 +++--- 27 files changed, 29 insertions(+), 29 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 444f9c21137..9356c1ce98c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -162,7 +162,7 @@ extern struct snd_ac97_bus_ops soc_ac97_ops; /* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); -int snd_soc_register_card(struct snd_soc_device *socdev); +int snd_soc_init_card(struct snd_soc_device *socdev); /* set runtime hw params */ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index c4208c8210c..fb53e6511af 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -114,7 +114,7 @@ static int ac97_soc_probe(struct platform_device *pdev) if (ret < 0) goto bus_err; - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) goto bus_err; return 0; diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index a9a268112d3..73fdbb4d4a3 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -270,7 +270,7 @@ static int ad1980_soc_probe(struct platform_device *pdev) ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); ad1980_add_controls(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register card\n"); goto reset_err; diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 59c4c8f18cb..0f4110f4bce 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -67,7 +67,7 @@ static int ad73311_soc_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "ad73311: failed to register card\n"); goto register_err; diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index c742290e553..23062c952e8 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -512,7 +512,7 @@ static int ak4535_init(struct snd_soc_device *socdev) ak4535_add_controls(codec); ak4535_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "ak4535: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 7507d468b20..4667a07b566 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -723,7 +723,7 @@ static int cs4270_probe(struct platform_device *pdev) printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n"); #endif - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "cs4270: failed to register card\n"); goto error_del_driver; diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 651a15eb8c2..a5862555b44 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -91,7 +91,7 @@ static int pcm3008_soc_probe(struct platform_device *pdev) } /* Register Card. */ - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "pcm3008: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 0c5884ea1b0..973844973fe 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -624,7 +624,7 @@ static int ssm2602_init(struct snd_soc_device *socdev) ssm2602_add_controls(codec); ssm2602_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { pr_err("ssm2602: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index a4e13d0688c..d209bec02a6 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -720,7 +720,7 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) tlv320aic23_add_controls(codec); tlv320aic23_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "tlv320aic23: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 6b7ddfc9257..e33fb7e00d1 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -359,7 +359,7 @@ static int aic26_probe(struct platform_device *pdev) /* CODEC is setup, we can register the card now */ dev_dbg(&pdev->dev, "Registering card\n"); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { dev_err(&pdev->dev, "aic26: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 255e784c805..0f4067bdd4a 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1187,7 +1187,7 @@ static int aic3x_init(struct snd_soc_device *socdev) aic3x_add_controls(codec); aic3x_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "aic3x: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 41362314789..f3e9e591b52 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -764,7 +764,7 @@ static int twl4030_init(struct snd_soc_device *socdev) twl4030_add_controls(codec); twl4030_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "twl4030: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 91f333cdc7c..58de749185e 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -578,7 +578,7 @@ static int uda134x_soc_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "UDA134X: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 330877c7069..42491650593 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -677,7 +677,7 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) /* uda1380 init */ uda1380_add_controls(codec); uda1380_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { pr_err("uda1380: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 173b66c0c76..126c70f749d 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -658,7 +658,7 @@ static int wm8510_init(struct snd_soc_device *socdev) wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8510_add_controls(codec); wm8510_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8510: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 220d4b68904..572a31de321 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -869,7 +869,7 @@ static int wm8580_init(struct snd_soc_device *socdev) wm8580_add_controls(codec); wm8580_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8580: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 71949bd320d..28f12c6a6ac 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -332,7 +332,7 @@ static int wm8728_init(struct snd_soc_device *socdev) wm8728_add_controls(codec); wm8728_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8728: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index c0f277053bb..403dea13b5d 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -545,7 +545,7 @@ static int wm8731_init(struct snd_soc_device *socdev) wm8731_add_controls(codec); wm8731_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8731: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 860a1d56830..979446f5c98 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -818,7 +818,7 @@ static int wm8750_init(struct snd_soc_device *socdev) wm8750_add_controls(codec); wm8750_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8750: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 5e4cd3bb824..96c0453fffb 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1605,7 +1605,7 @@ static int wm8753_init(struct snd_soc_device *socdev) wm8753_add_controls(codec); wm8753_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8753: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index d1326be91c8..29cd83991c5 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1365,7 +1365,7 @@ static int wm8900_init(struct snd_soc_device *socdev) wm8900_add_controls(codec); wm8900_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { dev_err(&i2c_client->dev, "Failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index efbe8927b7d..393a4c19882 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1648,7 +1648,7 @@ static int wm8903_init(struct snd_soc_device *socdev) wm8903_add_controls(codec); wm8903_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { dev_err(&i2c->dev, "wm8903: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 26edcc9d6e8..53e6937e9ba 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -747,7 +747,7 @@ static int wm8971_init(struct snd_soc_device *socdev) wm8971_add_controls(codec); wm8971_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8971: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 13926516d16..5c5128b6b45 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1462,7 +1462,7 @@ static int wm8990_init(struct snd_soc_device *socdev) wm8990_add_controls(codec); wm8990_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8990: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 40f14061fb7..af83d629078 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -700,7 +700,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm9712_add_controls(codec); wm9712_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm9712: failed to register card\n"); goto reset_err; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 9dad0bffcb0..49962a88770 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1247,7 +1247,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) wm9713_add_controls(codec); wm9713_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) goto reset_err; return 0; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 13b4aaff0e9..0448708245e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1233,7 +1233,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) EXPORT_SYMBOL_GPL(snd_soc_new_pcms); /** - * snd_soc_register_card - register sound card + * snd_soc_init_card - register sound card * @socdev: the SoC audio device * * Register a SoC sound card. Also registers an AC97 device if the @@ -1241,7 +1241,7 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms); * * Returns 0 for success, else error. */ -int snd_soc_register_card(struct snd_soc_device *socdev) +int snd_soc_init_card(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; struct snd_soc_card *card = socdev->card; @@ -1298,7 +1298,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) out: return ret; } -EXPORT_SYMBOL_GPL(snd_soc_register_card); +EXPORT_SYMBOL_GPL(snd_soc_init_card); /** * snd_soc_free_pcms - free sound card and pcms -- cgit v1.2.3 From 7d8c16a6f728f0ee5c42d1d731923cfd0cc19971 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Nov 2008 22:11:24 +0000 Subject: ASoC: Annotate core removal function Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0448708245e..7eb2ea1fd42 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1952,7 +1952,7 @@ static int __devinit snd_soc_init(void) return platform_driver_register(&soc_driver); } -static void snd_soc_exit(void) +static void __exit snd_soc_exit(void) { platform_driver_unregister(&soc_driver); } -- cgit v1.2.3 From fa5c76978cee331b25e6d271482cf8e76f51e68b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Nov 2008 22:55:46 +0000 Subject: ASoC: Remove in-code changelog from AD73311 driver Signed-off-by: Mark Brown --- sound/soc/codecs/ad73311.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 0f4110f4bce..500f9f3363d 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -8,9 +8,6 @@ * 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. - * - * Revision history - * 25th Sep 2008 Initial version. */ #include -- cgit v1.2.3 From 381a22b564ff5a7ada09ad9a0831246da1dc5513 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Dec 2008 10:03:45 +0200 Subject: ASoC: TWL4030: Change the capture volume control to TLV The digital Capture gain control has a range: 0 to 31 dB in 1 dB steps. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index f3e9e591b52..4b7a2d173a4 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -360,6 +360,12 @@ static DECLARE_TLV_DB_SCALE(master_tlv, -6300, 100, 1); */ static DECLARE_TLV_DB_SCALE(master_coarse_tlv, 0, 600, 0); +/* + * Capture gain after the ADCs + * from 0 dB to 31 dB in 1 dB steps + */ +static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("Master Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, @@ -367,9 +373,11 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("Master PCM Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, 6, 0x2, 0, master_coarse_tlv), - SOC_DOUBLE_R("Capture Volume", - TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, - 0, 0x1f, 0), + + /* Common capture gain controls */ + SOC_DOUBLE_R_TLV("Capture Volume", + TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, + 0, 0x1f, 0, digital_capture_tlv), }; /* add non dapm controls */ -- cgit v1.2.3 From d889a72c5c71161d6f934f9d7fca0e5b7e52bc08 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Dec 2008 10:03:46 +0200 Subject: ASoC: TWL4030: Change the common playback volume controls Add Playback volume controls for all four DACs. All four paths has three levels of volume controls: Digital Fine gain, Digital Coarse gain, Analog gain. The controls are named to reflect their connection to the DACs. Per DAC volume can be performed, if needed: amixer sset 'DAC1 Analog' 5,10 DACL1 analog gain to 5 DACR1 analog gain to 10 Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4b7a2d173a4..1dae73af527 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -351,14 +351,20 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) */ -static DECLARE_TLV_DB_SCALE(master_tlv, -6300, 100, 1); +static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1); /* * CGAIN volume control: * 0 dB to 12 dB in 6 dB steps * value 2 and 3 means 12 dB */ -static DECLARE_TLV_DB_SCALE(master_coarse_tlv, 0, 600, 0); +static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0); + +/* + * Analog playback gain + * -24 dB to 12 dB in 2 dB steps + */ +static DECLARE_TLV_DB_SCALE(analog_tlv, -2400, 200, 0); /* * Capture gain after the ADCs @@ -367,12 +373,27 @@ static DECLARE_TLV_DB_SCALE(master_coarse_tlv, 0, 600, 0); static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); static const struct snd_kcontrol_new twl4030_snd_controls[] = { - SOC_DOUBLE_R_TLV("Master Playback Volume", - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 0, 0x3f, 0, master_tlv), - SOC_DOUBLE_R_TLV("Master PCM Playback Volume", - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 6, 0x2, 0, master_coarse_tlv), + /* Common playback gain controls */ + SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", + TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, + 0, 0x3f, 0, digital_fine_tlv), + SOC_DOUBLE_R_TLV("DAC2 Digital Fine Playback Volume", + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, + 0, 0x3f, 0, digital_fine_tlv), + + SOC_DOUBLE_R_TLV("DAC1 Digital Coarse Playback Volume", + TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, + 6, 0x2, 0, digital_coarse_tlv), + SOC_DOUBLE_R_TLV("DAC2 Digital Coarse Playback Volume", + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, + 6, 0x2, 0, digital_coarse_tlv), + + SOC_DOUBLE_R_TLV("DAC1 Analog Playback Volume", + TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL, + 3, 0x12, 1, analog_tlv), + SOC_DOUBLE_R_TLV("DAC2 Analog Playback Volume", + TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, + 3, 0x12, 1, analog_tlv), /* Common capture gain controls */ SOC_DOUBLE_R_TLV("Capture Volume", -- cgit v1.2.3 From 4290239cd05b6323da87b5e7e7db4c673bff5359 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Dec 2008 10:03:47 +0200 Subject: ASoC: TWL4030: Add volume controls for outputs All outputs have dedicated gain controls except the HandsFree output. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1dae73af527..ffd5120697a 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -366,6 +366,12 @@ static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0); */ static DECLARE_TLV_DB_SCALE(analog_tlv, -2400, 200, 0); +/* + * Gain controls tied to outputs + * -6 dB to 6 dB in 6 dB steps (mute instead of -12) + */ +static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1); + /* * Capture gain after the ADCs * from 0 dB to 31 dB in 1 dB steps @@ -395,6 +401,21 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, 3, 0x12, 1, analog_tlv), + /* Separate output gain controls */ + SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", + TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL, + 4, 3, 0, output_tvl), + + SOC_DOUBLE_TLV_TWL4030("Headset Playback Volume", + TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, output_tvl), + + SOC_DOUBLE_R_TLV_TWL4030("Carkit Playback Volume", + TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL, + 4, 3, 0, output_tvl), + + SOC_SINGLE_TLV_TWL4030("Earpiece Playback Volume", + TWL4030_REG_EAR_CTL, 4, 3, 0, output_tvl), + /* Common capture gain controls */ SOC_DOUBLE_R_TLV("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, -- cgit v1.2.3 From 0ecfe7987855d21c2a89ffe003ddf0ee11b42d47 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Dec 2008 17:59:25 +0000 Subject: ASoC: Don't free static data in WM9713 Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 49962a88770..f3ca8aaf013 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1283,7 +1283,6 @@ static int wm9713_soc_remove(struct platform_device *pdev) snd_soc_free_ac97_codec(codec); kfree(codec->private_data); kfree(codec->reg_cache); - kfree(codec->dai); kfree(codec); return 0; } -- cgit v1.2.3 From 6308419a199eed66086cd756ab8dc81b88d54a6b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Dec 2008 15:08:03 +0000 Subject: ASoC: Push workqueue data into snd_soc_card ASoC v2 does not use the struct snd_soc_device at runtime, using struct snd_soc_card as the root of the card. Begin removing data from snd_soc_device by pushing the workqueue data into snd_soc_card, using a backpointer to the snd_soc_device to keep things going for the time being. Signed-off-by: Mark Brown --- include/sound/soc.h | 7 +++++-- sound/soc/soc-core.c | 33 ++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 9356c1ce98c..359ec49f8d0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -349,6 +349,11 @@ struct snd_soc_card { /* CPU <--> Codec DAI links */ struct snd_soc_dai_link *dai_link; int num_links; + + struct snd_soc_device *socdev; + + struct delayed_work delayed_work; + struct work_struct deferred_resume_work; }; /* SoC Device - the audio subsystem */ @@ -358,8 +363,6 @@ struct snd_soc_device { struct snd_soc_platform *platform; struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; - struct delayed_work delayed_work; - struct work_struct deferred_resume_work; void *codec_data; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7eb2ea1fd42..c4b22e6984e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -247,8 +247,9 @@ out: */ static void close_delayed_work(struct work_struct *work) { - struct snd_soc_device *socdev = - container_of(work, struct snd_soc_device, delayed_work.work); + struct snd_soc_card *card = container_of(work, struct snd_soc_card, + delayed_work.work); + struct snd_soc_device *socdev = card->socdev; struct snd_soc_codec *codec = socdev->codec; struct snd_soc_dai *codec_dai; int i; @@ -299,6 +300,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; @@ -340,7 +342,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; - schedule_delayed_work(&socdev->delayed_work, + schedule_delayed_work(&card->delayed_work, msecs_to_jiffies(pmdown_time)); } else { /* capture streams can be powered down now */ @@ -366,6 +368,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; @@ -411,7 +414,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && codec_dai->pop_wait) { codec_dai->pop_wait = 0; - cancel_delayed_work(&socdev->delayed_work); + cancel_delayed_work(&card->delayed_work); } /* do we need to power up codec */ @@ -645,7 +648,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) } /* close any waiting streams and save state */ - run_delayed_work(&socdev->delayed_work); + run_delayed_work(&card->delayed_work); codec->suspend_bias_level = codec->bias_level; for (i = 0; i < codec->num_dai; i++) { @@ -679,10 +682,10 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) */ static void soc_resume_deferred(struct work_struct *work) { - struct snd_soc_device *socdev = container_of(work, - struct snd_soc_device, - deferred_resume_work); - struct snd_soc_card *card = socdev->card; + struct snd_soc_card *card = container_of(work, + struct snd_soc_card, + deferred_resume_work); + struct snd_soc_device *socdev = card->socdev; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; @@ -746,10 +749,11 @@ static void soc_resume_deferred(struct work_struct *work) static int soc_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_card *card = socdev->card; dev_dbg(socdev->dev, "scheduling resume work\n"); - if (!schedule_work(&socdev->deferred_resume_work)) + if (!schedule_work(&card->deferred_resume_work)) dev_err(socdev->dev, "resume work item may be lost\n"); return 0; @@ -769,6 +773,9 @@ static int soc_probe(struct platform_device *pdev) struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + /* Bodge while we push things out of socdev */ + card->socdev = socdev; + if (card->probe) { ret = card->probe(pdev); if (ret < 0) @@ -797,10 +804,10 @@ static int soc_probe(struct platform_device *pdev) } /* DAPM stream work */ - INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); + INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work); #ifdef CONFIG_PM /* deferred resume work */ - INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred); + INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); #endif return 0; @@ -831,7 +838,7 @@ static int soc_remove(struct platform_device *pdev) struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - run_delayed_work(&socdev->delayed_work); + run_delayed_work(&card->delayed_work); if (platform->remove) platform->remove(pdev); -- cgit v1.2.3 From 87689d567a45f80416feea0a2aa6d3a2a6b8963a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Dec 2008 16:01:14 +0000 Subject: ASoC: Push platform registration down into the card As part of the deprecation of snd_soc_device push the registration of the platform down into the card structure. Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- sound/soc/atmel/playpaq_wm8510.c | 2 +- sound/soc/atmel/sam9g20_wm8731.c | 2 +- sound/soc/blackfin/bf5xx-ad1980.c | 2 +- sound/soc/blackfin/bf5xx-ad73311.c | 2 +- sound/soc/blackfin/bf5xx-ssm2602.c | 2 +- sound/soc/davinci/davinci-evm.c | 2 +- sound/soc/davinci/davinci-i2s.c | 2 +- sound/soc/davinci/davinci-sffsdr.c | 2 +- sound/soc/fsl/mpc8610_hpcd.c | 2 +- sound/soc/fsl/soc-of-simple.c | 2 +- sound/soc/omap/n810.c | 2 +- sound/soc/omap/omap2evm.c | 2 +- sound/soc/omap/omap3beagle.c | 2 +- sound/soc/omap/osk5912.c | 2 +- sound/soc/omap/overo.c | 2 +- sound/soc/omap/sdp3430.c | 2 +- sound/soc/pxa/corgi.c | 2 +- sound/soc/pxa/e800_wm9712.c | 2 +- sound/soc/pxa/em-x270.c | 2 +- sound/soc/pxa/palm27x.c | 2 +- sound/soc/pxa/poodle.c | 2 +- sound/soc/pxa/spitz.c | 2 +- sound/soc/pxa/tosa.c | 2 +- sound/soc/pxa/zylonite.c | 2 +- sound/soc/s3c24xx/ln2440sbc_alc650.c | 2 +- sound/soc/s3c24xx/neo1973_wm8753.c | 2 +- sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 +- sound/soc/s3c24xx/smdk2443_wm9710.c | 2 +- sound/soc/sh/sh7760-ac97.c | 2 +- sound/soc/soc-core.c | 44 ++++++++++++++++++++---------------- 31 files changed, 55 insertions(+), 49 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 359ec49f8d0..ad8141acd6b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -352,6 +352,7 @@ struct snd_soc_card { struct snd_soc_device *socdev; + struct snd_soc_platform *platform; struct delayed_work delayed_work; struct work_struct deferred_resume_work; }; @@ -360,7 +361,6 @@ struct snd_soc_card { struct snd_soc_device { struct device *dev; struct snd_soc_card *card; - struct snd_soc_platform *platform; struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; void *codec_data; diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index d40b5a52a8d..43dd8cee83c 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -363,6 +363,7 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = { static struct snd_soc_card snd_soc_playpaq = { .name = "LRS_PlayPaq_WM8510", + .platform = &at32_soc_platform, .dai_link = &playpaq_wm8510_dai, .num_links = 1, }; @@ -378,7 +379,6 @@ static struct wm8510_setup_data playpaq_wm8510_setup = { static struct snd_soc_device playpaq_wm8510_snd_devdata = { .card = &snd_soc_playpaq, - .platform = &at32_soc_platform, .codec_dev = &soc_codec_dev_wm8510, .codec_data = &playpaq_wm8510_setup, }; diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index fdc1d0206e0..1fb59a9d371 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -244,6 +244,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = { static struct snd_soc_card snd_soc_at91sam9g20ek = { .name = "WM8731", + .platform = &atmel_soc_platform, .dai_link = &at91sam9g20ek_dai, .num_links = 1, }; @@ -255,7 +256,6 @@ static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { static struct snd_soc_device at91sam9g20ek_snd_devdata = { .card = &snd_soc_at91sam9g20ek, - .platform = &atmel_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &at91sam9g20ek_wm8731_setup, }; diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index 36c569a43ce..d8f59127377 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c @@ -69,13 +69,13 @@ static struct snd_soc_dai_link bf5xx_board_dai = { static struct snd_soc_card bf5xx_board = { .name = "bf5xx-board", + .platform = &bf5xx_ac97_soc_platform, .dai_link = &bf5xx_board_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_board_snd_devdata = { .card = &bf5xx_board, - .platform = &bf5xx_ac97_soc_platform, .codec_dev = &soc_codec_dev_ad1980, }; diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 57da1479937..7f2a5e19907 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -192,6 +192,7 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai = { static struct snd_soc_card bf5xx_ad73311 = { .name = "bf5xx_ad73311", + .platform = &bf5xx_i2s_soc_platform, .probe = bf5xx_probe, .dai_link = &bf5xx_ad73311_dai, .num_links = 1, @@ -199,7 +200,6 @@ static struct snd_soc_card bf5xx_ad73311 = { static struct snd_soc_device bf5xx_ad73311_snd_devdata = { .card = &bf5xx_ad73311, - .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ad73311, }; diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index 0078dfcd95b..bc0cdded711 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -137,13 +137,13 @@ static struct ssm2602_setup_data bf5xx_ssm2602_setup = { static struct snd_soc_card bf5xx_ssm2602 = { .name = "bf5xx_ssm2602", + .platform = &bf5xx_i2s_soc_platform, .dai_link = &bf5xx_ssm2602_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { .card = &bf5xx_ssm2602, - .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ssm2602, .codec_data = &bf5xx_ssm2602_setup, }; diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 2ce34d44b15..d87b91179cc 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -130,6 +130,7 @@ static struct snd_soc_dai_link evm_dai = { /* davinci-evm audio machine driver */ static struct snd_soc_card snd_soc_card_evm = { .name = "DaVinci EVM", + .platform = &davinci_soc_platform, .dai_link = &evm_dai, .num_links = 1, }; @@ -143,7 +144,6 @@ static struct aic3x_setup_data evm_aic3x_setup = { /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { .card = &snd_soc_card_evm, - .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &evm_aic3x_setup, }; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index cf31b3bb96c..8b99efbc64c 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -112,7 +112,7 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = socdev->card->platform; u32 w; int ret; diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index e95fde1766b..f67579d5276 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -76,6 +76,7 @@ static struct snd_soc_dai_link sffsdr_dai = { /* davinci-sffsdr audio machine driver */ static struct snd_soc_card snd_soc_sffsdr = { .name = "DaVinci SFFSDR", + .platform = &davinci_soc_platform, .dai_link = &sffsdr_dai, .num_links = 1, }; @@ -91,7 +92,6 @@ static struct pcm3008_setup_data sffsdr_pcm3008_setup = { /* sffsdr audio subsystem */ static struct snd_soc_device sffsdr_snd_devdata = { .card = &snd_soc_sffsdr, - .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_pcm3008, .codec_data = &sffsdr_pcm3008_setup, }; diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 1cf4d6eeb53..bcec3f60bad 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -467,7 +467,7 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, machine_data->sound_devdata.card = &mpc8610_hpcd_machine; machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; - machine_data->sound_devdata.platform = &fsl_soc_platform; + machine_data->machine.platform = &fsl_soc_platform; sound_device->dev.platform_data = machine_data; diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c index 53be6491320..8bc5cd9e972 100644 --- a/sound/soc/fsl/soc-of-simple.c +++ b/sound/soc/fsl/soc-of-simple.c @@ -158,7 +158,7 @@ int of_snd_soc_register_platform(struct snd_soc_platform *platform, of_soc->platform_node = node; of_soc->dai_link.cpu_dai = cpu_dai; - of_soc->device.platform = platform; + of_soc->card.platform = platform; of_soc->card.name = of_soc->dai_link.cpu_dai->name; /* Now try to register the SoC device */ diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 18e2062e3a1..25593fee912 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -288,6 +288,7 @@ static struct snd_soc_dai_link n810_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_n810 = { .name = "N810", + .platform = &omap_soc_platform, .dai_link = &n810_dai, .num_links = 1, }; @@ -303,7 +304,6 @@ static struct aic3x_setup_data n810_aic33_setup = { /* Audio subsystem */ static struct snd_soc_device n810_snd_devdata = { .card = &snd_soc_n810, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &n810_aic33_setup, }; diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index 7b160f9d83f..0c2322dcf02 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -93,6 +93,7 @@ static struct snd_soc_dai_link omap2evm_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_omap2evm = { .name = "omap2evm", + .platform = &omap_soc_platform, .dai_link = &omap2evm_dai, .num_links = 1, }; @@ -100,7 +101,6 @@ static struct snd_soc_card snd_soc_omap2evm = { /* Audio subsystem */ static struct snd_soc_device omap2evm_snd_devdata = { .card = &snd_soc_omap2evm, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index 3ed25464627..fd24a4acd2f 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -90,6 +90,7 @@ static struct snd_soc_dai_link omap3beagle_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_omap3beagle = { .name = "omap3beagle", + .platform = &omap_soc_platform, .dai_link = &omap3beagle_dai, .num_links = 1, }; @@ -97,7 +98,6 @@ static struct snd_soc_card snd_soc_omap3beagle = { /* Audio subsystem */ static struct snd_soc_device omap3beagle_snd_devdata = { .card = &snd_soc_omap3beagle, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 7a8f14d0c77..845bf41335b 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -145,6 +145,7 @@ static struct snd_soc_dai_link osk_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_card_osk = { .name = "OSK5912", + .platform = &omap_soc_platform, .dai_link = &osk_dai, .num_links = 1, }; @@ -152,7 +153,6 @@ static struct snd_soc_card snd_soc_card_osk = { /* Audio subsystem */ static struct snd_soc_device osk_snd_devdata = { .card = &snd_soc_card_osk, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_tlv320aic23, }; diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index eea0c372bb3..a72dc4e159e 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -90,6 +90,7 @@ static struct snd_soc_dai_link overo_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_card_overo = { .name = "overo", + .platform = &omap_soc_platform, .dai_link = &overo_dai, .num_links = 1, }; @@ -97,7 +98,6 @@ static struct snd_soc_card snd_soc_card_overo = { /* Audio subsystem */ static struct snd_soc_device overo_snd_devdata = { .card = &snd_soc_card_overo, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index 85fd160bca1..ad97836818b 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -93,6 +93,7 @@ static struct snd_soc_dai_link sdp3430_dai = { /* Audio machine driver */ static struct snd_soc_machine snd_soc_machine_sdp3430 = { .name = "SDP3430", + .platform = &omap_soc_platform, .dai_link = &sdp3430_dai, .num_links = 1, }; @@ -100,7 +101,6 @@ static struct snd_soc_machine snd_soc_machine_sdp3430 = { /* Audio subsystem */ static struct snd_soc_device sdp3430_snd_devdata = { .machine = &snd_soc_machine_sdp3430, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index e56bf4b6c2a..1ba25a55952 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -312,6 +312,7 @@ static struct snd_soc_dai_link corgi_dai = { /* corgi audio machine driver */ static struct snd_soc_card snd_soc_corgi = { .name = "Corgi", + .platform = &pxa2xx_soc_platform, .dai_link = &corgi_dai, .num_links = 1, }; @@ -325,7 +326,6 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { .card = &snd_soc_corgi, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, }; diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 60c64861512..2e3386dfa0f 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -42,13 +42,13 @@ static struct snd_soc_dai_link e800_dai[] = { static struct snd_soc_card e800 = { .name = "Toshiba e800", + .platform = &pxa2xx_soc_platform, .dai_link = e800_dai, .num_links = ARRAY_SIZE(e800_dai), }; static struct snd_soc_device e800_snd_devdata = { .card = &e800, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index d6884b755d5..fe4a729ea64 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -54,13 +54,13 @@ static struct snd_soc_dai_link em_x270_dai[] = { static struct snd_soc_card em_x270 = { .name = "EM-X270", + .platform = &pxa2xx_soc_platform, .dai_link = em_x270_dai, .num_links = ARRAY_SIZE(em_x270_dai), }; static struct snd_soc_device em_x270_snd_devdata = { .card = &em_x270, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 3bb8879ac8a..4a9cf3083af 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -191,13 +191,13 @@ static struct snd_soc_dai_link palm27x_dai[] = { static struct snd_soc_card palm27x_asoc = { .name = "Palm/PXA27x", + .platform = &pxa2xx_soc_platform, .dai_link = palm27x_dai, .num_links = ARRAY_SIZE(palm27x_dai), }; static struct snd_soc_device palm27x_snd_devdata = { .card = &palm27x_asoc, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 03b510ab282..6e9827189ff 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -278,6 +278,7 @@ static struct snd_soc_dai_link poodle_dai = { /* poodle audio machine driver */ static struct snd_soc_card snd_soc_poodle = { .name = "Poodle", + .platform = &pxa2xx_soc_platform, .dai_link = &poodle_dai, .num_links = 1, }; @@ -291,7 +292,6 @@ static struct wm8731_setup_data poodle_wm8731_setup = { /* poodle audio subsystem */ static struct snd_soc_device poodle_snd_devdata = { .card = &snd_soc_poodle, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &poodle_wm8731_setup, }; diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 579d93368f1..a3b9e6bdf97 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -321,6 +321,7 @@ static struct snd_soc_dai_link spitz_dai = { /* spitz audio machine driver */ static struct snd_soc_card snd_soc_spitz = { .name = "Spitz", + .platform = &pxa2xx_soc_platform, .dai_link = &spitz_dai, .num_links = 1, }; @@ -334,7 +335,6 @@ static struct wm8750_setup_data spitz_wm8750_setup = { /* spitz audio subsystem */ static struct snd_soc_device spitz_snd_devdata = { .card = &snd_soc_spitz, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8750, .codec_data = &spitz_wm8750_setup, }; diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 48242b32a28..c77194f74c9 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -252,6 +252,7 @@ static int tosa_remove(struct platform_device *dev) static struct snd_soc_card tosa = { .name = "Tosa", + .platform = &pxa2xx_soc_platform, .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), .probe = tosa_probe, @@ -260,7 +261,6 @@ static struct snd_soc_card tosa = { static struct snd_soc_device tosa_snd_devdata = { .card = &tosa, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 842d6500d61..f8e9ecd589d 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -175,13 +175,13 @@ static struct snd_soc_dai_link zylonite_dai[] = { static struct snd_soc_card zylonite = { .name = "Zylonite", + .platform = &pxa2xx_soc_platform, .dai_link = zylonite_dai, .num_links = ARRAY_SIZE(zylonite_dai), }; static struct snd_soc_device zylonite_snd_ac97_devdata = { .card = &zylonite, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9713, }; diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index a70cbc0fa07..12c71482d25 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -40,13 +40,13 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { static struct snd_soc_card ln2440sbc = { .name = "LN2440SBC", + .platform = &s3c24xx_soc_platform, .dai_link = ln2440sbc_dai, .num_links = ARRAY_SIZE(ln2440sbc_dai), }; static struct snd_soc_device ln2440sbc_snd_ac97_devdata = { .card = &ln2440sbc, - .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 3df2224a672..45bb12e8ea4 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -580,6 +580,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { static struct snd_soc_card neo1973 = { .name = "neo1973", + .platform = &s3c24xx_soc_platform, .dai_link = neo1973_dai, .num_links = ARRAY_SIZE(neo1973_dai), }; @@ -591,7 +592,6 @@ static struct wm8753_setup_data neo1973_wm8753_setup = { static struct snd_soc_device neo1973_snd_devdata = { .card = &neo1973, - .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_wm8753, .codec_data = &neo1973_wm8753_setup, }; diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index 23325fca1f6..a0a4d1832a1 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -234,6 +234,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { static struct snd_soc_card snd_soc_s3c24xx_uda134x = { .name = "S3C24XX_UDA134X", + .platform = &s3c24xx_soc_platform, .dai_link = &s3c24xx_uda134x_dai_link, .num_links = 1, }; @@ -271,7 +272,6 @@ static struct uda134x_platform_data s3c24xx_uda134x = { static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { .card = &snd_soc_s3c24xx_uda134x, - .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_uda134x, .codec_data = &s3c24xx_uda134x, }; diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index 3d2e6a0417e..a2a4f5323c1 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -36,13 +36,13 @@ static struct snd_soc_dai_link smdk2443_dai[] = { static struct snd_soc_card smdk2443 = { .name = "SMDK2443", + .platform = &s3c24xx_soc_platform, .dai_link = smdk2443_dai, .num_links = ARRAY_SIZE(smdk2443_dai), }; static struct snd_soc_device smdk2443_snd_ac97_devdata = { .card = &smdk2443, - .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index 8b44f9c8a9f..ce7f95b59de 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c @@ -40,13 +40,13 @@ static struct snd_soc_dai_link sh7760_ac97_dai = { static struct snd_soc_card sh7760_ac97_soc_machine = { .name = "SH7760 AC97", + .platform = &sh7760_soc_platform, .dai_link = &sh7760_ac97_dai, .num_links = 1, }; static struct snd_soc_device sh7760_ac97_snd_devdata = { .card = &sh7760_ac97_soc_machine, - .platform = &sh7760_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c4b22e6984e..fe89260c902 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -109,9 +109,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card = socdev->card; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret = 0; @@ -302,7 +303,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -370,7 +371,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -464,7 +465,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_card *card = socdev->card; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret = 0; @@ -534,7 +536,8 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_card *card = socdev->card; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -568,8 +571,9 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card= socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret; @@ -610,7 +614,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; int i; @@ -686,7 +690,7 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_card, deferred_resume_work); struct snd_soc_device *socdev = card->socdev; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; struct platform_device *pdev = to_platform_device(socdev->dev); @@ -770,7 +774,7 @@ static int soc_probe(struct platform_device *pdev) int ret = 0, i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; /* Bodge while we push things out of socdev */ @@ -835,7 +839,7 @@ static int soc_remove(struct platform_device *pdev) int i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; run_delayed_work(&card->delayed_work); @@ -875,6 +879,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, struct snd_soc_dai_link *dai_link, int num) { struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_card *card = socdev->card; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *codec_dai = dai_link->codec_dai; struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; struct snd_soc_pcm_runtime *rtd; @@ -910,13 +916,13 @@ static int soc_new_pcm(struct snd_soc_device *socdev, dai_link->pcm = pcm; pcm->private_data = rtd; - soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; - soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; - soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl; - soc_pcm_ops.copy = socdev->platform->pcm_ops->copy; - soc_pcm_ops.silence = socdev->platform->pcm_ops->silence; - soc_pcm_ops.ack = socdev->platform->pcm_ops->ack; - soc_pcm_ops.page = socdev->platform->pcm_ops->page; + soc_pcm_ops.mmap = platform->pcm_ops->mmap; + soc_pcm_ops.pointer = platform->pcm_ops->pointer; + soc_pcm_ops.ioctl = platform->pcm_ops->ioctl; + soc_pcm_ops.copy = platform->pcm_ops->copy; + soc_pcm_ops.silence = platform->pcm_ops->silence; + soc_pcm_ops.ack = platform->pcm_ops->ack; + soc_pcm_ops.page = platform->pcm_ops->page; if (playback) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); @@ -924,14 +930,14 @@ static int soc_new_pcm(struct snd_soc_device *socdev, if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); - ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm); + ret = platform->pcm_new(codec->card, codec_dai, pcm); if (ret < 0) { printk(KERN_ERR "asoc: platform pcm constructor failed\n"); kfree(rtd); return ret; } - pcm->private_free = socdev->platform->pcm_free; + pcm->private_free = platform->pcm_free; printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; -- cgit v1.2.3 From 5920b45303291057fef827f5bdafe04001c1bbae Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Tue, 2 Dec 2008 20:48:58 +0200 Subject: ASoC: TWL4030: Add input selection and gain controls The TWL4030 codec device has two ADCs. Both of them can have several inputs routed to them, but TRM says that only one source can be selected for every ADC, even though every source has a dedicated bit in the registers. This patch adds input source controls. It modifies default register values to have no inputs selected and ADCs disabled. When some input is selected, control handlers enable apropriate input amplifier and ADC. If a microphone is selected, bias power is automatically enabled. When some input is deselected, unused chip parts are disabled. Microphone and line input recording tested on OMAP3 pandora board. Signed-off-by: Grazvydas Ignotas Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 177 ++++++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/twl4030.h | 16 ++++ 2 files changed, 190 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ffd5120697a..3c9fdf2c6c7 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -46,9 +46,9 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0xc3, /* REG_OPTION (0x2) */ 0x00, /* REG_UNKNOWN (0x3) */ 0x00, /* REG_MICBIAS_CTL (0x4) */ - 0x24, /* REG_ANAMICL (0x5) */ - 0x04, /* REG_ANAMICR (0x6) */ - 0x0a, /* REG_AVADC_CTL (0x7) */ + 0x20, /* REG_ANAMICL (0x5) */ + 0x00, /* REG_ANAMICR (0x6) */ + 0x00, /* REG_AVADC_CTL (0x7) */ 0x00, /* REG_ADCMICSEL (0x8) */ 0x00, /* REG_DIGMIXING (0x9) */ 0x0c, /* REG_ATXL1PGA (0xA) */ @@ -347,6 +347,162 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, return err; } +static int twl4030_get_left_input(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); + int result = 0; + + /* one bit must be set a time */ + reg &= TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN + | TWL4030_MAINMIC_EN; + if (reg != 0) { + result++; + while ((reg & 1) == 0) { + result++; + reg >>= 1; + } + } + + ucontrol->value.integer.value[0] = result; + return 0; +} + +static int twl4030_put_left_input(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + int value = ucontrol->value.integer.value[0]; + u8 anamicl, micbias, avadc_ctl; + + anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); + anamicl &= ~(TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN + | TWL4030_MAINMIC_EN); + micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); + micbias &= ~(TWL4030_HSMICBIAS_EN | TWL4030_MICBIAS1_EN); + avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); + + switch (value) { + case 1: + anamicl |= TWL4030_MAINMIC_EN; + micbias |= TWL4030_MICBIAS1_EN; + break; + case 2: + anamicl |= TWL4030_HSMIC_EN; + micbias |= TWL4030_HSMICBIAS_EN; + break; + case 3: + anamicl |= TWL4030_AUXL_EN; + break; + case 4: + anamicl |= TWL4030_CKMIC_EN; + break; + default: + break; + } + + /* If some input is selected, enable amp and ADC */ + if (value != 0) { + anamicl |= TWL4030_MICAMPL_EN; + avadc_ctl |= TWL4030_ADCL_EN; + } else { + anamicl &= ~TWL4030_MICAMPL_EN; + avadc_ctl &= ~TWL4030_ADCL_EN; + } + + twl4030_write(codec, TWL4030_REG_ANAMICL, anamicl); + twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); + twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); + + return 1; +} + +static int twl4030_get_right_input(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); + int value = 0; + + reg &= TWL4030_SUBMIC_EN|TWL4030_AUXR_EN; + switch (reg) { + case TWL4030_SUBMIC_EN: + value = 1; + break; + case TWL4030_AUXR_EN: + value = 2; + break; + default: + break; + } + + ucontrol->value.integer.value[0] = value; + return 0; +} + +static int twl4030_put_right_input(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + int value = ucontrol->value.integer.value[0]; + u8 anamicr, micbias, avadc_ctl; + + anamicr = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); + anamicr &= ~(TWL4030_SUBMIC_EN|TWL4030_AUXR_EN); + micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); + micbias &= ~TWL4030_MICBIAS2_EN; + avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); + + switch (value) { + case 1: + anamicr |= TWL4030_SUBMIC_EN; + micbias |= TWL4030_MICBIAS2_EN; + break; + case 2: + anamicr |= TWL4030_AUXR_EN; + break; + default: + break; + } + + if (value != 0) { + anamicr |= TWL4030_MICAMPR_EN; + avadc_ctl |= TWL4030_ADCR_EN; + } else { + anamicr &= ~TWL4030_MICAMPR_EN; + avadc_ctl &= ~TWL4030_ADCR_EN; + } + + twl4030_write(codec, TWL4030_REG_ANAMICR, anamicr); + twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); + twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); + + return 1; +} + +static const char *twl4030_left_in_sel[] = { + "None", + "Main Mic", + "Headset Mic", + "Line In", + "Carkit Mic", +}; + +static const char *twl4030_right_in_sel[] = { + "None", + "Sub Mic", + "Line In", +}; + +static const struct soc_enum twl4030_left_input_mux = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_left_in_sel), + twl4030_left_in_sel); + +static const struct soc_enum twl4030_right_input_mux = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_right_in_sel), + twl4030_right_in_sel); + /* * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) @@ -378,6 +534,12 @@ static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1); */ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); +/* + * Gain control for input amplifiers + * 0 dB to 30 dB in 6 dB steps + */ +static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { /* Common playback gain controls */ SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", @@ -420,6 +582,15 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, 0, 0x1f, 0, digital_capture_tlv), + + SOC_DOUBLE_TLV("Input Boost Volume", TWL4030_REG_ANAMIC_GAIN, + 0, 3, 5, 0, input_gain_tlv), + + /* Input source controls */ + SOC_ENUM_EXT("Left Input Source", twl4030_left_input_mux, + twl4030_get_left_input, twl4030_put_left_input), + SOC_ENUM_EXT("Right Input Source", twl4030_right_input_mux, + twl4030_get_right_input, twl4030_put_right_input), }; /* add non dapm controls */ diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index 09865d9f520..a2065d417c2 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -113,7 +113,16 @@ #define TWL4030_CODECPDZ 0x02 #define TWL4030_OPT_MODE 0x01 +/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ + +#define TWL4030_MICBIAS2_CTL 0x40 +#define TWL4030_MICBIAS1_CTL 0x20 +#define TWL4030_HSMICBIAS_EN 0x04 +#define TWL4030_MICBIAS2_EN 0x02 +#define TWL4030_MICBIAS1_EN 0x01 + /* ANAMICL (0x05) Fields */ + #define TWL4030_CNCL_OFFSET_START 0x80 #define TWL4030_OFFSET_CNCL_SEL 0x60 #define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 @@ -127,10 +136,17 @@ #define TWL4030_MAINMIC_EN 0x01 /* ANAMICR (0x06) Fields */ + #define TWL4030_MICAMPR_EN 0x10 #define TWL4030_AUXR_EN 0x04 #define TWL4030_SUBMIC_EN 0x01 +/* AVADC_CTL (0x07) Fields */ + +#define TWL4030_ADCL_EN 0x08 +#define TWL4030_AVADC_CLK_PRIORITY 0x04 +#define TWL4030_ADCR_EN 0x02 + /* AUDIO_IF (0x0E) Fields */ #define TWL4030_AIF_SLAVE_EN 0x80 -- cgit v1.2.3 From 4b4fffdd9d179677cb030e97869286b62df25adc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 11:21:08 +0000 Subject: ASoC: Fix WM8903 right mixer bypass path Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 393a4c19882..3c83b797307 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -773,14 +773,14 @@ static const struct snd_kcontrol_new left_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), -SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), +SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 0, 1, 0), }; static const struct snd_kcontrol_new right_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0), SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), -SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), +SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 0, 1, 0), }; static const struct snd_kcontrol_new left_speaker_mixer[] = { @@ -788,7 +788,7 @@ SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, - 1, 1, 0), + 0, 1, 0), }; static const struct snd_kcontrol_new right_speaker_mixer[] = { @@ -797,7 +797,7 @@ SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 1, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, - 1, 1, 0), + 0, 1, 0), }; static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = { -- cgit v1.2.3 From 6f2a974bfc8d3be7a30674c71e2fef003b39a8d2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Dec 2008 11:44:17 +0100 Subject: ASoC: tlv320aic3x: headset/button press support - Add aic3x_set_headset_detection() function to define the headset detection mode for tlv32aic3x chips - added aic3x_button_pressed() - Read from the real-time registers in aic3x_headset_detected() to query headset presence without an occured interrupt Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 31 ++++++++++++++++++++++++++-- sound/soc/codecs/tlv320aic3x.h | 46 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 0f4067bdd4a..341e1adc916 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1018,14 +1018,41 @@ int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) } EXPORT_SYMBOL_GPL(aic3x_get_gpio); +void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, + int headset_debounce, int button_debounce) +{ + u8 val; + + val = ((detect & AIC3X_HEADSET_DETECT_MASK) + << AIC3X_HEADSET_DETECT_SHIFT) | + ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK) + << AIC3X_HEADSET_DEBOUNCE_SHIFT) | + ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK) + << AIC3X_BUTTON_DEBOUNCE_SHIFT); + + if (detect & AIC3X_HEADSET_DETECT_MASK) + val |= AIC3X_HEADSET_DETECT_ENABLED; + + aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); +} +EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); + int aic3x_headset_detected(struct snd_soc_codec *codec) { u8 val; - aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); - return (val >> 2) & 1; + aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); + return (val >> 4) & 1; } EXPORT_SYMBOL_GPL(aic3x_headset_detected); +int aic3x_button_pressed(struct snd_soc_codec *codec) +{ + u8 val; + aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); + return (val >> 5) & 1; +} +EXPORT_SYMBOL_GPL(aic3x_button_pressed); + #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 7e982acf399..73e35b6ec92 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -39,7 +39,9 @@ #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 /* Audio codec digital filter control register */ #define AIC3X_CODEC_DFILT_CTRL 12 - +/* Headset/button press detection register */ +#define AIC3X_HEADSET_DETECT_CTRL_A 13 +#define AIC3X_HEADSET_DETECT_CTRL_B 14 /* ADC PGA Gain control registers */ #define LADC_VOL 15 #define RADC_VOL 16 @@ -233,7 +235,49 @@ enum { void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); + +/* headset detection / button API */ + +/* The AIC3x supports detection of stereo headsets (GND + left + right signal) + * and cellular headsets (GND + speaker output + microphone input). + * It is recommended to enable MIC bias for this function to work properly. + * For more information, please refer to the datasheet. */ +enum { + AIC3X_HEADSET_DETECT_OFF = 0, + AIC3X_HEADSET_DETECT_STEREO = 1, + AIC3X_HEADSET_DETECT_CELLULAR = 2, + AIC3X_HEADSET_DETECT_BOTH = 3 +}; + +enum { + AIC3X_HEADSET_DEBOUNCE_16MS = 0, + AIC3X_HEADSET_DEBOUNCE_32MS = 1, + AIC3X_HEADSET_DEBOUNCE_64MS = 2, + AIC3X_HEADSET_DEBOUNCE_128MS = 3, + AIC3X_HEADSET_DEBOUNCE_256MS = 4, + AIC3X_HEADSET_DEBOUNCE_512MS = 5 +}; + +enum { + AIC3X_BUTTON_DEBOUNCE_0MS = 0, + AIC3X_BUTTON_DEBOUNCE_8MS = 1, + AIC3X_BUTTON_DEBOUNCE_16MS = 2, + AIC3X_BUTTON_DEBOUNCE_32MS = 3 +}; + +#define AIC3X_HEADSET_DETECT_ENABLED 0x80 +#define AIC3X_HEADSET_DETECT_SHIFT 5 +#define AIC3X_HEADSET_DETECT_MASK 3 +#define AIC3X_HEADSET_DEBOUNCE_SHIFT 2 +#define AIC3X_HEADSET_DEBOUNCE_MASK 7 +#define AIC3X_BUTTON_DEBOUNCE_SHIFT 0 +#define AIC3X_BUTTON_DEBOUNCE_MASK 3 + +/* see the enums above for valid parameters to this function */ +void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, + int headset_debounce, int button_debounce); int aic3x_headset_detected(struct snd_soc_codec *codec); +int aic3x_button_pressed(struct snd_soc_codec *codec); struct aic3x_setup_data { int i2c_bus; -- cgit v1.2.3 From 384c89e2e4cb5879b86a38414d1b3bb2b23ec8ee Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 17:34:03 +0000 Subject: ASoC: Push debugfs files out of the snd_soc_device structure This is in preparation for the removal of struct snd_soc_device. The pop time configuration should really be a property of the card not the codec but since DAPM currently uses the codec rather than the card using the codec is fine for now. Signed-off-by: Mark Brown --- include/sound/soc.h | 8 +++--- sound/soc/soc-core.c | 73 +++++++++++++++++++++++++++++----------------------- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ad8141acd6b..3ee608dce2f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -279,6 +279,11 @@ struct snd_soc_codec { /* codec DAI's */ struct snd_soc_dai *dai; unsigned int num_dai; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_reg; + struct dentry *debugfs_pop_time; +#endif }; /* codec device */ @@ -364,9 +369,6 @@ struct snd_soc_device { struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; void *codec_data; -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_root; -#endif }; /* runtime channel data */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fe89260c902..34114398b91 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -39,6 +39,10 @@ static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); +#ifdef CONFIG_DEBUG_FS +static struct dentry *debugfs_root; +#endif + /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -1002,7 +1006,9 @@ static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { ssize_t ret; - struct snd_soc_device *devdata = file->private_data; + struct snd_soc_codec *codec = file->private_data; + struct device *card_dev = codec->card->dev; + struct snd_soc_device *devdata = card_dev->driver_data; char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1021,8 +1027,7 @@ static ssize_t codec_reg_write_file(struct file *file, char *start = buf; unsigned long reg, value; int step = 1; - struct snd_soc_device *devdata = file->private_data; - struct snd_soc_codec *codec = devdata->codec; + struct snd_soc_codec *codec = file->private_data; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) @@ -1051,44 +1056,36 @@ static const struct file_operations codec_reg_fops = { .write = codec_reg_write_file, }; -static void soc_init_debugfs(struct snd_soc_device *socdev) +static void soc_init_codec_debugfs(struct snd_soc_codec *codec) { - struct dentry *root, *file; - struct snd_soc_codec *codec = socdev->codec; - root = debugfs_create_dir(dev_name(socdev->dev), NULL); - if (IS_ERR(root) || !root) - goto exit1; - - file = debugfs_create_file("codec_reg", 0644, - root, socdev, &codec_reg_fops); - if (!file) - goto exit2; - - file = debugfs_create_u32("dapm_pop_time", 0744, - root, &codec->pop_time); - if (!file) - goto exit2; - socdev->debugfs_root = root; - return; -exit2: - debugfs_remove_recursive(root); -exit1: - dev_err(socdev->dev, "debugfs is not available\n"); + codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, + debugfs_root, codec, + &codec_reg_fops); + if (!codec->debugfs_reg) + printk(KERN_WARNING + "ASoC: Failed to create codec register debugfs file\n"); + + codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, + debugfs_root, + &codec->pop_time); + if (!codec->debugfs_pop_time) + printk(KERN_WARNING + "Failed to create pop time debugfs file\n"); } -static void soc_cleanup_debugfs(struct snd_soc_device *socdev) +static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) { - debugfs_remove_recursive(socdev->debugfs_root); - socdev->debugfs_root = NULL; + debugfs_remove(codec->debugfs_pop_time); + debugfs_remove(codec->debugfs_reg); } #else -static inline void soc_init_debugfs(struct snd_soc_device *socdev) +static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) { } -static inline void soc_cleanup_debugfs(struct snd_soc_device *socdev) +static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) { } #endif @@ -1305,7 +1302,7 @@ int snd_soc_init_card(struct snd_soc_device *socdev) if (err < 0) printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); - soc_init_debugfs(socdev); + soc_init_codec_debugfs(socdev->codec); mutex_unlock(&codec->mutex); out: @@ -1329,7 +1326,7 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) #endif mutex_lock(&codec->mutex); - soc_cleanup_debugfs(socdev); + soc_cleanup_codec_debugfs(socdev->codec); #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; @@ -1962,11 +1959,23 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); static int __devinit snd_soc_init(void) { +#ifdef CONFIG_DEBUG_FS + debugfs_root = debugfs_create_dir("asoc", NULL); + if (IS_ERR(debugfs_root) || !debugfs_root) { + printk(KERN_WARNING + "ASoC: Failed to create debugfs directory\n"); + debugfs_root = NULL; + } +#endif + return platform_driver_register(&soc_driver); } static void __exit snd_soc_exit(void) { +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(debugfs_root); +#endif platform_driver_unregister(&soc_driver); } -- cgit v1.2.3 From 07c84d0409f3551b79d676630d8ee76bb551598d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 18:17:28 +0000 Subject: ASoC: Remove device from platform suspend and resume operations None of the platforms are actually using the SoC device so remove it (only atmel actually has a suspend method). Signed-off-by: Mark Brown --- include/sound/soc.h | 6 ++---- sound/soc/atmel/atmel-pcm.c | 6 ++---- sound/soc/soc-core.c | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3ee608dce2f..8ec63c02dc1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -300,10 +300,8 @@ struct snd_soc_platform { int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); - int (*suspend)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*resume)(struct platform_device *pdev, - struct snd_soc_dai *dai); + int (*suspend)(struct snd_soc_dai *dai); + int (*resume)(struct snd_soc_dai *dai); /* pcm creation and destruction */ int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 394412fb396..8507aa1cd81 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -417,8 +417,7 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) } #ifdef CONFIG_PM -static int atmel_pcm_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int atmel_pcm_suspend(struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = dai->runtime; struct atmel_runtime_data *prtd; @@ -442,8 +441,7 @@ static int atmel_pcm_suspend(struct platform_device *pdev, return 0; } -static int atmel_pcm_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int atmel_pcm_resume(struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = dai->runtime; struct atmel_runtime_data *prtd; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 34114398b91..f83852f1146 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -652,7 +652,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) if (cpu_dai->suspend && !cpu_dai->ac97_control) cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) - platform->suspend(pdev, cpu_dai); + platform->suspend(cpu_dai); } /* close any waiting streams and save state */ @@ -741,7 +741,7 @@ static void soc_resume_deferred(struct work_struct *work) if (cpu_dai->resume && !cpu_dai->ac97_control) cpu_dai->resume(pdev, cpu_dai); if (platform->resume) - platform->resume(pdev, cpu_dai); + platform->resume(cpu_dai); } if (card->resume_post) -- cgit v1.2.3 From dc7d7b830ee1f4111696e73d1c25da683b461548 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 18:21:52 +0000 Subject: ASoC: Remove platform device from DAI suspend and resume operations None of the DAIs use it except s3c2412-i2s which only uses it for dev_() printouts. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 6 ++---- sound/soc/atmel/atmel_ssc_dai.c | 6 ++---- sound/soc/au1x/psc-ac97.c | 6 ++---- sound/soc/au1x/psc-i2s.c | 6 ++---- sound/soc/blackfin/bf5xx-ac97.c | 6 ++---- sound/soc/blackfin/bf5xx-i2s.c | 6 ++---- sound/soc/pxa/pxa-ssp.c | 6 ++---- sound/soc/pxa/pxa2xx-ac97.c | 6 ++---- sound/soc/pxa/pxa2xx-i2s.c | 6 ++---- sound/soc/s3c24xx/s3c2412-i2s.c | 16 +++++++--------- sound/soc/s3c24xx/s3c24xx-i2s.c | 6 ++---- sound/soc/soc-core.c | 8 ++++---- 12 files changed, 31 insertions(+), 53 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index a01a24b1019..e2d5f76838c 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -191,10 +191,8 @@ struct snd_soc_dai { struct snd_soc_dai *dai); void (*remove)(struct platform_device *pdev, struct snd_soc_dai *dai); - int (*suspend)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*resume)(struct platform_device *pdev, - struct snd_soc_dai *dai); + int (*suspend)(struct snd_soc_dai *dai); + int (*resume)(struct snd_soc_dai *dai); /* ops */ struct snd_soc_dai_ops ops; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 0bb18dfa949..d9b874c5bf3 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -628,8 +628,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, #ifdef CONFIG_PM -static int atmel_ssc_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) { struct atmel_ssc_info *ssc_p; @@ -657,8 +656,7 @@ static int atmel_ssc_suspend(struct platform_device *pdev, -static int atmel_ssc_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) { struct atmel_ssc_info *ssc_p; u32 cr; diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index a0bcfeaf5f8..a1e824d29cf 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -314,8 +314,7 @@ static void au1xpsc_ac97_remove(struct platform_device *pdev, au1xpsc_ac97_workdata = NULL; } -static int au1xpsc_ac97_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai) { /* save interesting registers and disable PSC */ au1xpsc_ac97_workdata->pm[0] = @@ -329,8 +328,7 @@ static int au1xpsc_ac97_suspend(struct platform_device *pdev, return 0; } -static int au1xpsc_ac97_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) { /* restore PSC clock config */ au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE, diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index f4217e70a78..16f97462ea1 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -339,8 +339,7 @@ static void au1xpsc_i2s_remove(struct platform_device *pdev, au1xpsc_i2s_workdata = NULL; } -static int au1xpsc_i2s_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai) { /* save interesting register and disable PSC */ au1xpsc_i2s_workdata->pm[0] = @@ -354,8 +353,7 @@ static int au1xpsc_i2s_suspend(struct platform_device *pdev, return 0; } -static int au1xpsc_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai) { /* select I2S mode and PSC clock */ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 709bdf08e39..c602ce109d5 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -269,8 +269,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); #ifdef CONFIG_PM -static int bf5xx_ac97_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) { struct sport_device *sport = (struct sport_device *)dai->private_data; @@ -285,8 +284,7 @@ static int bf5xx_ac97_suspend(struct platform_device *pdev, return 0; } -static int bf5xx_ac97_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int bf5xx_ac97_resume(struct snd_soc_dai *dai) { int ret; struct sport_device *sport = diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 6e5036bf924..9f8ce87cc6c 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -222,16 +222,14 @@ static int bf5xx_i2s_probe(struct platform_device *pdev, return 0; } -static void bf5xx_i2s_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static void bf5xx_i2s_remove(struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); peripheral_free_list(&sport_req[sport_num][0]); } #ifdef CONFIG_PM -static int bf5xx_i2s_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) +static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) { struct sport_device *sport = (struct sport_device *)dai->private_data; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 402fc5ba65e..73fa10defcc 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -244,8 +244,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, #ifdef CONFIG_PM -static int pxa_ssp_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = cpu_dai->private_data; @@ -257,8 +256,7 @@ static int pxa_ssp_suspend(struct platform_device *pdev, return 0; } -static int pxa_ssp_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = cpu_dai->private_data; diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index bffbe288634..8eed80d5675 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -87,14 +87,12 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { }; #ifdef CONFIG_PM -static int pxa2xx_ac97_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int pxa2xx_ac97_suspend(struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_suspend(); } -static int pxa2xx_ac97_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int pxa2xx_ac97_resume(struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_resume(); } diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index f9a9e2ebafa..314973ace6d 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -293,8 +293,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, } #ifdef CONFIG_PM -static int pxa2xx_i2s_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) +static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) { if (!dai->active) return 0; @@ -311,8 +310,7 @@ static int pxa2xx_i2s_suspend(struct platform_device *dev, return 0; } -static int pxa2xx_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) { if (!dai->active) return 0; diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 1c741047ae3..75f87c3c74d 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -649,8 +649,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, } #ifdef CONFIG_PM -static int s3c2412_i2s_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) +static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; u32 iismod; @@ -665,25 +664,24 @@ static int s3c2412_i2s_suspend(struct platform_device *dev, iismod = readl(i2s->regs + S3C2412_IISMOD); if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) - dev_warn(&dev->dev, "%s: RXDMA active?\n", __func__); + pr_warning("%s: RXDMA active?\n", __func__); if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) - dev_warn(&dev->dev, "%s: TXDMA active?\n", __func__); + pr_warning("%s: TXDMA active?\n", __func__); if (iismod & S3C2412_IISCON_IIS_ACTIVE) - dev_warn(&dev->dev, "%s: IIS active\n", __func__); + pr_warning("%s: IIS active\n", __func__); } return 0; } -static int s3c2412_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int s3c2412_i2s_resume(struct snd_soc_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; - dev_info(&pdev->dev, "dai_active %d, IISMOD %08x, IISCON %08x\n", - dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); + pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", + dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); if (dai->active) { writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 8d9135f41bc..45fe8f7c88a 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -419,8 +419,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, } #ifdef CONFIG_PM -static int s3c24xx_i2s_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) { DBG("Entered %s\n", __func__); @@ -434,8 +433,7 @@ static int s3c24xx_i2s_suspend(struct platform_device *pdev, return 0; } -static int s3c24xx_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) { DBG("Entered %s\n", __func__); clk_enable(s3c24xx_i2s.iis_clk); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f83852f1146..2f2a8d93bbf 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -650,7 +650,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->suspend && !cpu_dai->ac97_control) - cpu_dai->suspend(pdev, cpu_dai); + cpu_dai->suspend(cpu_dai); if (platform->suspend) platform->suspend(cpu_dai); } @@ -676,7 +676,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->suspend && cpu_dai->ac97_control) - cpu_dai->suspend(pdev, cpu_dai); + cpu_dai->suspend(cpu_dai); } if (card->suspend_post) @@ -712,7 +712,7 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->resume && cpu_dai->ac97_control) - cpu_dai->resume(pdev, cpu_dai); + cpu_dai->resume(cpu_dai); } if (codec_dev->resume) @@ -739,7 +739,7 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->resume && !cpu_dai->ac97_control) - cpu_dai->resume(pdev, cpu_dai); + cpu_dai->resume(cpu_dai); if (platform->resume) platform->resume(cpu_dai); } -- cgit v1.2.3 From 32c8dabc97d436582298ebd0e33af041c69f5a4b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 19:41:13 +0000 Subject: ASoC: Remove obsolete declaration of struct snd_soc_clock_info The struct is never defined. Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 8ec63c02dc1..79d855d2bdd 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -152,7 +152,6 @@ struct snd_soc_dai; struct snd_soc_codec; struct soc_enum; struct snd_soc_ac97_ops; -struct snd_soc_clock_info; typedef int (*hw_write_t)(void *,const char* ,int); typedef int (*hw_read_t)(void *,char* ,int); -- cgit v1.2.3 From 68fb740774a429ecbccd4d8b3287cf4883ad3ec2 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Thu, 4 Dec 2008 22:39:54 +0200 Subject: ASoC: Add support for OMAP3 Pandora This patch adds basic support for OMAP3 Pandora. Signed-off-by: Grazvydas Ignotas Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 8 ++ sound/soc/omap/Makefile | 2 + sound/soc/omap/omap3pandora.c | 311 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 sound/soc/omap/omap3pandora.c diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index da39f27c661..a7b1d77b210 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -46,3 +46,11 @@ config SND_OMAP_SOC_SDP3430 help Say Y if you want to add support for SoC audio on Texas Instruments SDP3430. + +config SND_OMAP_SOC_OMAP3_PANDORA + tristate "SoC Audio support for OMAP3 Pandora" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the OMAP3 Pandora. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 29cf3a856c8..76fedd96e36 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -11,9 +11,11 @@ snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o snd-soc-omap2evm-objs := omap2evm.o snd-soc-sdp3430-objs := sdp3430.o +snd-soc-omap3pandora-objs := omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c new file mode 100644 index 00000000000..bd91594496b --- /dev/null +++ b/sound/soc/omap/omap3pandora.c @@ -0,0 +1,311 @@ +/* + * omap3pandora.c -- SoC audio for Pandora Handheld Console + * + * Author: Gražvydas Ignotas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +#define OMAP3_PANDORA_DAC_POWER_GPIO 118 +#define OMAP3_PANDORA_AMP_POWER_GPIO 14 + +#define PREFIX "ASoC omap3pandora: " + +static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, + struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + pr_err(PREFIX "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_err(PREFIX "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + pr_err(PREFIX "can't set codec system clock\n"); + return ret; + } + + /* Set McBSP clock to external */ + ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + pr_err(PREFIX "can't set cpu system clock\n"); + return ret; + } + + ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8); + if (ret < 0) { + pr_err(PREFIX "can't set SRG clock divider\n"); + return ret; + } + + return 0; +} + +static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFS); +} + +static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); +} + +static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); + gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1); + } else { + gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0); + mdelay(1); + gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); + } + + return 0; +} + +/* + * Audio paths on Pandora board: + * + * |O| ---> PCM DAC +-> AMP -> Headphone Jack + * |M| A +--------> Line Out + * |A| <~~clk~~+ + * |P| <--- TWL4030 <--------- Line In and MICs + */ +static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { + SND_SOC_DAPM_DAC("PCM DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, + 0, 0, NULL, 0, omap3pandora_hp_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), +}; + +static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic (Internal)", NULL), + SND_SOC_DAPM_MIC("Mic (external)", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static const struct snd_soc_dapm_route omap3pandora_out_map[] = { + {"Headphone Amplifier", NULL, "PCM DAC"}, + {"Line Out", NULL, "PCM DAC"}, + {"Headphone Jack", NULL, "Headphone Amplifier"}, +}; + +static const struct snd_soc_dapm_route omap3pandora_in_map[] = { + {"INL", NULL, "Line In"}, + {"INR", NULL, "Line In"}, + {"INL", NULL, "Mic (Internal)"}, + {"INR", NULL, "Mic (external)"}, +}; + +static int omap3pandora_out_init(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets, + ARRAY_SIZE(omap3pandora_out_dapm_widgets)); + if (ret < 0) + return ret; + + snd_soc_dapm_add_routes(codec, omap3pandora_out_map, + ARRAY_SIZE(omap3pandora_out_map)); + + return snd_soc_dapm_sync(codec); +} + +static int omap3pandora_in_init(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, + ARRAY_SIZE(omap3pandora_in_dapm_widgets)); + if (ret < 0) + return ret; + + snd_soc_dapm_add_routes(codec, omap3pandora_in_map, + ARRAY_SIZE(omap3pandora_in_map)); + + return snd_soc_dapm_sync(codec); +} + +static struct snd_soc_ops omap3pandora_out_ops = { + .hw_params = omap3pandora_out_hw_params, +}; + +static struct snd_soc_ops omap3pandora_in_ops = { + .hw_params = omap3pandora_in_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap3pandora_dai[] = { + { + .name = "PCM1773", + .stream_name = "HiFi Out", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap3pandora_out_ops, + .init = omap3pandora_out_init, + }, { + .name = "TWL4030", + .stream_name = "Line/Mic In", + .cpu_dai = &omap_mcbsp_dai[1], + .codec_dai = &twl4030_dai, + .ops = &omap3pandora_in_ops, + .init = omap3pandora_in_init, + } +}; + +/* SoC card */ +static struct snd_soc_card snd_soc_card_omap3pandora = { + .name = "omap3pandora", + .platform = &omap_soc_platform, + .dai_link = omap3pandora_dai, + .num_links = ARRAY_SIZE(omap3pandora_dai), +}; + +/* Audio subsystem */ +static struct snd_soc_device omap3pandora_snd_data = { + .card = &snd_soc_card_omap3pandora, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap3pandora_snd_device; + +static int __init omap3pandora_soc_init(void) +{ + int ret; + + if (!machine_is_omap3_pandora()) { + pr_debug(PREFIX "Not OMAP3 Pandora\n"); + return -ENODEV; + } + pr_info("OMAP3 Pandora SoC init\n"); + + ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power"); + if (ret) { + pr_err(PREFIX "Failed to get DAC power GPIO\n"); + return ret; + } + + ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0); + if (ret) { + pr_err(PREFIX "Failed to set DAC power GPIO direction\n"); + goto fail0; + } + + ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power"); + if (ret) { + pr_err(PREFIX "Failed to get amp power GPIO\n"); + goto fail0; + } + + ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0); + if (ret) { + pr_err(PREFIX "Failed to set amp power GPIO direction\n"); + goto fail1; + } + + omap3pandora_snd_device = platform_device_alloc("soc-audio", -1); + if (omap3pandora_snd_device == NULL) { + pr_err(PREFIX "Platform device allocation failed\n"); + ret = -ENOMEM; + goto fail1; + } + + platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data); + omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev; + *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */ + *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */ + + ret = platform_device_add(omap3pandora_snd_device); + if (ret) { + pr_err(PREFIX "Unable to add platform device\n"); + goto fail2; + } + + return 0; + +fail2: + platform_device_put(omap3pandora_snd_device); +fail1: + gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); +fail0: + gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); + return ret; +} +module_init(omap3pandora_soc_init); + +static void __exit omap3pandora_soc_exit(void) +{ + platform_device_unregister(omap3pandora_snd_device); + gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); + gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); +} +module_exit(omap3pandora_soc_exit); + +MODULE_AUTHOR("Grazvydas Ignotas "); +MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 28a1d869560a49d960ba2a3b450ec965712e5560 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 5 Dec 2008 17:31:00 +0100 Subject: ASoC: tlv320aic3x: control additions and cleanups - split "Line Playback Switch" into "LineL Playback Switch" and "LineR Playback Switch" - split "Line PGA Bypass Playback Volume" into "LineL Left PGA Bypass Playback Volume" and "LineR Right PGA Bypass Playback Volume" - split "Line Line2 Bypass Playback Volume" into "LineL Line2 Bypass Playback Volume" and "LineR Line2 Bypass Playback Volume" - Added "HP Right PGA Bypass Playback Volume" Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 341e1adc916..6a058298a3c 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -253,11 +253,17 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, 0, 0x7f, 1), - SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, - 0x01, 0), - SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, - PGAR_2_RLOPM_VOL, 0, 0x7f, 1), - SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, + SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0), + SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0), + SOC_DOUBLE_R("LineL DAC Playback Volume", DACL1_2_LLOPM_VOL, + DACR1_2_LLOPM_VOL, 0, 0x7f, 1), + SOC_SINGLE("LineL Left PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, + 0, 0x7f, 1), + SOC_SINGLE("LineR Right PGA Bypass Playback Volume", PGAR_2_RLOPM_VOL, + 0, 0x7f, 1), + SOC_DOUBLE_R("LineL Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, + LINE2R_2_LLOPM_VOL, 0, 0x7f, 1), + SOC_DOUBLE_R("LineR Line2 Bypass Playback Volume", LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, @@ -272,6 +278,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPROUT_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, 0x01, 0), + SOC_DOUBLE_R("HP Right PGA Bypass Playback Volume", PGAR_2_HPLOUT_VOL, + PGAR_2_HPROUT_VOL, 0, 0x7f, 1), SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, 0, 0x7f, 1), SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL, -- cgit v1.2.3 From 53b5047d994edfcafabc0e95bb681ae70d6e8604 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 08:45:43 +0200 Subject: ASoC: TWL4030: Correct DAPM_DAC with power control Add all four DACs to dapm_widgets with power switch. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 3c9fdf2c6c7..3543bf6e258 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -616,8 +616,15 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), - SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0), + /* DACs */ + SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", + TWL4030_REG_AVDAC_CTL, 0, 0), + SND_SOC_DAPM_DAC("DACL1", "Left Front Playback", + TWL4030_REG_AVDAC_CTL, 1, 0), + SND_SOC_DAPM_DAC("DACR2", "Right Rear Playback", + TWL4030_REG_AVDAC_CTL, 2, 0), + SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", + TWL4030_REG_AVDAC_CTL, 3, 0), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -625,8 +632,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { static const struct snd_soc_dapm_route intercon[] = { /* outputs */ - {"OUTL", NULL, "DACL"}, - {"OUTR", NULL, "DACR"}, + {"OUTL", NULL, "DACL2"}, + {"OUTR", NULL, "DACR2"}, /* inputs */ {"ADCL", NULL, "INL"}, -- cgit v1.2.3 From 44c5587035fbbdd368a3d5d8d11997d43758078a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 08:45:44 +0200 Subject: ASoC: TWL4030: Add Analog PGA control switch to DAPM Add all four APGA switch to DAPM routing and widgets. Add user control for DA enable for all APGA as normal control. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 3543bf6e258..4293ec7b502 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -562,6 +562,12 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("DAC2 Analog Playback Volume", TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, 3, 0x12, 1, analog_tlv), + SOC_DOUBLE_R("DAC1 Analog Playback Switch", + TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL, + 1, 1, 0), + SOC_DOUBLE_R("DAC2 Analog Playback Switch", + TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, + 1, 1, 0), /* Separate output gain controls */ SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", @@ -626,14 +632,29 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", TWL4030_REG_AVDAC_CTL, 3, 0), + /* Analog PGAs */ + SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXL1_APGA", TWL4030_REG_ARXL1_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXR2_APGA", TWL4030_REG_ARXR2_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route intercon[] = { + {"ARXL1_APGA", NULL, "DACL1"}, + {"ARXR1_APGA", NULL, "DACR1"}, + {"ARXL2_APGA", NULL, "DACL2"}, + {"ARXR2_APGA", NULL, "DACR2"}, + /* outputs */ - {"OUTL", NULL, "DACL2"}, - {"OUTR", NULL, "DACR2"}, + {"OUTL", NULL, "ARXL2_APGA"}, + {"OUTR", NULL, "ARXR2_APGA"}, /* inputs */ {"ADCL", NULL, "INL"}, -- cgit v1.2.3 From e8ff9c417ad6e8f7ef253e36f9d6e22dc2aa2512 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:46 +0200 Subject: ASoC: TWL4030: Add DAPM event handler for output MUX selection DAPM event handler is set to filter out invalid MUX settings for certain outputs. Earpiece: - 0 = Off - 1 = DACL1 - 2 = DACL2 - 3 = *** Invalid *** - 4 = DACR1 PreDriveL/R: - 0 = Off/Off - 1 = DACL1/DACR1 - 2 = DACL2/DACR2 - 3 = *** Invalid/Invalid *** - 4 = DACR2/DACL2 Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4293ec7b502..9d1078325c3 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -190,6 +190,30 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } +static int outmixer_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int ret = 0; + int val; + + switch (e->reg) { + case TWL4030_REG_PREDL_CTL: + case TWL4030_REG_PREDR_CTL: + case TWL4030_REG_EAR_CTL: + val = w->value >> e->shift_l; + if (val == 3) { + printk(KERN_WARNING + "Invalid MUX setting for register 0x%02x (%d)\n", + e->reg, val); + ret = -1; + } + break; + } + + return ret; +} + /* * Some of the gain controls in TWL (mostly those which are associated with * the outputs) are implemented in an interesting way: -- cgit v1.2.3 From 5e98a46449cd028b9b97a8ef2c2448c8f473d6c5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:47 +0200 Subject: ASoC: TWL4030: DAPM mapping of the Earpiece output Adds DAPM muxing, routing for the Earpiece output. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 9d1078325c3..1da46175519 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -190,6 +190,19 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } +/* Earpiece */ +static const char *twl4030_earpiece_texts[] = + {"Off", "DACL1", "DACL2", "Invalid", + "DACR1"}; + +static const struct soc_enum twl4030_earpiece_enum = + SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, + ARRAY_SIZE(twl4030_earpiece_texts), + twl4030_earpiece_texts); + +static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = +SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -645,6 +658,7 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), + SND_SOC_DAPM_OUTPUT("EARPIECE"), /* DACs */ SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", @@ -666,6 +680,12 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, 0, 0, NULL, 0), + /* Output MUX controls */ + /* Earpiece */ + SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_earpiece_control, outmixer_event, + SND_SOC_DAPM_PRE_REG), + SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), }; @@ -676,9 +696,16 @@ static const struct snd_soc_dapm_route intercon[] = { {"ARXL2_APGA", NULL, "DACL2"}, {"ARXR2_APGA", NULL, "DACR2"}, + /* Internal playback routings */ + /* Earpiece */ + {"Earpiece Mux", "DACL1", "ARXL1_APGA"}, + {"Earpiece Mux", "DACL2", "ARXL2_APGA"}, + {"Earpiece Mux", "DACR1", "ARXR1_APGA"}, + /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, {"OUTR", NULL, "ARXR2_APGA"}, + {"EARPIECE", NULL, "Earpiece Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, -- cgit v1.2.3 From 2a6f5c5892dcd17c81204fe5e26b92a37d2daafa Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:48 +0200 Subject: ASoC: TWL4030: DAPM mapping of the PreDriv outputs Adds DAPM muxing, routing for the PreDrive outputs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1da46175519..c508344241e 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -203,6 +203,32 @@ static const struct soc_enum twl4030_earpiece_enum = static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); +/* PreDrive Left */ +static const char *twl4030_predrivel_texts[] = + {"Off", "DACL1", "DACL2", "Invalid", + "DACR2"}; + +static const struct soc_enum twl4030_predrivel_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, + ARRAY_SIZE(twl4030_predrivel_texts), + twl4030_predrivel_texts); + +static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = +SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); + +/* PreDrive Right */ +static const char *twl4030_predriver_texts[] = + {"Off", "DACR1", "DACR2", "Invalid", + "DACL2"}; + +static const struct soc_enum twl4030_predriver_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, + ARRAY_SIZE(twl4030_predriver_texts), + twl4030_predriver_texts); + +static const struct snd_kcontrol_new twl4030_dapm_predriver_control = +SOC_DAPM_ENUM("Route", twl4030_predriver_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -659,6 +685,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), SND_SOC_DAPM_OUTPUT("EARPIECE"), + SND_SOC_DAPM_OUTPUT("PREDRIVEL"), + SND_SOC_DAPM_OUTPUT("PREDRIVER"), /* DACs */ SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", @@ -685,6 +713,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_earpiece_control, outmixer_event, SND_SOC_DAPM_PRE_REG), + /* PreDrivL/R */ + SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predrivel_control, outmixer_event, + SND_SOC_DAPM_PRE_REG), + SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predriver_control, outmixer_event, + SND_SOC_DAPM_PRE_REG), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -701,11 +736,21 @@ static const struct snd_soc_dapm_route intercon[] = { {"Earpiece Mux", "DACL1", "ARXL1_APGA"}, {"Earpiece Mux", "DACL2", "ARXL2_APGA"}, {"Earpiece Mux", "DACR1", "ARXR1_APGA"}, + /* PreDrivL */ + {"PredriveL Mux", "DACL1", "ARXL1_APGA"}, + {"PredriveL Mux", "DACL2", "ARXL2_APGA"}, + {"PredriveL Mux", "DACR2", "ARXR2_APGA"}, + /* PreDrivR */ + {"PredriveR Mux", "DACR1", "ARXR1_APGA"}, + {"PredriveR Mux", "DACR2", "ARXR2_APGA"}, + {"PredriveR Mux", "DACL2", "ARXL2_APGA"}, /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, {"OUTR", NULL, "ARXR2_APGA"}, {"EARPIECE", NULL, "Earpiece Mux"}, + {"PREDRIVEL", NULL, "PredriveL Mux"}, + {"PREDRIVER", NULL, "PredriveR Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, -- cgit v1.2.3 From dfad21a26f5b3cc379fbec9c5d12b5106dd1f9c5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:49 +0200 Subject: ASoC: TWL4030: DAPM mapping of the Headset outputs Adds DAPM muxing, routing for the Headset outputs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c508344241e..86ff5a9ffa7 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -229,6 +229,30 @@ static const struct soc_enum twl4030_predriver_enum = static const struct snd_kcontrol_new twl4030_dapm_predriver_control = SOC_DAPM_ENUM("Route", twl4030_predriver_enum); +/* Headset Left */ +static const char *twl4030_hsol_texts[] = + {"Off", "DACL1", "DACL2"}; + +static const struct soc_enum twl4030_hsol_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 1, + ARRAY_SIZE(twl4030_hsol_texts), + twl4030_hsol_texts); + +static const struct snd_kcontrol_new twl4030_dapm_hsol_control = +SOC_DAPM_ENUM("Route", twl4030_hsol_enum); + +/* Headset Right */ +static const char *twl4030_hsor_texts[] = + {"Off", "DACR1", "DACR2"}; + +static const struct soc_enum twl4030_hsor_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 4, + ARRAY_SIZE(twl4030_hsor_texts), + twl4030_hsor_texts); + +static const struct snd_kcontrol_new twl4030_dapm_hsor_control = +SOC_DAPM_ENUM("Route", twl4030_hsor_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -687,6 +711,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("EARPIECE"), SND_SOC_DAPM_OUTPUT("PREDRIVEL"), SND_SOC_DAPM_OUTPUT("PREDRIVER"), + SND_SOC_DAPM_OUTPUT("HSOL"), + SND_SOC_DAPM_OUTPUT("HSOR"), /* DACs */ SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", @@ -720,6 +746,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_predriver_control, outmixer_event, SND_SOC_DAPM_PRE_REG), + /* HeadsetL/R */ + SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_hsol_control), + SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_hsor_control), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -744,6 +775,12 @@ static const struct snd_soc_dapm_route intercon[] = { {"PredriveR Mux", "DACR1", "ARXR1_APGA"}, {"PredriveR Mux", "DACR2", "ARXR2_APGA"}, {"PredriveR Mux", "DACL2", "ARXL2_APGA"}, + /* HeadsetL */ + {"HeadsetL Mux", "DACL1", "ARXL1_APGA"}, + {"HeadsetL Mux", "DACL2", "ARXL2_APGA"}, + /* HeadsetR */ + {"HeadsetR Mux", "DACR1", "ARXR1_APGA"}, + {"HeadsetR Mux", "DACR2", "ARXR2_APGA"}, /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, @@ -751,6 +788,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"EARPIECE", NULL, "Earpiece Mux"}, {"PREDRIVEL", NULL, "PredriveL Mux"}, {"PREDRIVER", NULL, "PredriveR Mux"}, + {"HSOL", NULL, "HeadsetL Mux"}, + {"HSOR", NULL, "HeadsetR Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, -- cgit v1.2.3 From 5152d8c28b95e421b91483ca0df76726e6e6c41e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:50 +0200 Subject: ASoC: TWL4030: DAPM mapping of the Carkit outputs Adds DAPM muxing, routing for the Carkit outputs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 86ff5a9ffa7..08c33e9b96c 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -253,6 +253,30 @@ static const struct soc_enum twl4030_hsor_enum = static const struct snd_kcontrol_new twl4030_dapm_hsor_control = SOC_DAPM_ENUM("Route", twl4030_hsor_enum); +/* Carkit Left */ +static const char *twl4030_carkitl_texts[] = + {"Off", "DACL1", "DACL2"}; + +static const struct soc_enum twl4030_carkitl_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PRECKL_CTL, 1, + ARRAY_SIZE(twl4030_carkitl_texts), + twl4030_carkitl_texts); + +static const struct snd_kcontrol_new twl4030_dapm_carkitl_control = +SOC_DAPM_ENUM("Route", twl4030_carkitl_enum); + +/* Carkit Right */ +static const char *twl4030_carkitr_texts[] = + {"Off", "DACR1", "DACR2"}; + +static const struct soc_enum twl4030_carkitr_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PRECKR_CTL, 1, + ARRAY_SIZE(twl4030_carkitr_texts), + twl4030_carkitr_texts); + +static const struct snd_kcontrol_new twl4030_dapm_carkitr_control = +SOC_DAPM_ENUM("Route", twl4030_carkitr_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -751,6 +775,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { &twl4030_dapm_hsol_control), SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_hsor_control), + /* CarkitL/R */ + SND_SOC_DAPM_MUX("CarkitL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_carkitl_control), + SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_carkitr_control), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -781,6 +810,12 @@ static const struct snd_soc_dapm_route intercon[] = { /* HeadsetR */ {"HeadsetR Mux", "DACR1", "ARXR1_APGA"}, {"HeadsetR Mux", "DACR2", "ARXR2_APGA"}, + /* CarkitL */ + {"CarkitL Mux", "DACL1", "ARXL1_APGA"}, + {"CarkitL Mux", "DACL2", "ARXL2_APGA"}, + /* CarkitR */ + {"CarkitR Mux", "DACR1", "ARXR1_APGA"}, + {"CarkitR Mux", "DACR2", "ARXR2_APGA"}, /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, @@ -790,6 +825,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"PREDRIVER", NULL, "PredriveR Mux"}, {"HSOL", NULL, "HeadsetL Mux"}, {"HSOR", NULL, "HeadsetR Mux"}, + {"CARKITL", NULL, "CarkitL Mux"}, + {"CARKITR", NULL, "CarkitR Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, -- cgit v1.2.3 From df339804bbfc118eaca066b95488a2dbacc2e258 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:51 +0200 Subject: ASoC: TWL4030: DAPM mapping of the Handsfree outputs Adds DAPM muxing, routing for the Handsfree outputs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 08c33e9b96c..d0612a4ca45 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -277,6 +277,30 @@ static const struct soc_enum twl4030_carkitr_enum = static const struct snd_kcontrol_new twl4030_dapm_carkitr_control = SOC_DAPM_ENUM("Route", twl4030_carkitr_enum); +/* Handsfree Left */ +static const char *twl4030_handsfreel_texts[] = + {"Voice", "DACL1", "DACL2", "DACR2"}; + +static const struct soc_enum twl4030_handsfreel_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, + ARRAY_SIZE(twl4030_handsfreel_texts), + twl4030_handsfreel_texts); + +static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = +SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); + +/* Handsfree Right */ +static const char *twl4030_handsfreer_texts[] = + {"Voice", "DACR1", "DACR2", "DACL2"}; + +static const struct soc_enum twl4030_handsfreer_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, + ARRAY_SIZE(twl4030_handsfreer_texts), + twl4030_handsfreer_texts); + +static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = +SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -737,6 +761,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("PREDRIVER"), SND_SOC_DAPM_OUTPUT("HSOL"), SND_SOC_DAPM_OUTPUT("HSOR"), + SND_SOC_DAPM_OUTPUT("HFL"), + SND_SOC_DAPM_OUTPUT("HFR"), /* DACs */ SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", @@ -780,6 +806,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { &twl4030_dapm_carkitl_control), SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_carkitr_control), + /* HandsfreeL/R */ + SND_SOC_DAPM_MUX("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, + &twl4030_dapm_handsfreel_control), + SND_SOC_DAPM_MUX("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, + &twl4030_dapm_handsfreer_control), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -816,6 +847,14 @@ static const struct snd_soc_dapm_route intercon[] = { /* CarkitR */ {"CarkitR Mux", "DACR1", "ARXR1_APGA"}, {"CarkitR Mux", "DACR2", "ARXR2_APGA"}, + /* HandsfreeL */ + {"HandsfreeL Mux", "DACL1", "ARXL1_APGA"}, + {"HandsfreeL Mux", "DACL2", "ARXL2_APGA"}, + {"HandsfreeL Mux", "DACR2", "ARXR2_APGA"}, + /* HandsfreeR */ + {"HandsfreeR Mux", "DACR1", "ARXR1_APGA"}, + {"HandsfreeR Mux", "DACR2", "ARXR2_APGA"}, + {"HandsfreeR Mux", "DACL2", "ARXL2_APGA"}, /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, @@ -827,6 +866,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HSOR", NULL, "HeadsetR Mux"}, {"CARKITL", NULL, "CarkitL Mux"}, {"CARKITR", NULL, "CarkitR Mux"}, + {"HFL", NULL, "HandsfreeL Mux"}, + {"HFR", NULL, "HandsfreeR Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, -- cgit v1.2.3 From ca4513fe06c483bf0111c990059d42f97288605d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:52 +0200 Subject: ASoC: TWL4030: Do not alter the Headset output volume on power-up/down There is a separate gain control for the Headset output already. Do not reset the gain to 0 dB at power up. In power-down, there is no need to set the Headset output gain to power-down mode, since if the CODECPDZ is in powered off this setting has no effect. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index d0612a4ca45..358aa2b1aae 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -887,7 +887,7 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec) static void twl4030_power_up(struct snd_soc_codec *codec) { - u8 anamicl, regmisc1, byte, popn, hsgain; + u8 anamicl, regmisc1, byte, popn; int i = 0; /* set CODECPDZ to turn on codec */ @@ -925,10 +925,6 @@ static void twl4030_power_up(struct snd_soc_codec *codec) popn |= TWL4030_VMID_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - /* enable output stage and gain setting */ - hsgain = TWL4030_HSR_GAIN_0DB | TWL4030_HSL_GAIN_0DB; - twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain); - /* enable anti-pop ramp */ popn |= TWL4030_RAMP_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); @@ -936,17 +932,13 @@ static void twl4030_power_up(struct snd_soc_codec *codec) static void twl4030_power_down(struct snd_soc_codec *codec) { - u8 popn, hsgain; + u8 popn; /* disable anti-pop ramp */ popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); popn &= ~TWL4030_RAMP_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - /* disable output stage and gain setting */ - hsgain = TWL4030_HSR_GAIN_PWR_DOWN | TWL4030_HSL_GAIN_PWR_DOWN; - twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain); - /* disable bias out */ popn &= ~TWL4030_VMID_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); -- cgit v1.2.3 From c5af3a2e192d333997d1e191f3eba7fd2f869681 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 28 Nov 2008 13:29:45 +0000 Subject: ASoC: Add card registration API ASoC v2 allows cards, codecs and platforms to instantiate separately, with the overall ASoC device only being instantiated once all the required components have registered. As part of backporting Liam's work introduce an initial version of the card registration functions. At present these do nothing active and are internal only, they will be exposed to machine drivers after further backporting. Adding this now allows the datastructures used for dynamic card instantiation to be built up gradually. Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 79d855d2bdd..4a578b5d855 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -333,6 +333,11 @@ struct snd_soc_dai_link { /* SoC card */ struct snd_soc_card { char *name; + struct device *dev; + + struct list_head list; + + int instantiated; int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2f2a8d93bbf..44fbd71ce80 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -43,6 +43,12 @@ static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); static struct dentry *debugfs_root; #endif +static DEFINE_MUTEX(client_mutex); +static LIST_HEAD(card_list); + +static int snd_soc_register_card(struct snd_soc_card *card); +static int snd_soc_unregister_card(struct snd_soc_card *card); + /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -784,6 +790,14 @@ static int soc_probe(struct platform_device *pdev) /* Bodge while we push things out of socdev */ card->socdev = socdev; + /* Bodge while we unpick instantiation */ + card->dev = &pdev->dev; + ret = snd_soc_register_card(card); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register card\n"); + return ret; + } + if (card->probe) { ret = card->probe(pdev); if (ret < 0) @@ -863,6 +877,8 @@ static int soc_remove(struct platform_device *pdev) if (card->remove) card->remove(pdev); + snd_soc_unregister_card(card); + return 0; } @@ -1957,6 +1973,52 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); +/** + * snd_soc_register_card - Register a card with the ASoC core + * + * @param card Card to register + * + * Note that currently this is an internal only function: it will be + * exposed to machine drivers after further backporting of ASoC v2 + * registration APIs. + */ +static int snd_soc_register_card(struct snd_soc_card *card) +{ + if (!card->name || !card->dev) + return -EINVAL; + + INIT_LIST_HEAD(&card->list); + card->instantiated = 0; + + mutex_lock(&client_mutex); + list_add(&card->list, &card_list); + mutex_unlock(&client_mutex); + + dev_dbg(card->dev, "Registered card '%s'\n", card->name); + + return 0; +} + +/** + * snd_soc_unregister_card - Unregister a card with the ASoC core + * + * @param card Card to unregister + * + * Note that currently this is an internal only function: it will be + * exposed to machine drivers after further backporting of ASoC v2 + * registration APIs. + */ +static int snd_soc_unregister_card(struct snd_soc_card *card) +{ + mutex_lock(&client_mutex); + list_del(&card->list); + mutex_unlock(&client_mutex); + + dev_dbg(card->dev, "Unregistered card '%s'\n", card->name); + + return 0; +} + static int __devinit snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS -- cgit v1.2.3 From 9115171a6b79b6b4d5c6697f123556b6efc37f1f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Nov 2008 23:31:24 +0000 Subject: ASoC: Add DAI registration API Add API calls to register and unregister DAIs with the core. Currently these APIs are ineffective. Since multiple DAIs for a given device are a common case bulk variants are provided. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 8 +++++ sound/soc/soc-core.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index e2d5f76838c..24247f76360 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -100,6 +100,12 @@ struct snd_soc_dai_ops; struct snd_soc_dai; struct snd_ac97_bus_ops; +/* Digital Audio Interface registration */ +int snd_soc_register_dai(struct snd_soc_dai *dai); +void snd_soc_unregister_dai(struct snd_soc_dai *dai); +int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count); +void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count); + /* Digital Audio Interface clocking API.*/ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir); @@ -186,6 +192,8 @@ struct snd_soc_dai { unsigned int id; int ac97_control; + struct device *dev; + /* DAI callbacks */ int (*probe)(struct platform_device *pdev, struct snd_soc_dai *dai); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 44fbd71ce80..03460b068f1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -45,6 +45,7 @@ static struct dentry *debugfs_root; static DEFINE_MUTEX(client_mutex); static LIST_HEAD(card_list); +static LIST_HEAD(dai_list); static int snd_soc_register_card(struct snd_soc_card *card); static int snd_soc_unregister_card(struct snd_soc_card *card); @@ -2019,6 +2020,88 @@ static int snd_soc_unregister_card(struct snd_soc_card *card) return 0; } +/** + * snd_soc_register_dai - Register a DAI with the ASoC core + * + * @param dai DAI to register + */ +int snd_soc_register_dai(struct snd_soc_dai *dai) +{ + if (!dai->name) + return -EINVAL; + + /* The device should become mandatory over time */ + if (!dai->dev) + printk(KERN_WARNING "No device for DAI %s\n", dai->name); + + INIT_LIST_HEAD(&dai->list); + + mutex_lock(&client_mutex); + list_add(&dai->list, &dai_list); + mutex_unlock(&client_mutex); + + pr_debug("Registered DAI '%s'\n", dai->name); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_register_dai); + +/** + * snd_soc_unregister_dai - Unregister a DAI from the ASoC core + * + * @param dai DAI to unregister + */ +void snd_soc_unregister_dai(struct snd_soc_dai *dai) +{ + mutex_lock(&client_mutex); + list_del(&dai->list); + mutex_unlock(&client_mutex); + + pr_debug("Unregistered DAI '%s'\n", dai->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); + +/** + * snd_soc_register_dais - Register multiple DAIs with the ASoC core + * + * @param dai Array of DAIs to register + * @param count Number of DAIs + */ +int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = snd_soc_register_dai(&dai[i]); + if (ret != 0) + goto err; + } + + return 0; + +err: + for (i--; i >= 0; i--) + snd_soc_unregister_dai(&dai[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_register_dais); + +/** + * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core + * + * @param dai Array of DAIs to unregister + * @param count Number of DAIs + */ +void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count) +{ + int i; + + for (i = 0; i < count; i++) + snd_soc_unregister_dai(&dai[i]); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); + static int __devinit snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS -- cgit v1.2.3 From 3f4b783cfdebb559814690572041a17bc9744cf3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 19:26:35 +0000 Subject: ASoC: Register platform DAIs Register all platform DAIs with the core. In line with current behaviour this is done at module probe time rather than when the devices are probed (since currently that only happens as the entire ASoC card is registered except for those drivers that currently implement some kind of hotplug). Since the core currently ignores DAI registration this has no practical effect. Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 11 +++++++++++ sound/soc/au1x/psc-ac97.c | 3 ++- sound/soc/au1x/psc-i2s.c | 3 ++- sound/soc/blackfin/bf5xx-ac97.c | 12 ++++++++++++ sound/soc/blackfin/bf5xx-i2s.c | 12 ++++++++++++ sound/soc/davinci/davinci-i2s.c | 12 ++++++++++++ sound/soc/fsl/fsl_ssi.c | 10 ++++++++++ sound/soc/omap/omap-mcbsp.c | 13 +++++++++++++ sound/soc/pxa/pxa-ssp.c | 12 ++++++++++++ sound/soc/pxa/pxa2xx-ac97.c | 12 ++++++++++++ sound/soc/pxa/pxa2xx-i2s.c | 13 ++++++++++++- sound/soc/s3c24xx/s3c2412-i2s.c | 13 +++++++++++++ sound/soc/s3c24xx/s3c2443-ac97.c | 13 +++++++++++++ sound/soc/s3c24xx/s3c24xx-i2s.c | 12 ++++++++++++ sound/soc/sh/hac.c | 12 ++++++++++++ sound/soc/sh/ssi.c | 12 ++++++++++++ 16 files changed, 172 insertions(+), 3 deletions(-) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index d9b874c5bf3..c9f02edd730 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -772,6 +772,17 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { }; EXPORT_SYMBOL_GPL(atmel_ssc_dai); +static int __devinit atmel_ssc_modinit(void) +{ + return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); +} +module_init(snd_soc_init); + +static void __exit snd_soc_exit(void) +{ + snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); +} + /* Module information */ MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); MODULE_DESCRIPTION("ATMEL SSC ASoC Interface"); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index a1e824d29cf..f0e30aec7f2 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -371,11 +371,12 @@ EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); static int __init au1xpsc_ac97_init(void) { au1xpsc_ac97_workdata = NULL; - return 0; + return snd_soc_register_dai(&au1xpsc_ac97_dai); } static void __exit au1xpsc_ac97_exit(void) { + snd_soc_unregister_dai(&au1xpsc_ac97_dai); } module_init(au1xpsc_ac97_init); diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 16f97462ea1..f916de4400e 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -396,11 +396,12 @@ EXPORT_SYMBOL(au1xpsc_i2s_dai); static int __init au1xpsc_i2s_init(void) { au1xpsc_i2s_workdata = NULL; - return 0; + return snd_soc_register_dai(&au1xpsc_i2s_dai); } static void __exit au1xpsc_i2s_exit(void) { + snd_soc_unregister_dai(&au1xpsc_i2s_dai); } module_init(au1xpsc_i2s_init); diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index c602ce109d5..ad3efeeb6d4 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -431,6 +431,18 @@ struct snd_soc_dai bfin_ac97_dai = { }; EXPORT_SYMBOL_GPL(bfin_ac97_dai); +static int __devinit bfin_ac97_init(void) +{ + return snd_soc_register_dai(&bfin_ac97_dai); +} +module_init(bfin_ac97_init); + +static void __exit bfin_ac97_exit(void) +{ + snd_soc_unregister_dai(&bfin_ac97_dai); +} +module_exit(bfin_ac97_exit); + MODULE_AUTHOR("Roy Huang"); MODULE_DESCRIPTION("AC97 driver for ADI Blackfin"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 9f8ce87cc6c..0d58d2b6db6 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -313,6 +313,18 @@ struct snd_soc_dai bf5xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); +static int __devinit bfin_i2s_init(void) +{ + return snd_soc_register_dai(&bfin_i2s_dai); +} +module_init(bfin_i2s_init); + +static void __exit bfin_i2s_exit(void) +{ + snd_soc_unregister_dai(&bfin_i2s_dai); +} +module_exit(bfin_i2s_exit); + /* Module information */ MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("I2S driver for ADI Blackfin"); diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 8b99efbc64c..d89fc2f009a 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -481,6 +481,18 @@ struct snd_soc_dai davinci_i2s_dai = { }; EXPORT_SYMBOL_GPL(davinci_i2s_dai); +static int __devinit davinci_i2s_init(void) +{ + return snd_soc_register_dai(&davinci_i2s_dai); +} +module_init(davinci_i2s_init); + +static void __exit davinci_i2s_exit(void) +{ + snd_soc_unregister_dai(&davinci_i2s_dai); +} +module_exit(davinci_i2s_exit); + MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 52c290bb47b..c6d6eb71dc1 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -673,6 +673,14 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) fsl_ssi_dai->private_data = ssi_private; fsl_ssi_dai->name = ssi_private->name; fsl_ssi_dai->id = ssi_info->id; + fsl_ssi_dai->dev = ssi_info->dev; + + ret = snd_soc_register_dai(fsl_ssi_dai); + if (ret != 0) { + dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret); + kfree(fsl_ssi_dai); + return NULL; + } return fsl_ssi_dai; } @@ -690,6 +698,8 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) device_remove_file(ssi_private->dev, &ssi_private->dev_attr); + snd_soc_unregister_dai(&ssi_private->cpu_dai); + kfree(ssi_private); } EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index e8f1314762d..41cab203416 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -499,6 +499,19 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); +static int __devinit omap_mcbsp_init(void) +{ + return snd_soc_register_dais(omap_mcbsp_dai, + ARRAY_SIZE(omap_mcbsp_dai)); +} +module_init(omap_mcbsp_init); + +static void __exit omap_mcbsp_exit(void) +{ + snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); +} +module_exit(omap_mcbsp_exit); + MODULE_AUTHOR("Jarkko Nikula "); MODULE_DESCRIPTION("OMAP I2S SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 73fa10defcc..3587f2fae5f 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -913,6 +913,18 @@ struct snd_soc_dai pxa_ssp_dai[] = { }; EXPORT_SYMBOL_GPL(pxa_ssp_dai); +static int __devinit pxa_ssp_init(void) +{ + return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); +} +module_init(pxa_ssp_init); + +static void __exit pxa_ssp_exit(void) +{ + snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); +} +module_exit(pxa_ssp_exit); + /* Module information */ MODULE_AUTHOR("Mark Brown "); MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 8eed80d5675..f6249d5b492 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -228,6 +228,18 @@ struct snd_soc_dai pxa_ac97_dai[] = { EXPORT_SYMBOL_GPL(pxa_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); +static int __devinit pxa_ac97_init(void) +{ + return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); +} +module_init(pxa_ac97_init); + +static void __exit pxa_ac97_exit(void) +{ + snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); +} +module_exit(pxa_ac97_exit); + MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 314973ace6d..517991fb109 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -364,12 +364,23 @@ EXPORT_SYMBOL_GPL(pxa_i2s_dai); static int pxa2xx_i2s_probe(struct platform_device *dev) { + int ret; + clk_i2s = clk_get(&dev->dev, "I2SCLK"); - return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0; + if (IS_ERR(clk_i2s)) + return PTR_ERR(clk_i2s); + + pxa_i2s_dai.dev = &dev->dev; + ret = snd_soc_register_dai(&pxa_i2s_dai); + if (ret != 0) + clk_put(clk_i2s); + + return ret; } static int __devexit pxa2xx_i2s_remove(struct platform_device *dev) { + snd_soc_unregister_dai(&pxa_i2s_dai); clk_put(clk_i2s); clk_i2s = ERR_PTR(-ENOENT); return 0; diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 75f87c3c74d..2cf05079156 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -736,6 +736,19 @@ struct snd_soc_dai s3c2412_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); +static int __devinit s3c2412_i2s_init(void) +{ + return snd_soc_register_dai(&s3c2412_i2s_dai); +} +module_init(s3c2412_i2s_init); + +static void __exit s3c2412_i2s_exit(void) +{ + snd_soc_unregister_dai(&s3c2412_i2s_dai); +} +module_exit(s3c2412_i2s_exit); + + /* Module information */ MODULE_AUTHOR("Ben Dooks, "); MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index f0bc9b7e084..7360c6d913b 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -396,6 +396,19 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); +static int __devinit s3c2443_ac97_init(void) +{ + return snd_soc_register_dai(&s3c2443_ac97_dai); +} +module_init(s3c2443_ac97_init); + +static void __exit s3c2443_ac97_exit(void) +{ + snd_soc_unregister_dai(&s3c2443_ac97_dai); +} +module_exit(s3c2443_ac97_exit); + + MODULE_AUTHOR("Graeme Gregory"); MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 45fe8f7c88a..897b1ac92ce 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -482,6 +482,18 @@ struct snd_soc_dai s3c24xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); +static int __devinit s3c24xx_i2s_init(void) +{ + return snd_soc_register_dai(&s3c24xx_i2s_dai); +} +module_init(s3c24xx_i2s_init); + +static void __exit s3c24xx_i2s_exit(void) +{ + snd_soc_unregister_dai(&s3c24xx_i2s_dai); +} +module_exit(s3c24xx_i2s_exit); + /* Module information */ MODULE_AUTHOR("Ben Dooks, "); MODULE_DESCRIPTION("s3c24xx I2S SoC Interface"); diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index c435913c60e..9169bad1acf 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -314,6 +314,18 @@ struct snd_soc_dai sh4_hac_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_hac_dai); +static int __devinit sh4_hac_init(void) +{ + return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); +} +module_init(sh4_hac_init); + +static void __exit sh4_hac_exit(void) +{ + snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); +} +module_exit(sh4_hac_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver"); MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index fed544a3def..9093588d4d0 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -392,6 +392,18 @@ struct snd_soc_dai sh4_ssi_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_ssi_dai); +static int __devinit sh4_ssi_init(void) +{ + return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); +} +module_init(sh4_ssi_init); + +static void __exit sh4_ssi_exit(void) +{ + snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); +} +module_exit(sh4_ssi_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver"); MODULE_AUTHOR("Manuel Lauss "); -- cgit v1.2.3 From 12a48a8c0087ba39d926cf1d63938ccbdb9752c3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 19:40:30 +0000 Subject: ASoC: Add platform registration API ASoC v2 allows platform drivers to instantiate independantly of the overall ASoC card. This API allows drivers to notify the core when they are registered. Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4a578b5d855..ce3661d07c2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -149,6 +149,7 @@ struct snd_soc_ops; struct snd_soc_dai_mode; struct snd_soc_pcm_runtime; struct snd_soc_dai; +struct snd_soc_platform; struct snd_soc_codec; struct soc_enum; struct snd_soc_ac97_ops; @@ -158,6 +159,9 @@ typedef int (*hw_read_t)(void *,char* ,int); extern struct snd_ac97_bus_ops soc_ac97_ops; +int snd_soc_register_platform(struct snd_soc_platform *platform); +void snd_soc_unregister_platform(struct snd_soc_platform *platform); + /* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); @@ -296,6 +300,7 @@ struct snd_soc_codec_device { /* SoC platform interface */ struct snd_soc_platform { char *name; + struct list_head list; int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 03460b068f1..ffae370b45d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -46,6 +46,7 @@ static struct dentry *debugfs_root; static DEFINE_MUTEX(client_mutex); static LIST_HEAD(card_list); static LIST_HEAD(dai_list); +static LIST_HEAD(platform_list); static int snd_soc_register_card(struct snd_soc_card *card); static int snd_soc_unregister_card(struct snd_soc_card *card); @@ -2102,6 +2103,43 @@ void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count) } EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); +/** + * snd_soc_register_platform - Register a platform with the ASoC core + * + * @param platform platform to register + */ +int snd_soc_register_platform(struct snd_soc_platform *platform) +{ + if (!platform->name) + return -EINVAL; + + INIT_LIST_HEAD(&platform->list); + + mutex_lock(&client_mutex); + list_add(&platform->list, &platform_list); + mutex_unlock(&client_mutex); + + pr_debug("Registered platform '%s'\n", platform->name); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_register_platform); + +/** + * snd_soc_unregister_platform - Unregister a platform from the ASoC core + * + * @param platform platform to unregister + */ +void snd_soc_unregister_platform(struct snd_soc_platform *platform) +{ + mutex_lock(&client_mutex); + list_del(&platform->list); + mutex_unlock(&client_mutex); + + pr_debug("Unregistered platform '%s'\n", platform->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); + static int __devinit snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS -- cgit v1.2.3 From 958e792c7c8f06a9e666adb0ed94fff2cf90156f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 19:58:17 +0000 Subject: ASoC: Register platform drivers This is done at modprobe time, mirroring current behaviour, except for mpc5200_psc_i2s where we do registration at the same time as we register with soc-of-simple. Since the core currently ignores registration this has no practical impact. Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm.c | 12 ++++++++++++ sound/soc/au1x/dbdma2.c | 3 ++- sound/soc/blackfin/bf5xx-ac97-pcm.c | 12 ++++++++++++ sound/soc/blackfin/bf5xx-i2s-pcm.c | 12 ++++++++++++ sound/soc/davinci/davinci-pcm.c | 12 ++++++++++++ sound/soc/fsl/fsl_dma.c | 12 ++++++++++++ sound/soc/fsl/mpc5200_psc_i2s.c | 4 ++++ sound/soc/omap/omap-pcm.c | 12 ++++++++++++ sound/soc/pxa/pxa2xx-pcm.c | 12 ++++++++++++ sound/soc/s3c24xx/s3c24xx-pcm.c | 12 ++++++++++++ sound/soc/sh/dma-sh7760.c | 12 ++++++++++++ 11 files changed, 114 insertions(+), 1 deletion(-) diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 8507aa1cd81..d6bcb4e6fda 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -477,6 +477,18 @@ struct snd_soc_platform atmel_soc_platform = { }; EXPORT_SYMBOL_GPL(atmel_soc_platform); +static int __devinit atmel_pcm_modinit(void) +{ + return snd_soc_register_platform(&atmel_soc_platform); +} +module_init(atmel_pcm_modinit); + +static void __exit atmel_pcm_exit(void) +{ + snd_soc_unregister_platform(&atmel_soc_platform); +} +module_exit(atmel_pcm_modexit); + MODULE_AUTHOR("Sedji Gaouaou "); MODULE_DESCRIPTION("Atmel PCM module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 1466d932880..74c823d60f9 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -406,11 +406,12 @@ static int __init au1xpsc_audio_dbdma_init(void) { au1xpsc_audio_pcmdma[PCM_TX] = NULL; au1xpsc_audio_pcmdma[PCM_RX] = NULL; - return 0; + return snd_soc_register_platform(&au1xpsc_soc_platform); } static void __exit au1xpsc_audio_dbdma_exit(void) { + snd_soc_unregister_platform(&au1xpsc_soc_platform); } module_init(au1xpsc_audio_dbdma_init); diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index d3d51bcb456..5b27e0d9d0e 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -451,6 +451,18 @@ struct snd_soc_platform bf5xx_ac97_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform); +static int __devinit bfin_ac97_init(void) +{ + return snd_soc_register_platform(&bf5xx_ac97_soc_platform); +} +module_init(bfin_ac97_init); + +static void __exit bfin_ac97_exit(void) +{ + snd_soc_unregister_platform(&bf5xx_ac97_soc_platform); +} +module_exit(bfin_ac97_exit); + MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 61fccf92519..c58b12a4487 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -283,6 +283,18 @@ struct snd_soc_platform bf5xx_i2s_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform); +static int __devinit bfin_i2s_init(void) +{ + return snd_soc_register_platform(&bf5xx_i2s_soc_platform); +} +module_init(bfin_i2s_init); + +static void __exit bfin_i2s_exit(void) +{ + snd_soc_unregister_platform(&bf5xx_i2s_soc_platform); +} +module_exit(bfin_i2s_exit); + MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 76feaa65737..f1b6e02d24e 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -384,6 +384,18 @@ struct snd_soc_platform davinci_soc_platform = { }; EXPORT_SYMBOL_GPL(davinci_soc_platform); +static int __devinit davinci_soc_platform_init(void) +{ + return snd_soc_register_platform(&davinci_soc_platform); +} +module_init(davinci_soc_platform_init); + +static void __exit davinci_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&davinci_soc_platform); +} +module_exit(davinci_soc_platform_exit); + MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index bf92331b476..646c807163a 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -853,6 +853,18 @@ int fsl_dma_configure(struct fsl_dma_info *dma_info) } EXPORT_SYMBOL_GPL(fsl_dma_configure); +static int __devinit fsl_soc_platform_init(void) +{ + return snd_soc_register_platform(&fsl_soc_platform); +} +module_init(fsl_soc_platform_init); + +static void __exit fsl_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&fsl_soc_platform); +} +module_exit(fsl_soc_platform_exit); + MODULE_AUTHOR("Timur Tabi "); MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 9ad8f9a2d8e..9eb1ce185bd 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -828,6 +828,8 @@ static int __devinit psc_i2s_of_probe(struct of_device *op, if (rc) dev_info(psc_i2s->dev, "error creating sysfs files\n"); + snd_soc_register_platform(&psc_i2s_pcm_soc_platform); + /* Tell the ASoC OF helpers about it */ of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node, &psc_i2s->dai); @@ -841,6 +843,8 @@ static int __devexit psc_i2s_of_remove(struct of_device *op) dev_dbg(&op->dev, "psc_i2s_remove()\n"); + snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform); + bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task); bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index e9084fdd208..9940de29631 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -354,6 +354,18 @@ struct snd_soc_platform omap_soc_platform = { }; EXPORT_SYMBOL_GPL(omap_soc_platform); +static int __devinit omap_soc_platform_init(void) +{ + return snd_soc_register_platform(&omap_soc_platform); +} +module_init(omap_soc_platform_init); + +static void __exit omap_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&omap_soc_platform); +} +module_exit(omap_soc_platform_exit); + MODULE_AUTHOR("Jarkko Nikula "); MODULE_DESCRIPTION("OMAP PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 0f6b7bb2d44..4fa1578f5d4 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -118,6 +118,18 @@ struct snd_soc_platform pxa2xx_soc_platform = { }; EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); +static int __devinit pxa2xx_soc_platform_init(void) +{ + return snd_soc_register_platform(&pxa2xx_soc_platform); +} +module_init(pxa2xx_soc_platform_init); + +static void __exit pxa2xx_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&pxa2xx_soc_platform); +} +module_exit(pxa2xx_soc_platform_exit); + MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index e13e614bada..ea5a9caec13 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -465,6 +465,18 @@ struct snd_soc_platform s3c24xx_soc_platform = { }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); +static int __devinit s3c24xx_soc_platform_init(void) +{ + return snd_soc_register_platform(&s3c24xx_soc_platform); +} +module_init(s3c24xx_soc_platform_init); + +static void __exit s3c24xx_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&s3c24xx_soc_platform); +} +module_exit(s3c24xx_soc_platform_exit); + MODULE_AUTHOR("Ben Dooks, "); MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 9faa12622d0..39ffca0933a 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -348,6 +348,18 @@ struct snd_soc_platform sh7760_soc_platform = { }; EXPORT_SYMBOL_GPL(sh7760_soc_platform); +static int __devinit sh7760_soc_platform_init(void) +{ + return snd_soc_register_platform(&sh7760_soc_platform); +} +module_init(sh7760_soc_platform_init); + +static void __exit sh7760_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&sh7760_soc_platform); +} +module_exit(sh7760_soc_platform_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver"); MODULE_AUTHOR("Manuel Lauss "); -- cgit v1.2.3 From 64089b84abfe2f26a864ebd968429302dcb071de Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 8 Dec 2008 19:17:58 +0000 Subject: ASoC: Register non-AC97 codec DAIs Currently this is done at module probe time since ASoC ties in codec device probe to the instantiation of the entire ASoC device. Subsequent patches will refactor the codec drivers to handle probing separately. Note that the core does not yet use this information. AC97 is special since the codec is controlled over the AC97 link but we want to give the machine driver a chance to set up the system before trying to instantiate since it may need to do configuration before the AC97 link will operate Signed-off-by: Mark Brown --- sound/soc/codecs/ad73311.c | 12 ++++++++++++ sound/soc/codecs/ak4535.c | 12 ++++++++++++ sound/soc/codecs/cs4270.c | 12 ++++++++++++ sound/soc/codecs/pcm3008.c | 12 ++++++++++++ sound/soc/codecs/ssm2602.c | 12 ++++++++++++ sound/soc/codecs/tlv320aic23.c | 12 ++++++++++++ sound/soc/codecs/tlv320aic26.c | 15 ++++++++++++--- sound/soc/codecs/tlv320aic3x.c | 12 ++++++++++++ sound/soc/codecs/twl4030.c | 14 +++++++++++++- sound/soc/codecs/uda134x.c | 12 ++++++++++++ sound/soc/codecs/uda1380.c | 12 ++++++++++++ sound/soc/codecs/wm8510.c | 12 ++++++++++++ sound/soc/codecs/wm8580.c | 12 ++++++++++++ sound/soc/codecs/wm8728.c | 12 ++++++++++++ sound/soc/codecs/wm8731.c | 12 ++++++++++++ sound/soc/codecs/wm8750.c | 12 ++++++++++++ sound/soc/codecs/wm8753.c | 12 ++++++++++++ sound/soc/codecs/wm8900.c | 12 ++++++++++++ sound/soc/codecs/wm8903.c | 12 ++++++++++++ sound/soc/codecs/wm8971.c | 12 ++++++++++++ sound/soc/codecs/wm8990.c | 12 ++++++++++++ 21 files changed, 253 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 500f9f3363d..e32f55034e6 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -98,6 +98,18 @@ struct snd_soc_codec_device soc_codec_dev_ad73311 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311); +static int __devinit ad73311_init(void) +{ + return snd_soc_register_dai(&ad73311_dai); +} +module_init(ad73311_init); + +static void __exit ad73311_exit(void) +{ + snd_soc_unregister_dai(&ad73311_dai); +} +module_exit(ad73311_exit); + MODULE_DESCRIPTION("ASoC ad73311 driver"); MODULE_AUTHOR("Cliff Cai "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 23062c952e8..94148fba911 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -688,6 +688,18 @@ struct snd_soc_codec_device soc_codec_dev_ak4535 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); +static int __devinit ak4535_modinit(void) +{ + return snd_soc_register_dai(&ak4535_dai); +} +module_init(ak4535_modinit); + +static void __exit ak4535_exit(void) +{ + snd_soc_unregister_dai(&ak4535_dai); +} +module_exit(ak4535_exit); + MODULE_DESCRIPTION("Soc AK4535 driver"); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 4667a07b566..73aaf249d78 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -774,6 +774,18 @@ struct snd_soc_codec_device soc_codec_device_cs4270 = { }; EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); +static int __devinit cs4270_init(void) +{ + return snd_soc_register_dai(&cs4270_dai); +} +module_init(cs4270_init); + +static void __exit cs4270_exit(void) +{ + snd_soc_unregister_dai(&cs4270_dai); +} +module_exit(cs4270_exit); + MODULE_AUTHOR("Timur Tabi "); MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index a5862555b44..f333e88ee25 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -195,6 +195,18 @@ struct snd_soc_codec_device soc_codec_dev_pcm3008 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008); +static int __devinit pcm3008_init(void) +{ + return snd_soc_register_dai(&pcm3008_dai); +} +module_init(pcm3008_init); + +static void __exit pcm3008_exit(void) +{ + snd_soc_unregister_dai(&pcm3008_dai); +} +module_exit(pcm3008_exit); + MODULE_DESCRIPTION("Soc PCM3008 driver"); MODULE_AUTHOR("Hugo Villeneuve"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 973844973fe..77fdcb4b9a1 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -793,6 +793,18 @@ struct snd_soc_codec_device soc_codec_dev_ssm2602 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); +static int __devinit ssm2602_modinit(void) +{ + return snd_soc_register_dai(&ssm2602_dai); +} +module_init(ssm2602_modinit); + +static void __exit ssm2602_exit(void) +{ + snd_soc_unregister_dai(&ssm2602_dai); +} +module_exit(ssm2602_exit); + MODULE_DESCRIPTION("ASoC ssm2602 driver"); MODULE_AUTHOR("Cliff Cai"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index d209bec02a6..eac449b92bd 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -847,6 +847,18 @@ struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); +static int __devinit tlv320aic23_modinit(void) +{ + return snd_soc_register_dai(&tlv320aic23_dai); +} +module_init(tlv320aic23_modinit); + +static void __exit tlv320aic23_exit(void) +{ + snd_soc_unregister_dai(&tlv320aic23_dai); +} +module_exit(tlv320aic23_exit); + MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); MODULE_AUTHOR("Arun KS "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index e33fb7e00d1..29f2f1a017f 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -426,7 +426,7 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); static int aic26_spi_probe(struct spi_device *spi) { struct aic26 *aic26; - int rc, i, reg; + int ret, i, reg; dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n"); @@ -456,6 +456,14 @@ static int aic26_spi_probe(struct spi_device *spi) aic26->codec.reg_cache_size = AIC26_NUM_REGS; aic26->codec.reg_cache = aic26->reg_cache; + aic26_dai.dev = &spi->dev; + ret = snd_soc_register_dai(&aic26_dai); + if (ret != 0) { + dev_err(&spi->dev, "Failed to register DAI: %d\n", ret); + kfree(aic26); + return ret; + } + /* Reset the codec to power on defaults */ aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00); @@ -474,8 +482,8 @@ static int aic26_spi_probe(struct spi_device *spi) /* Register the sysfs files for debugging */ /* Create SysFS files */ - rc = device_create_file(&spi->dev, &dev_attr_keyclick); - if (rc) + ret = device_create_file(&spi->dev, &dev_attr_keyclick); + if (ret) dev_info(&spi->dev, "error creating sysfs files\n"); #if defined(CONFIG_SND_SOC_OF_SIMPLE) @@ -492,6 +500,7 @@ static int aic26_spi_remove(struct spi_device *spi) { struct aic26 *aic26 = dev_get_drvdata(&spi->dev); + snd_soc_unregister_dai(&aic26_dai); kfree(aic26); return 0; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6a058298a3c..ccd57596186 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1411,6 +1411,18 @@ struct snd_soc_codec_device soc_codec_dev_aic3x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); +static int __devinit aic3x_modinit(void) +{ + return snd_soc_register_dai(&aic3x_dai); +} +module_init(aic3x_modinit); + +static void __exit aic3x_exit(void) +{ + snd_soc_unregister_dai(&aic3x_dai); +} +module_exit(aic3x_exit); + MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); MODULE_AUTHOR("Vladimir Barinov"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 358aa2b1aae..373daa486ce 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -358,7 +358,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, .put = snd_soc_put_volsw_r2_twl4030, \ .private_value = (unsigned long)&(struct soc_mixer_control) \ {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ - .max = xmax, .invert = xinvert} } + .rshift = xshift, .max = xmax, .invert = xinvert} } #define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \ SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \ xinvert, tlv_array) @@ -1275,6 +1275,18 @@ struct snd_soc_codec_device soc_codec_dev_twl4030 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); +static int __devinit twl4030_init(void) +{ + return snd_soc_register_dai(&twl4030_dai); +} +module_init(twl4030_init); + +static void __exit twl4030_exit(void) +{ + snd_soc_unregister_dai(&twl4030_dai); +} +module_exit(twl4030_exit); + MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); MODULE_AUTHOR("Steve Sakoman"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 58de749185e..8e035b5d733 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -651,6 +651,18 @@ struct snd_soc_codec_device soc_codec_dev_uda134x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); +static int __devinit uda134x_init(void) +{ + return snd_soc_register_dai(&uda134x_dai); +} +module_init(uda134x_init); + +static void __exit uda134x_exit(void) +{ + snd_soc_unregister_dai(&uda134x_dai); +} +module_exit(uda134x_exit); + MODULE_DESCRIPTION("UDA134X ALSA soc codec driver"); MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 42491650593..55a99b6a68a 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -841,6 +841,18 @@ struct snd_soc_codec_device soc_codec_dev_uda1380 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); +static int __devinit uda1380_modinit(void) +{ + return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); +} +module_init(uda1380_modinit); + +static void __exit uda1380_exit(void) +{ + snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); +} +module_exit(uda1380_exit); + MODULE_AUTHOR("Giorgio Padrin"); MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 126c70f749d..a2af04bb4e9 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -889,6 +889,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8510 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); +static int __devinit wm8510_modinit(void) +{ + return snd_soc_register_dai(&wm8510_dai); +} +module_init(wm8510_modinit); + +static void __exit wm8510_exit(void) +{ + snd_soc_unregister_dai(&wm8510_dai); +} +module_exit(wm8510_exit); + MODULE_DESCRIPTION("ASoC WM8510 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 572a31de321..391ec2978ae 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1042,6 +1042,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); +static int __devinit wm8580_modinit(void) +{ + return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); +} +module_init(wm8580_modinit); + +static void __exit wm8580_exit(void) +{ + snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); +} +module_exit(wm8580_exit); + MODULE_DESCRIPTION("ASoC WM8580 driver"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 28f12c6a6ac..d905e25b1a9 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -568,6 +568,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8728 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); +static int __devinit wm8728_modinit(void) +{ + return snd_soc_register_dai(&wm8728_dai); +} +module_init(wm8728_modinit); + +static void __exit wm8728_exit(void) +{ + snd_soc_unregister_dai(&wm8728_dai); +} +module_exit(wm8728_exit); + MODULE_DESCRIPTION("ASoC WM8728 driver"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 403dea13b5d..7b455a60d71 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -793,6 +793,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); +static int __devinit wm8731_modinit(void) +{ + return snd_soc_register_dai(&wm8731_dai); +} +module_init(wm8731_modinit); + +static void __exit wm8731_exit(void) +{ + snd_soc_unregister_dai(&wm8731_dai); +} +module_exit(wm8731_exit); + MODULE_DESCRIPTION("ASoC WM8731 driver"); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 979446f5c98..84a6307de90 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -1085,6 +1085,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8750 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); +static int __devinit wm8750_modinit(void) +{ + return snd_soc_register_dai(&wm8750_dai); +} +module_init(wm8750_modinit); + +static void __exit wm8750_exit(void) +{ + snd_soc_unregister_dai(&wm8750_dai); +} +module_exit(wm8750_exit); + MODULE_DESCRIPTION("ASoC WM8750 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 96c0453fffb..1caca30d081 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1874,6 +1874,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8753 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); +static int __devinit wm8753_modinit(void) +{ + return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); +} +module_init(wm8753_modinit); + +static void __exit wm8753_exit(void) +{ + snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); +} +module_exit(wm8753_exit); + MODULE_DESCRIPTION("ASoC WM8753 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 29cd83991c5..02bb1c999ba 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1530,6 +1530,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8900 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); +static int __devinit wm8900_modinit(void) +{ + return snd_soc_register_dai(&wm8900_dai); +} +module_init(wm8900_modinit); + +static void __exit wm8900_exit(void) +{ + snd_soc_unregister_dai(&wm8900_dai); +} +module_exit(wm8900_exit); + MODULE_DESCRIPTION("ASoC WM8900 driver"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 3c83b797307..5d8fe7e1571 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1809,6 +1809,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8903 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); +static int __devinit wm8903_modinit(void) +{ + return snd_soc_register_dai(&wm8903_dai); +} +module_init(wm8903_modinit); + +static void __exit wm8903_exit(void) +{ + snd_soc_unregister_dai(&wm8903_dai); +} +module_exit(wm8903_exit); + MODULE_DESCRIPTION("ASoC WM8903 driver"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 53e6937e9ba..2979fc4f44f 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -935,6 +935,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8971 = { EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); +static int __devinit wm8971_modinit(void) +{ + return snd_soc_register_dai(&wm8971_dai); +} +module_init(wm8971_modinit); + +static void __exit wm8971_exit(void) +{ + snd_soc_unregister_dai(&wm8971_dai); +} +module_exit(wm8971_exit); + MODULE_DESCRIPTION("ASoC WM8971 driver"); MODULE_AUTHOR("Lab126"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 5c5128b6b45..53e71aafe6c 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1643,6 +1643,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8990 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); +static int __devinit wm8990_modinit(void) +{ + return snd_soc_register_dai(&wm8990_dai); +} +module_init(wm8990_modinit); + +static void __exit wm8990_exit(void) +{ + snd_soc_unregister_dai(&wm8990_dai); +} +module_exit(wm8990_exit); + MODULE_DESCRIPTION("ASoC WM8990 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 435c5e2588893e3f7aba0bd4de67991bf00b3c9d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 4 Dec 2008 15:32:53 +0000 Subject: ASoC: Initial framework for dynamic card instantiation Use the lists of platforms, platform DAIs and cards to check to see that everything has registered. Since relationships are still specified by direct references to the structures in the drivers and the drivers all register everything at modprobe there should be no practical effect yet. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 99 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ffae370b45d..717db0e6499 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -780,30 +780,54 @@ static int soc_resume(struct platform_device *pdev) #define soc_resume NULL #endif -/* probes a new socdev */ -static int soc_probe(struct platform_device *pdev) -{ - int ret = 0, i; - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; - struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - - /* Bodge while we push things out of socdev */ - card->socdev = socdev; +static void snd_soc_instantiate_card(struct snd_soc_card *card) +{ + struct platform_device *pdev = container_of(card->dev, + struct platform_device, + dev); + struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev; + struct snd_soc_platform *platform; + struct snd_soc_dai *dai; + int i, found, ret; + + if (card->instantiated) + return; + + found = 0; + list_for_each_entry(platform, &platform_list, list) + if (card->platform == platform) { + found = 1; + break; + } + if (!found) { + dev_dbg(card->dev, "Platform %s not registered\n", + card->platform->name); + return; + } - /* Bodge while we unpick instantiation */ - card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to register card\n"); - return ret; + for (i = 0; i < card->num_links; i++) { + found = 0; + list_for_each_entry(dai, &dai_list, list) + if (card->dai_link[i].cpu_dai == dai) { + found = 1; + break; + } + if (!found) { + dev_dbg(card->dev, "DAI %s not registered\n", + card->dai_link[i].cpu_dai->name); + return; + } } + /* Note that we do not current check for codec components */ + + dev_dbg(card->dev, "All components present, instantiating\n"); + + /* Found everything, bring it up */ if (card->probe) { ret = card->probe(pdev); if (ret < 0) - return ret; + return; } for (i = 0; i < card->num_links; i++) { @@ -834,7 +858,9 @@ static int soc_probe(struct platform_device *pdev) INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); #endif - return 0; + card->instantiated = 1; + + return; platform_err: if (codec_dev->remove) @@ -849,8 +875,38 @@ cpu_dai_err: if (card->remove) card->remove(pdev); +} - return ret; +/* + * Attempt to initialise any uninitalised cards. Must be called with + * client_mutex. + */ +static void snd_soc_instantiate_cards(void) +{ + struct snd_soc_card *card; + list_for_each_entry(card, &card_list, list) + snd_soc_instantiate_card(card); +} + +/* probes a new socdev */ +static int soc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_card *card = socdev->card; + + /* Bodge while we push things out of socdev */ + card->socdev = socdev; + + /* Bodge while we unpick instantiation */ + card->dev = &pdev->dev; + ret = snd_soc_register_card(card); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register card\n"); + return ret; + } + + return 0; } /* removes a socdev */ @@ -1994,6 +2050,7 @@ static int snd_soc_register_card(struct snd_soc_card *card) mutex_lock(&client_mutex); list_add(&card->list, &card_list); + snd_soc_instantiate_cards(); mutex_unlock(&client_mutex); dev_dbg(card->dev, "Registered card '%s'\n", card->name); @@ -2039,6 +2096,7 @@ int snd_soc_register_dai(struct snd_soc_dai *dai) mutex_lock(&client_mutex); list_add(&dai->list, &dai_list); + snd_soc_instantiate_cards(); mutex_unlock(&client_mutex); pr_debug("Registered DAI '%s'\n", dai->name); @@ -2117,6 +2175,7 @@ int snd_soc_register_platform(struct snd_soc_platform *platform) mutex_lock(&client_mutex); list_add(&platform->list, &platform_list); + snd_soc_instantiate_cards(); mutex_unlock(&client_mutex); pr_debug("Registered platform '%s'\n", platform->name); -- cgit v1.2.3 From 6b05eda6383d89bffc21da654d148733e7839540 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 8 Dec 2008 19:26:48 +0000 Subject: ASoC: Wait for non-AC97 codec DAIs before instantiating This will allow codec drivers to be refactored to allow them to be registered out of line with the ASoC device registration. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 717db0e6499..76a89eb65ba 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -788,7 +788,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev; struct snd_soc_platform *platform; struct snd_soc_dai *dai; - int i, found, ret; + int i, found, ret, ac97; if (card->instantiated) return; @@ -805,6 +805,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) return; } + ac97 = 0; for (i = 0; i < card->num_links; i++) { found = 0; list_for_each_entry(dai, &dai_list, list) @@ -817,8 +818,32 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) card->dai_link[i].cpu_dai->name); return; } + + if (card->dai_link[i].cpu_dai->ac97_control) + ac97 = 1; } + /* If we have AC97 in the system then don't wait for the + * codec. This will need revisiting if we have to handle + * systems with mixed AC97 and non-AC97 parts. Only check for + * DAIs currently; we can't do this per link since some AC97 + * codecs have non-AC97 DAIs. + */ + if (!ac97) + for (i = 0; i < card->num_links; i++) { + found = 0; + list_for_each_entry(dai, &dai_list, list) + if (card->dai_link[i].codec_dai == dai) { + found = 1; + break; + } + if (!found) { + dev_dbg(card->dev, "DAI %s not registered\n", + card->dai_link[i].codec_dai->name); + return; + } + } + /* Note that we do not current check for codec components */ dev_dbg(card->dev, "All components present, instantiating\n"); -- cgit v1.2.3 From f0752331b89ce79063f765545dd7dd5f49d9a713 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Dec 2008 12:51:56 +0000 Subject: ASoC: Convert WM8900 to allow registration by machine code This makes use of the support for delayed DAI registration to allow the WM8900 I2C device to be registered by general platform/architecture code rather than as part of the ASoC device probe. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8900.c | 97 ++++++++++------------------------------------- 1 file changed, 20 insertions(+), 77 deletions(-) diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 02bb1c999ba..34e58af0c65 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1382,32 +1382,21 @@ priv_err: return ret; } -static struct snd_soc_device *wm8900_socdev; +static struct i2c_client *wm8900_client; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ static int wm8900_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct snd_soc_device *socdev = wm8900_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; - - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = wm8900_init(socdev); - if (ret < 0) - dev_err(&i2c->dev, "failed to initialise WM8900\n"); - return ret; + wm8900_client = i2c; + wm8900_dai.dev = &i2c->dev; + return snd_soc_register_dai(&wm8900_dai); } static int wm8900_i2c_remove(struct i2c_client *client) { - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); + snd_soc_unregister_dai(&wm8900_dai); + wm8900_dai.dev = NULL; + wm8900_client = NULL; return 0; } @@ -1427,57 +1416,17 @@ static struct i2c_driver wm8900_i2c_driver = { .id_table = wm8900_i2c_id, }; -static int wm8900_add_i2c_device(struct platform_device *pdev, - const struct wm8900_setup_data *setup) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - int ret; - - ret = i2c_add_driver(&wm8900_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "wm8900", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; - -err_driver: - i2c_del_driver(&wm8900_i2c_driver); - return -ENODEV; -} -#endif - static int wm8900_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8900_setup_data *setup; struct snd_soc_codec *codec; int ret = 0; - dev_info(&pdev->dev, "WM8900 Audio Codec\n"); + if (!wm8900_client) { + dev_err(&pdev->dev, "I2C client not yet instantiated\n"); + return -ENODEV; + } - setup = socdev->codec_data; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; @@ -1490,15 +1439,13 @@ static int wm8900_probe(struct platform_device *pdev) codec->set_bias_level = wm8900_set_bias_level; - wm8900_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; - ret = wm8900_add_i2c_device(pdev, setup); - } -#else -#error Non-I2C interfaces not yet supported -#endif + codec->hw_write = (hw_write_t)i2c_master_send; + codec->control_data = wm8900_client; + + ret = wm8900_init(socdev); + if (ret != 0) + kfree(codec); + return ret; } @@ -1513,10 +1460,6 @@ static int wm8900_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); - i2c_del_driver(&wm8900_i2c_driver); -#endif kfree(codec); return 0; @@ -1532,13 +1475,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); static int __devinit wm8900_modinit(void) { - return snd_soc_register_dai(&wm8900_dai); + return i2c_add_driver(&wm8900_i2c_driver); } module_init(wm8900_modinit); static void __exit wm8900_exit(void) { - snd_soc_unregister_dai(&wm8900_dai); + i2c_del_driver(&wm8900_i2c_driver); } module_exit(wm8900_exit); -- cgit v1.2.3 From 471716f7ea646487b7b5c7b3efc68a023b05a933 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Dec 2008 14:47:07 +0000 Subject: ASoC: Fix typos in Atmel module registration I wish I had boards which work with unmodified kernels :/ Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index d6bcb4e6fda..027eb13f9dd 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -483,7 +483,7 @@ static int __devinit atmel_pcm_modinit(void) } module_init(atmel_pcm_modinit); -static void __exit atmel_pcm_exit(void) +static void __exit atmel_pcm_modexit(void) { snd_soc_unregister_platform(&atmel_soc_platform); } diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index c9f02edd730..87904b6ab8c 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -776,12 +776,13 @@ static int __devinit atmel_ssc_modinit(void) { return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); } -module_init(snd_soc_init); +module_init(atmel_ssc_modinit); -static void __exit snd_soc_exit(void) +static void __exit atmel_ssc_modexit(void) { snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); } +module_exit(atmel_ssc_modexit); /* Module information */ MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); -- cgit v1.2.3 From 24e07db8cceb7dfe2d4005e4450a27f4bcda6499 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 07:40:24 +0100 Subject: ALSA: ASoC - Fix module init entry for twl4030.c Fixed the function name of module init entry for twl4030.c, which conflicted with the existing hardware init function: sound/soc/codecs/twl4030.c:1278: error: conflicting types for 'twl4030_init' sound/soc/codecs/twl4030.c:1187: error: previous definition of 'twl4030_init' was here Also fixed the section type of init function. Signed-off-by: Takashi Iwai --- sound/soc/codecs/twl4030.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 373daa486ce..71ab5342bea 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1275,11 +1275,11 @@ struct snd_soc_codec_device soc_codec_dev_twl4030 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); -static int __devinit twl4030_init(void) +static int __init twl4030_modinit(void) { return snd_soc_register_dai(&twl4030_dai); } -module_init(twl4030_init); +module_init(twl4030_modinit); static void __exit twl4030_exit(void) { -- cgit v1.2.3 From c9b3a40ff2b3dea9914e36965a17c802650bb603 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 07:47:22 +0100 Subject: ALSA: ASoC - Fix wrong section types The module init entries should be __init instead of __devinit. Signed-off-by: Takashi Iwai --- sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 2 +- sound/soc/blackfin/bf5xx-ac97-pcm.c | 2 +- sound/soc/blackfin/bf5xx-ac97.c | 2 +- sound/soc/blackfin/bf5xx-i2s-pcm.c | 2 +- sound/soc/blackfin/bf5xx-i2s.c | 2 +- sound/soc/codecs/ad73311.c | 2 +- sound/soc/codecs/ak4535.c | 2 +- sound/soc/codecs/cs4270.c | 2 +- sound/soc/codecs/pcm3008.c | 2 +- sound/soc/codecs/ssm2602.c | 2 +- sound/soc/codecs/tlv320aic23.c | 2 +- sound/soc/codecs/tlv320aic3x.c | 2 +- sound/soc/codecs/uda134x.c | 2 +- sound/soc/codecs/uda1380.c | 2 +- sound/soc/codecs/wm8510.c | 2 +- sound/soc/codecs/wm8580.c | 2 +- sound/soc/codecs/wm8728.c | 2 +- sound/soc/codecs/wm8731.c | 2 +- sound/soc/codecs/wm8750.c | 2 +- sound/soc/codecs/wm8753.c | 2 +- sound/soc/codecs/wm8900.c | 2 +- sound/soc/codecs/wm8903.c | 2 +- sound/soc/codecs/wm8971.c | 2 +- sound/soc/codecs/wm8990.c | 2 +- sound/soc/davinci/davinci-i2s.c | 2 +- sound/soc/davinci/davinci-pcm.c | 2 +- sound/soc/fsl/fsl_dma.c | 2 +- sound/soc/omap/omap-mcbsp.c | 2 +- sound/soc/omap/omap-pcm.c | 2 +- sound/soc/pxa/pxa-ssp.c | 2 +- sound/soc/pxa/pxa2xx-ac97.c | 2 +- sound/soc/pxa/pxa2xx-pcm.c | 2 +- sound/soc/s3c24xx/s3c2412-i2s.c | 2 +- sound/soc/s3c24xx/s3c2443-ac97.c | 2 +- sound/soc/s3c24xx/s3c24xx-i2s.c | 2 +- sound/soc/s3c24xx/s3c24xx-pcm.c | 2 +- sound/soc/sh/dma-sh7760.c | 2 +- sound/soc/sh/hac.c | 2 +- sound/soc/sh/ssi.c | 2 +- sound/soc/soc-core.c | 2 +- 41 files changed, 41 insertions(+), 41 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 027eb13f9dd..1fac5efd285 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -477,7 +477,7 @@ struct snd_soc_platform atmel_soc_platform = { }; EXPORT_SYMBOL_GPL(atmel_soc_platform); -static int __devinit atmel_pcm_modinit(void) +static int __init atmel_pcm_modinit(void) { return snd_soc_register_platform(&atmel_soc_platform); } diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 87904b6ab8c..c5d67900d66 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -772,7 +772,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { }; EXPORT_SYMBOL_GPL(atmel_ssc_dai); -static int __devinit atmel_ssc_modinit(void) +static int __init atmel_ssc_modinit(void) { return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); } diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 5b27e0d9d0e..8067cfafa3a 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -451,7 +451,7 @@ struct snd_soc_platform bf5xx_ac97_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform); -static int __devinit bfin_ac97_init(void) +static int __init bfin_ac97_init(void) { return snd_soc_register_platform(&bf5xx_ac97_soc_platform); } diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index ad3efeeb6d4..3be2be60576 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -431,7 +431,7 @@ struct snd_soc_dai bfin_ac97_dai = { }; EXPORT_SYMBOL_GPL(bfin_ac97_dai); -static int __devinit bfin_ac97_init(void) +static int __init bfin_ac97_init(void) { return snd_soc_register_dai(&bfin_ac97_dai); } diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index c58b12a4487..53d290b3ea4 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -283,7 +283,7 @@ struct snd_soc_platform bf5xx_i2s_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform); -static int __devinit bfin_i2s_init(void) +static int __init bfin_i2s_init(void) { return snd_soc_register_platform(&bf5xx_i2s_soc_platform); } diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 0d58d2b6db6..c17b131f662 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -313,7 +313,7 @@ struct snd_soc_dai bf5xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); -static int __devinit bfin_i2s_init(void) +static int __init bfin_i2s_init(void) { return snd_soc_register_dai(&bfin_i2s_dai); } diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index e32f55034e6..b09289a1e55 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -98,7 +98,7 @@ struct snd_soc_codec_device soc_codec_dev_ad73311 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311); -static int __devinit ad73311_init(void) +static int __init ad73311_init(void) { return snd_soc_register_dai(&ad73311_dai); } diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 94148fba911..81300d8d42c 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -688,7 +688,7 @@ struct snd_soc_codec_device soc_codec_dev_ak4535 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); -static int __devinit ak4535_modinit(void) +static int __init ak4535_modinit(void) { return snd_soc_register_dai(&ak4535_dai); } diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 73aaf249d78..f1aa0c34421 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -774,7 +774,7 @@ struct snd_soc_codec_device soc_codec_device_cs4270 = { }; EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); -static int __devinit cs4270_init(void) +static int __init cs4270_init(void) { return snd_soc_register_dai(&cs4270_dai); } diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index f333e88ee25..9a3e67e5319 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -195,7 +195,7 @@ struct snd_soc_codec_device soc_codec_dev_pcm3008 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008); -static int __devinit pcm3008_init(void) +static int __init pcm3008_init(void) { return snd_soc_register_dai(&pcm3008_dai); } diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 77fdcb4b9a1..2325aefea41 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -793,7 +793,7 @@ struct snd_soc_codec_device soc_codec_dev_ssm2602 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); -static int __devinit ssm2602_modinit(void) +static int __init ssm2602_modinit(void) { return snd_soc_register_dai(&ssm2602_dai); } diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index eac449b92bd..39f5b981d25 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -847,7 +847,7 @@ struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); -static int __devinit tlv320aic23_modinit(void) +static int __init tlv320aic23_modinit(void) { return snd_soc_register_dai(&tlv320aic23_dai); } diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index ccd57596186..8da9e5d2e2f 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1411,7 +1411,7 @@ struct snd_soc_codec_device soc_codec_dev_aic3x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); -static int __devinit aic3x_modinit(void) +static int __init aic3x_modinit(void) { return snd_soc_register_dai(&aic3x_dai); } diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 8e035b5d733..a2c5064a774 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -651,7 +651,7 @@ struct snd_soc_codec_device soc_codec_dev_uda134x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); -static int __devinit uda134x_init(void) +static int __init uda134x_init(void) { return snd_soc_register_dai(&uda134x_dai); } diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 55a99b6a68a..e6bf0844fbf 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -841,7 +841,7 @@ struct snd_soc_codec_device soc_codec_dev_uda1380 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); -static int __devinit uda1380_modinit(void) +static int __init uda1380_modinit(void) { return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); } diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index a2af04bb4e9..40f8238df71 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -889,7 +889,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8510 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); -static int __devinit wm8510_modinit(void) +static int __init wm8510_modinit(void) { return snd_soc_register_dai(&wm8510_dai); } diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 391ec2978ae..d004e584529 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1042,7 +1042,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); -static int __devinit wm8580_modinit(void) +static int __init wm8580_modinit(void) { return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); } diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index d905e25b1a9..80b11983e13 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -568,7 +568,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8728 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); -static int __devinit wm8728_modinit(void) +static int __init wm8728_modinit(void) { return snd_soc_register_dai(&wm8728_dai); } diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7b455a60d71..c444b9f2701 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -793,7 +793,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); -static int __devinit wm8731_modinit(void) +static int __init wm8731_modinit(void) { return snd_soc_register_dai(&wm8731_dai); } diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 84a6307de90..5997fa68e0d 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -1085,7 +1085,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8750 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); -static int __devinit wm8750_modinit(void) +static int __init wm8750_modinit(void) { return snd_soc_register_dai(&wm8750_dai); } diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 1caca30d081..6c21b50c937 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1874,7 +1874,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8753 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); -static int __devinit wm8753_modinit(void) +static int __init wm8753_modinit(void) { return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); } diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 34e58af0c65..ebf58fba1be 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1473,7 +1473,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8900 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); -static int __devinit wm8900_modinit(void) +static int __init wm8900_modinit(void) { return i2c_add_driver(&wm8900_i2c_driver); } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 5d8fe7e1571..0b5bea37e3d 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1809,7 +1809,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8903 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); -static int __devinit wm8903_modinit(void) +static int __init wm8903_modinit(void) { return snd_soc_register_dai(&wm8903_dai); } diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 2979fc4f44f..88ead7f8dd9 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -935,7 +935,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8971 = { EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); -static int __devinit wm8971_modinit(void) +static int __init wm8971_modinit(void) { return snd_soc_register_dai(&wm8971_dai); } diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 53e71aafe6c..5b5afc14447 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1643,7 +1643,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8990 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); -static int __devinit wm8990_modinit(void) +static int __init wm8990_modinit(void) { return snd_soc_register_dai(&wm8990_dai); } diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d89fc2f009a..81ff5c37ab5 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -481,7 +481,7 @@ struct snd_soc_dai davinci_i2s_dai = { }; EXPORT_SYMBOL_GPL(davinci_i2s_dai); -static int __devinit davinci_i2s_init(void) +static int __init davinci_i2s_init(void) { return snd_soc_register_dai(&davinci_i2s_dai); } diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index f1b6e02d24e..bc83e1cbd17 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -384,7 +384,7 @@ struct snd_soc_platform davinci_soc_platform = { }; EXPORT_SYMBOL_GPL(davinci_soc_platform); -static int __devinit davinci_soc_platform_init(void) +static int __init davinci_soc_platform_init(void) { return snd_soc_register_platform(&davinci_soc_platform); } diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 646c807163a..64993eda567 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -853,7 +853,7 @@ int fsl_dma_configure(struct fsl_dma_info *dma_info) } EXPORT_SYMBOL_GPL(fsl_dma_configure); -static int __devinit fsl_soc_platform_init(void) +static int __init fsl_soc_platform_init(void) { return snd_soc_register_platform(&fsl_soc_platform); } diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 41cab203416..39cc57ce4bf 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -499,7 +499,7 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); -static int __devinit omap_mcbsp_init(void) +static int __init omap_mcbsp_init(void) { return snd_soc_register_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 9940de29631..ce580a97cbd 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -354,7 +354,7 @@ struct snd_soc_platform omap_soc_platform = { }; EXPORT_SYMBOL_GPL(omap_soc_platform); -static int __devinit omap_soc_platform_init(void) +static int __init omap_soc_platform_init(void) { return snd_soc_register_platform(&omap_soc_platform); } diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 3587f2fae5f..73cb6b4c2f2 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -913,7 +913,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { }; EXPORT_SYMBOL_GPL(pxa_ssp_dai); -static int __devinit pxa_ssp_init(void) +static int __init pxa_ssp_init(void) { return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); } diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index f6249d5b492..780db6757ad 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -228,7 +228,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { EXPORT_SYMBOL_GPL(pxa_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); -static int __devinit pxa_ac97_init(void) +static int __init pxa_ac97_init(void) { return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); } diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 4fa1578f5d4..c670d08e7c9 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -118,7 +118,7 @@ struct snd_soc_platform pxa2xx_soc_platform = { }; EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); -static int __devinit pxa2xx_soc_platform_init(void) +static int __init pxa2xx_soc_platform_init(void) { return snd_soc_register_platform(&pxa2xx_soc_platform); } diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 2cf05079156..f3fc0aba0aa 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -736,7 +736,7 @@ struct snd_soc_dai s3c2412_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); -static int __devinit s3c2412_i2s_init(void) +static int __init s3c2412_i2s_init(void) { return snd_soc_register_dai(&s3c2412_i2s_dai); } diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 7360c6d913b..723779a3058 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -396,7 +396,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); -static int __devinit s3c2443_ac97_init(void) +static int __init s3c2443_ac97_init(void) { return snd_soc_register_dai(&s3c2443_ac97_dai); } diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 897b1ac92ce..6f4d439b57a 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -482,7 +482,7 @@ struct snd_soc_dai s3c24xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); -static int __devinit s3c24xx_i2s_init(void) +static int __init s3c24xx_i2s_init(void) { return snd_soc_register_dai(&s3c24xx_i2s_dai); } diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index ea5a9caec13..7c64d31d067 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -465,7 +465,7 @@ struct snd_soc_platform s3c24xx_soc_platform = { }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); -static int __devinit s3c24xx_soc_platform_init(void) +static int __init s3c24xx_soc_platform_init(void) { return snd_soc_register_platform(&s3c24xx_soc_platform); } diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 39ffca0933a..0dad3a0bb92 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -348,7 +348,7 @@ struct snd_soc_platform sh7760_soc_platform = { }; EXPORT_SYMBOL_GPL(sh7760_soc_platform); -static int __devinit sh7760_soc_platform_init(void) +static int __init sh7760_soc_platform_init(void) { return snd_soc_register_platform(&sh7760_soc_platform); } diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 9169bad1acf..eab31838bad 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -314,7 +314,7 @@ struct snd_soc_dai sh4_hac_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_hac_dai); -static int __devinit sh4_hac_init(void) +static int __init sh4_hac_init(void) { return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); } diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 9093588d4d0..d1e5390fdde 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -392,7 +392,7 @@ struct snd_soc_dai sh4_ssi_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_ssi_dai); -static int __devinit sh4_ssi_init(void) +static int __init sh4_ssi_init(void) { return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 76a89eb65ba..4d2db7cfaf4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2224,7 +2224,7 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform) } EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); -static int __devinit snd_soc_init(void) +static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS debugfs_root = debugfs_create_dir("asoc", NULL); -- cgit v1.2.3 From f73f2a6a23e34de9cca9672f727694e5af00e6c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 07:59:33 +0100 Subject: ALSA: ASoC - Fix symbol conflicts in omac-mcbsp.c Add snd_ prefix to avoid the conflict of symbols in omac-mcbsp.c: sound/soc/omap/omap-mcbsp.c:503: error: static declaration of 'omap_mcbsp_init' follows non-static declaration arch/arm/plat-omap/include/mach/mcbsp.h:373: error: previous declaration of 'omap_mcbsp_init' was here Signed-off-by: Takashi Iwai --- sound/soc/omap/omap-mcbsp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 39cc57ce4bf..7b86373007c 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -499,18 +499,18 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); -static int __init omap_mcbsp_init(void) +static int __init snd_omap_mcbsp_init(void) { return snd_soc_register_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); } -module_init(omap_mcbsp_init); +module_init(snd_omap_mcbsp_init); -static void __exit omap_mcbsp_exit(void) +static void __exit snd_omap_mcbsp_exit(void) { snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); } -module_exit(omap_mcbsp_exit); +module_exit(snd_omap_mcbsp_exit); MODULE_AUTHOR("Jarkko Nikula "); MODULE_DESCRIPTION("OMAP I2S SoC Interface"); -- cgit v1.2.3 From 1e297a19252a6792c4479b300020f7f63eeb56ef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 11:08:33 +0000 Subject: ASoC: Work around warnings from some build environments BUG() should be marked as not returning but for at least some configurations (including some widely deployed compilers) that's either not happening or being forgotten by the compiler. Add some extra return statements to the affected paths. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 0b5bea37e3d..b1f5cf77a87 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -392,6 +392,7 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, break; default: BUG(); + return -EINVAL; /* Spurious warning from some compilers */ } switch (w->shift) { @@ -403,6 +404,7 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, break; default: BUG(); + return -EINVAL; /* Spurious warning from some compilers */ } if (event & SND_SOC_DAPM_PRE_PMU) { -- cgit v1.2.3 From 6a1bee4a9cae13aa73abd8f724bada213a38eb63 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 10 Dec 2008 12:51:46 +0200 Subject: ASoC: TWL4030: Add missing Carkit output SND_SOC_DAPM_OUTPUT definition for carkitL/R was missing. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 71ab5342bea..13d5a12ac29 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -761,6 +761,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("PREDRIVER"), SND_SOC_DAPM_OUTPUT("HSOL"), SND_SOC_DAPM_OUTPUT("HSOR"), + SND_SOC_DAPM_OUTPUT("CARKITL"), + SND_SOC_DAPM_OUTPUT("CARKITR"), SND_SOC_DAPM_OUTPUT("HFL"), SND_SOC_DAPM_OUTPUT("HFR"), -- cgit v1.2.3 From d4a73131a56e906b8f65e20934516adcad68b524 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 10 Dec 2008 12:51:47 +0200 Subject: ASoC: TWL4030: Small cleanup The mux switch related texts fits to on line, no need to wrap them. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 13d5a12ac29..b321928152d 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -192,8 +192,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* Earpiece */ static const char *twl4030_earpiece_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR1"}; + {"Off", "DACL1", "DACL2", "Invalid", "DACR1"}; static const struct soc_enum twl4030_earpiece_enum = SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, @@ -205,8 +204,7 @@ SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); /* PreDrive Left */ static const char *twl4030_predrivel_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR2"}; + {"Off", "DACL1", "DACL2", "Invalid", "DACR2"}; static const struct soc_enum twl4030_predrivel_enum = SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, @@ -218,8 +216,7 @@ SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); /* PreDrive Right */ static const char *twl4030_predriver_texts[] = - {"Off", "DACR1", "DACR2", "Invalid", - "DACL2"}; + {"Off", "DACR1", "DACR2", "Invalid", "DACL2"}; static const struct soc_enum twl4030_predriver_enum = SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, -- cgit v1.2.3 From 1e5fa31f96d558e53fe80e943305104bf4339711 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 10 Dec 2008 12:51:48 +0200 Subject: ASoC: TWL4030: Change the name for the DACs To avoid confusion the names for the DACs changed: DACL1 -> DAC Left1 ... Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b321928152d..13773028f6f 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -764,13 +764,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HFR"), /* DACs */ - SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", + SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback", TWL4030_REG_AVDAC_CTL, 0, 0), - SND_SOC_DAPM_DAC("DACL1", "Left Front Playback", + SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback", TWL4030_REG_AVDAC_CTL, 1, 0), - SND_SOC_DAPM_DAC("DACR2", "Right Rear Playback", + SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback", TWL4030_REG_AVDAC_CTL, 2, 0), - SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", + SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback", TWL4030_REG_AVDAC_CTL, 3, 0), /* Analog PGAs */ @@ -816,10 +816,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { }; static const struct snd_soc_dapm_route intercon[] = { - {"ARXL1_APGA", NULL, "DACL1"}, - {"ARXR1_APGA", NULL, "DACR1"}, - {"ARXL2_APGA", NULL, "DACL2"}, - {"ARXR2_APGA", NULL, "DACR2"}, + {"ARXL1_APGA", NULL, "DAC Left1"}, + {"ARXR1_APGA", NULL, "DAC Right1"}, + {"ARXL2_APGA", NULL, "DAC Left2"}, + {"ARXR2_APGA", NULL, "DAC Right2"}, /* Internal playback routings */ /* Earpiece */ -- cgit v1.2.3 From 0d0cf00a7fc63cee9a4c4a3b8612879b4f7f42ba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 14:32:45 +0000 Subject: ASoC: Add codec registration API Another part of the backporting of Liam's ASoC v2 work. Using this is more complicated than the other registration types since currently the codec is instantiated during the probe of the ASoC device so we can't currently readily wait for the codec to register. Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index ce3661d07c2..f86e455d382 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -161,6 +161,8 @@ extern struct snd_ac97_bus_ops soc_ac97_ops; int snd_soc_register_platform(struct snd_soc_platform *platform); void snd_soc_unregister_platform(struct snd_soc_platform *platform); +int snd_soc_register_codec(struct snd_soc_codec *codec); +void snd_soc_unregister_codec(struct snd_soc_codec *codec); /* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); @@ -247,6 +249,9 @@ struct snd_soc_codec { char *name; struct module *owner; struct mutex mutex; + struct device *dev; + + struct list_head list; /* callbacks */ int (*set_bias_level)(struct snd_soc_codec *, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4d2db7cfaf4..b098c0b4c58 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -47,6 +47,7 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(card_list); static LIST_HEAD(dai_list); static LIST_HEAD(platform_list); +static LIST_HEAD(codec_list); static int snd_soc_register_card(struct snd_soc_card *card); static int snd_soc_unregister_card(struct snd_soc_card *card); @@ -2224,6 +2225,48 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform) } EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); +/** + * snd_soc_register_codec - Register a codec with the ASoC core + * + * @param codec codec to register + */ +int snd_soc_register_codec(struct snd_soc_codec *codec) +{ + if (!codec->name) + return -EINVAL; + + /* The device should become mandatory over time */ + if (!codec->dev) + printk(KERN_WARNING "No device for codec %s\n", codec->name); + + INIT_LIST_HEAD(&codec->list); + + mutex_lock(&client_mutex); + list_add(&codec->list, &codec_list); + snd_soc_instantiate_cards(); + mutex_unlock(&client_mutex); + + pr_debug("Registered codec '%s'\n", codec->name); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_register_codec); + +/** + * snd_soc_unregister_codec - Unregister a codec from the ASoC core + * + * @param codec codec to unregister + */ +void snd_soc_unregister_codec(struct snd_soc_codec *codec) +{ + mutex_lock(&client_mutex); + list_del(&codec->list); + mutex_unlock(&client_mutex); + + pr_debug("Unregistered codec '%s'\n", codec->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS -- cgit v1.2.3 From 78e19a39d3985e2a06354493a70a200c0d432de5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 15:38:36 +0000 Subject: ASoC: Convert WM8900 to do more work at I2C probe time Redo the instantiation of the WM8900 to do most of the initialisation work when the I2C driver probes rather than when the ASoC device is instantiated, registering the codec with the ASoC core when done. Also move all dynamic allocations into a single kmalloc() to simplify error handling and rename the I2C driver to make output more sensible. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8900.c | 159 +++++++++++++++++++++++----------------------- sound/soc/codecs/wm8900.h | 7 -- 2 files changed, 81 insertions(+), 85 deletions(-) diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index ebf58fba1be..6767de10ded 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -138,6 +138,10 @@ struct snd_soc_codec_device soc_codec_dev_wm8900; struct wm8900_priv { + struct snd_soc_codec codec; + + u16 reg_cache[WM8900_MAXREG]; + u32 fll_in; /* FLL input frequency */ u32 fll_out; /* FLL output frequency */ }; @@ -1282,16 +1286,28 @@ static int wm8900_resume(struct platform_device *pdev) return 0; } -/* - * initialise the WM8900 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8900_init(struct snd_soc_device *socdev) +static struct snd_soc_codec *wm8900_codec; + +static int wm8900_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; + struct wm8900_priv *wm8900; + struct snd_soc_codec *codec; unsigned int reg; - struct i2c_client *i2c_client = socdev->codec->control_data; + int ret; + + wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); + if (wm8900 == NULL) + return -ENOMEM; + + codec = &wm8900->codec; + codec->private_data = wm8900; + codec->reg_cache = &wm8900->reg_cache[0]; + codec->reg_cache_size = WM8900_MAXREG; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); codec->name = "WM8900"; codec->owner = THIS_MODULE; @@ -1299,33 +1315,28 @@ static int wm8900_init(struct snd_soc_device *socdev) codec->write = wm8900_write; codec->dai = &wm8900_dai; codec->num_dai = 1; - codec->reg_cache_size = WM8900_MAXREG; - codec->reg_cache = kmemdup(wm8900_reg_defaults, - sizeof(wm8900_reg_defaults), GFP_KERNEL); - - if (codec->reg_cache == NULL) - return -ENOMEM; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->control_data = i2c; + codec->set_bias_level = wm8900_set_bias_level; + codec->dev = &i2c->dev; reg = wm8900_read(codec, WM8900_REG_ID); if (reg != 0x8900) { - dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n", - reg); - return -ENODEV; - } - - codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); - if (codec->private_data == NULL) { - ret = -ENOMEM; - goto priv_err; + dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg); + ret = -ENODEV; + goto err; } /* Read back from the chip */ reg = wm8900_chip_read(codec, WM8900_REG_POWER1); reg = (reg >> 12) & 0xf; - dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg); + dev_info(&i2c->dev, "WM8900 revision %d\n", reg); wm8900_reset(codec); + /* Turn the chip on */ + wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Latch the volume update bits */ wm8900_write(codec, WM8900_REG_LINVOL, wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); @@ -1351,52 +1362,43 @@ static int wm8900_init(struct snd_soc_device *socdev) /* Set the DAC and mixer output bias */ wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); - /* Register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(&i2c_client->dev, "Failed to register new PCMs\n"); - goto pcm_err; - } + wm8900_dai.dev = &i2c->dev; - /* Turn the chip on */ - codec->bias_level = SND_SOC_BIAS_OFF; - wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8900_codec = codec; - wm8900_add_controls(codec); - wm8900_add_widgets(codec); + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + goto err; + } - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&i2c_client->dev, "Failed to register card\n"); - goto card_err; + ret = snd_soc_register_dai(&wm8900_dai); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; } - return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); -priv_err: - kfree(codec->private_data); return ret; -} - -static struct i2c_client *wm8900_client; -static int wm8900_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - wm8900_client = i2c; - wm8900_dai.dev = &i2c->dev; - return snd_soc_register_dai(&wm8900_dai); +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8900); + wm8900_codec = NULL; + return ret; } static int wm8900_i2c_remove(struct i2c_client *client) { snd_soc_unregister_dai(&wm8900_dai); + snd_soc_unregister_codec(wm8900_codec); + + wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF); + wm8900_dai.dev = NULL; - wm8900_client = NULL; + kfree(wm8900_codec->private_data); + wm8900_codec = NULL; + return 0; } @@ -1408,7 +1410,7 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); static struct i2c_driver wm8900_i2c_driver = { .driver = { - .name = "WM8900 I2C codec", + .name = "WM8900", .owner = THIS_MODULE, }, .probe = wm8900_i2c_probe, @@ -1422,30 +1424,36 @@ static int wm8900_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0; - if (!wm8900_client) { + if (!wm8900_codec) { dev_err(&pdev->dev, "I2C client not yet instantiated\n"); return -ENODEV; } - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - + codec = wm8900_codec; socdev->codec = codec; - codec->set_bias_level = wm8900_set_bias_level; + /* Register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register new PCMs\n"); + goto pcm_err; + } - codec->hw_write = (hw_write_t)i2c_master_send; - codec->control_data = wm8900_client; + wm8900_add_controls(codec); + wm8900_add_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register card\n"); + goto card_err; + } - ret = wm8900_init(socdev); - if (ret != 0) - kfree(codec); + return ret; +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: return ret; } @@ -1453,14 +1461,9 @@ static int wm8900_probe(struct platform_device *pdev) static int wm8900_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); - kfree(codec); return 0; } diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h index 2249a446ad3..fd15007d10c 100644 --- a/sound/soc/codecs/wm8900.h +++ b/sound/soc/codecs/wm8900.h @@ -52,13 +52,6 @@ #define WM8900_DAC_CLKDIV_5_5 0x14 #define WM8900_DAC_CLKDIV_6 0x18 -#define WM8900_ - -struct wm8900_setup_data { - int i2c_bus; - unsigned short i2c_address; -}; - extern struct snd_soc_dai wm8900_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8900; -- cgit v1.2.3 From d58d5d5567ea9483346f57c83a94ce05992cd47c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 18:36:42 +0000 Subject: ASoC: Convert WM8903 driver to register at I2C probe time The driver now registers the codec and DAI when probed as an I2C device. Also convert the driver to use a single dynamic allocation to simplify error handling. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 230 +++++++++++++++++++--------------------------- sound/soc/codecs/wm8903.h | 5 - 2 files changed, 97 insertions(+), 138 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b1f5cf77a87..c80968fe326 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -33,19 +33,6 @@ #include "wm8903.h" -struct wm8903_priv { - int sysclk; - - /* Reference counts */ - int charge_pump_users; - int class_w_users; - int playback_active; - int capture_active; - - struct snd_pcm_substream *master_substream; - struct snd_pcm_substream *slave_substream; -}; - /* Register defaults at reset */ static u16 wm8903_reg_defaults[] = { 0x8903, /* R0 - SW Reset and ID */ @@ -223,6 +210,23 @@ static u16 wm8903_reg_defaults[] = { 0x0000, /* R172 - Analogue Output Bias 0 */ }; +struct wm8903_priv { + struct snd_soc_codec codec; + u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)]; + + int sysclk; + + /* Reference counts */ + int charge_pump_users; + int class_w_users; + int playback_active; + int capture_active; + + struct snd_pcm_substream *master_substream; + struct snd_pcm_substream *slave_substream; +}; + + static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { @@ -360,6 +364,8 @@ static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) static void wm8903_reset(struct snd_soc_codec *codec) { wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); + memcpy(codec->reg_cache, wm8903_reg_defaults, + sizeof(wm8903_reg_defaults)); } #define WM8903_OUTPUT_SHORT 0x8 @@ -1563,39 +1569,48 @@ static int wm8903_resume(struct platform_device *pdev) return 0; } -/* - * initialise the WM8903 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8903_init(struct snd_soc_device *socdev) +static struct snd_soc_codec *wm8903_codec; + +static int wm8903_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c = codec->control_data; - int ret = 0; + struct wm8903_priv *wm8903; + struct snd_soc_codec *codec; + int ret; u16 val; - val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); - if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { - dev_err(&i2c->dev, - "Device with ID register %x is not a WM8903\n", val); - return -ENODEV; - } + wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); + if (wm8903 == NULL) + return -ENOMEM; + codec = &wm8903->codec; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->dev = &i2c->dev; codec->name = "WM8903"; codec->owner = THIS_MODULE; codec->read = wm8903_read; codec->write = wm8903_write; + codec->hw_write = (hw_write_t)i2c_master_send; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8903_set_bias_level; codec->dai = &wm8903_dai; codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults); - codec->reg_cache = kmemdup(wm8903_reg_defaults, - sizeof(wm8903_reg_defaults), - GFP_KERNEL); - if (codec->reg_cache == NULL) { - dev_err(&i2c->dev, "Failed to allocate register cache\n"); - return -ENOMEM; + codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache); + codec->reg_cache = &wm8903->reg_cache[0]; + codec->private_data = wm8903; + + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); + if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { + dev_err(&i2c->dev, + "Device with ID register %x is not a WM8903\n", val); + return -ENODEV; } val = wm8903_read(codec, WM8903_REVISION_NUMBER); @@ -1604,13 +1619,6 @@ static int wm8903_init(struct snd_soc_device *socdev) wm8903_reset(codec); - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(&i2c->dev, "failed to create pcms\n"); - goto pcm_err; - } - /* SYSCLK is required for pretty much anything */ wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); @@ -1648,47 +1656,45 @@ static int wm8903_init(struct snd_soc_device *socdev) val |= WM8903_DAC_MUTEMODE; wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); - wm8903_add_controls(codec); - wm8903_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&i2c->dev, "wm8903: failed to register card\n"); - goto card_err; + wm8903_dai.dev = &i2c->dev; + wm8903_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&wm8903_dai); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); +err_codec: + snd_soc_unregister_codec(codec); +err: + wm8903_codec = NULL; + kfree(wm8903); return ret; } -static struct snd_soc_device *wm8903_socdev; - -static int wm8903_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8903_i2c_remove(struct i2c_client *client) { - struct snd_soc_device *socdev = wm8903_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; + struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; + snd_soc_unregister_dai(&wm8903_dai); + snd_soc_unregister_codec(codec); - ret = wm8903_init(socdev); - if (ret < 0) - dev_err(&i2c->dev, "Device initialisation failed\n"); + wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); - return ret; -} + kfree(codec->private_data); + + wm8903_codec = NULL; + wm8903_dai.dev = NULL; -static int wm8903_i2c_remove(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); return 0; } @@ -1712,75 +1718,37 @@ static struct i2c_driver wm8903_i2c_driver = { static int wm8903_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8903_setup_data *setup; - struct snd_soc_codec *codec; - struct wm8903_priv *wm8903; - struct i2c_board_info board_info; - struct i2c_adapter *adapter; - struct i2c_client *i2c_client; int ret = 0; - setup = socdev->codec_data; - - if (!setup->i2c_address) { - dev_err(&pdev->dev, "No codec address provided\n"); - return -ENODEV; + if (!wm8903_codec) { + dev_err(&pdev->dev, "I2C device not yet probed\n"); + goto err; } - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; + socdev->codec = wm8903_codec; - wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); - if (wm8903 == NULL) { - ret = -ENOMEM; - goto err_codec; + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to create pcms\n"); + goto err; } - codec->private_data = wm8903; - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); + wm8903_add_controls(socdev->codec); + wm8903_add_widgets(socdev->codec); - wm8903_socdev = socdev; - - codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8903_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - goto err_priv; - } else { - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE); - board_info.addr = setup->i2c_address; - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "Can't get I2C bus %d\n", - setup->i2c_bus); - ret = -ENODEV; - goto err_adapter; - } - - i2c_client = i2c_new_device(adapter, &board_info); - i2c_put_adapter(adapter); - if (i2c_client == NULL) { - dev_err(&pdev->dev, - "I2C driver registration failed\n"); - ret = -ENODEV; - goto err_adapter; - } + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "wm8903: failed to register card\n"); + goto card_err; } return ret; -err_adapter: - i2c_del_driver(&wm8903_i2c_driver); -err_priv: - kfree(codec->private_data); -err_codec: - kfree(codec); +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +err: return ret; } @@ -1795,10 +1763,6 @@ static int wm8903_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); - i2c_unregister_device(socdev->codec->control_data); - i2c_del_driver(&wm8903_i2c_driver); - kfree(codec->private_data); - kfree(codec); return 0; } @@ -1813,13 +1777,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); static int __init wm8903_modinit(void) { - return snd_soc_register_dai(&wm8903_dai); + return i2c_add_driver(&wm8903_i2c_driver); } module_init(wm8903_modinit); static void __exit wm8903_exit(void) { - snd_soc_unregister_dai(&wm8903_dai); + i2c_del_driver(&wm8903_i2c_driver); } module_exit(wm8903_exit); diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h index cec622f2f66..0ea27e2b996 100644 --- a/sound/soc/codecs/wm8903.h +++ b/sound/soc/codecs/wm8903.h @@ -18,11 +18,6 @@ extern struct snd_soc_dai wm8903_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8903; -struct wm8903_setup_data { - int i2c_bus; - int i2c_address; -}; - #define WM8903_MCLK_DIV_2 1 #define WM8903_CLK_SYS 2 #define WM8903_BCLK 3 -- cgit v1.2.3 From 3b1228abc93f7ab0aa28c46341d6a0f7e2cade70 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 19:27:10 +0000 Subject: ASoC: Stop WM8903 SYSCLK when suspending This will save some additional power. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c80968fe326..bde74546db4 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -997,6 +997,9 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { + wm8903_write(codec, WM8903_CLOCK_RATES_2, + WM8903_CLK_SYS_ENA); + wm8903_run_sequence(codec, 0); wm8903_sync_reg_cache(codec, codec->reg_cache); @@ -1027,6 +1030,9 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: wm8903_run_sequence(codec, 32); + reg = wm8903_read(codec, WM8903_CLOCK_RATES_2); + reg &= ~WM8903_CLK_SYS_ENA; + wm8903_write(codec, WM8903_CLOCK_RATES_2, reg); break; } @@ -1619,9 +1625,6 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, wm8903_reset(codec); - /* SYSCLK is required for pretty much anything */ - wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); - /* power on device */ wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -- cgit v1.2.3 From 6de45d5d776d2a7e7a9adc8ea49d37fe1bd45fb2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 10:28:18 +0100 Subject: ALSA: ASoC - Fix DAI registration in s3c2443-ac97.c Fixed the registration of dais in s3c2443-ac97.c. sound/soc/s3c24xx/s3c2443-ac97.c: In function 's3c2443_ac97_init': sound/soc/s3c24xx/s3c2443-ac97.c:401: warning: passing argument 1 of 'snd_soc_register_dai' from incompatible pointer type sound/soc/s3c24xx/s3c2443-ac97.c: In function 's3c2443_ac97_exit': sound/soc/s3c24xx/s3c2443-ac97.c:407: warning: passing argument 1 of 'snd_soc_unregister_dai' from incompatible pointer type Signed-off-by: Takashi Iwai --- sound/soc/s3c24xx/s3c2443-ac97.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 723779a3058..1bfce40bb2e 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -398,13 +398,15 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops); static int __init s3c2443_ac97_init(void) { - return snd_soc_register_dai(&s3c2443_ac97_dai); + return snd_soc_register_dais(s3c2443_ac97_dai, + ARRAY_SIZE(s3c2443_ac97_dai)); } module_init(s3c2443_ac97_init); static void __exit s3c2443_ac97_exit(void) { - snd_soc_unregister_dai(&s3c2443_ac97_dai); + snd_soc_unregister_dais(s3c2443_ac97_dai, + ARRAY_SIZE(s3c2443_ac97_dai)); } module_exit(s3c2443_ac97_exit); -- cgit v1.2.3 From 4544f8a22f38ba4560320fcfbe8c7e81562ddc6f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Dec 2008 16:11:38 +0000 Subject: ASoC: Fix variable name for Blackfin I2S DAI Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index c17b131f662..d1d95d2393f 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -315,13 +315,13 @@ EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); static int __init bfin_i2s_init(void) { - return snd_soc_register_dai(&bfin_i2s_dai); + return snd_soc_register_dai(&bf5xx_i2s_dai); } module_init(bfin_i2s_init); static void __exit bfin_i2s_exit(void) { - snd_soc_unregister_dai(&bfin_i2s_dai); + snd_soc_unregister_dai(&bf5xx_i2s_dai); } module_exit(bfin_i2s_exit); -- cgit v1.2.3 From 49d92c7d5bbd158734bc34ed578a68b214a48583 Mon Sep 17 00:00:00 2001 From: "Stanley.Miao" Date: Thu, 11 Dec 2008 23:28:10 +0800 Subject: ASoC: TWL4030: hands-free start-up sequence. A special start-up sequence is required to reduce the pop-noise of Class D amplifier when enable hands-free on TWL4030. Signed-off-by: Stanley.Miao Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 34 ++++++++++++++++++++++++++++++---- sound/soc/codecs/twl4030.h | 6 ++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 13773028f6f..51848880504 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -322,6 +322,30 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, return ret; } +static int handsfree_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value; + unsigned char hs_ctl; + + hs_ctl = twl4030_read_reg_cache(w->codec, e->reg); + + if (hs_ctl & TWL4030_HF_CTL_REF_EN) { + hs_ctl |= TWL4030_HF_CTL_RAMP_EN; + twl4030_write(w->codec, e->reg, hs_ctl); + hs_ctl |= TWL4030_HF_CTL_LOOP_EN; + twl4030_write(w->codec, e->reg, hs_ctl); + hs_ctl |= TWL4030_HF_CTL_HB_EN; + twl4030_write(w->codec, e->reg, hs_ctl); + } else { + hs_ctl &= ~(TWL4030_HF_CTL_RAMP_EN | TWL4030_HF_CTL_LOOP_EN + | TWL4030_HF_CTL_HB_EN); + twl4030_write(w->codec, e->reg, hs_ctl); + } + + return 0; +} + /* * Some of the gain controls in TWL (mostly those which are associated with * the outputs) are implemented in an interesting way: @@ -806,10 +830,12 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_carkitr_control), /* HandsfreeL/R */ - SND_SOC_DAPM_MUX("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, - &twl4030_dapm_handsfreel_control), - SND_SOC_DAPM_MUX("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, - &twl4030_dapm_handsfreer_control), + SND_SOC_DAPM_MUX_E("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, + &twl4030_dapm_handsfreel_control, handsfree_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, + &twl4030_dapm_handsfreer_control, handsfree_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index a2065d417c2..54615c76802 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -191,6 +191,12 @@ #define TWL4030_RAMP_DELAY_2581MS 0x1C #define TWL4030_RAMP_EN 0x02 +/* HFL_CTL (0x29, 0x2A) Fields */ +#define TWL4030_HF_CTL_HB_EN 0x04 +#define TWL4030_HF_CTL_LOOP_EN 0x08 +#define TWL4030_HF_CTL_RAMP_EN 0x10 +#define TWL4030_HF_CTL_REF_EN 0x20 + /* APLL_CTL (0x3A) Fields */ #define TWL4030_APLL_EN 0x10 -- cgit v1.2.3 From 9cd28ab0051cc5232e3dffea6b318233445a3d5f Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Sat, 13 Dec 2008 16:25:27 +0300 Subject: ASoC: switch davinci DPRINTK to pr_debug() Signed-off-by: Alexander Beregalov Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-pcm.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index bc83e1cbd17..74abc9b4f1c 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,13 +25,6 @@ #include "davinci-pcm.h" -#define DAVINCI_PCM_DEBUG 0 -#if DAVINCI_PCM_DEBUG -#define DPRINTK(x...) printk(KERN_DEBUG x) -#else -#define DPRINTK(x...) -#endif - static struct snd_pcm_hardware davinci_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -78,8 +72,8 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset; - DPRINTK("audio_set_dma_params_play channel = %d dma_ptr = %x " - "period_size=%x\n", lch, dma_pos, period_size); + pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " + "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size); data_type = prtd->params->data_type; count = period_size / data_type; @@ -112,7 +106,7 @@ static void davinci_pcm_dma_irq(int lch, u16 ch_status, void *data) struct snd_pcm_substream *substream = data; struct davinci_runtime_data *prtd = substream->runtime->private_data; - DPRINTK("lch=%d, status=0x%x\n", lch, ch_status); + pr_debug("davinci_pcm: lch=%d, status=0x%x\n", lch, ch_status); if (unlikely(ch_status != DMA_COMPLETE)) return; @@ -316,8 +310,8 @@ static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) buf->area = dma_alloc_writecombine(pcm->card->dev, size, &buf->addr, GFP_KERNEL); - DPRINTK("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, (void *) buf->addr, size); + pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, " + "size=%d\n", (void *) buf->area, (void *) buf->addr, size); if (!buf->area) return -ENOMEM; -- cgit v1.2.3 From 0b34a3d03e2fa615a786027b1ef4cbbd8c807f2c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Dec 2008 14:44:48 +0000 Subject: ASoC: Ease merge difficulties from new architectures Rather than listing lots of architectures per line in Kconfig and Makefile, causing merge conflicts all the time, have one per line in alphabetical order. Signed-off-by: Mark Brown --- sound/soc/Kconfig | 10 +++++----- sound/soc/Makefile | 12 ++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 615ebf0b76e..ef025c66cc6 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -22,16 +22,16 @@ if SND_SOC config SND_SOC_AC97_BUS bool -# All the supported Soc's +# All the supported SoCs source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" +source "sound/soc/blackfin/Kconfig" +source "sound/soc/davinci/Kconfig" +source "sound/soc/fsl/Kconfig" +source "sound/soc/omap/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" source "sound/soc/sh/Kconfig" -source "sound/soc/fsl/Kconfig" -source "sound/soc/davinci/Kconfig" -source "sound/soc/omap/Kconfig" -source "sound/soc/blackfin/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 4d475c3ceb9..86a9b1f5b0f 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,13 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ atmel/ pxa/ s3c24xx/ sh/ fsl/ davinci/ -obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ +obj-$(CONFIG_SND_SOC) += codecs/ +obj-$(CONFIG_SND_SOC) += atmel/ +obj-$(CONFIG_SND_SOC) += au1x/ +obj-$(CONFIG_SND_SOC) += blackfin/ +obj-$(CONFIG_SND_SOC) += davinci/ +obj-$(CONFIG_SND_SOC) += fsl/ +obj-$(CONFIG_SND_SOC) += omap/ +obj-$(CONFIG_SND_SOC) += pxa/ +obj-$(CONFIG_SND_SOC) += s3c24xx/ +obj-$(CONFIG_SND_SOC) += sh/ -- cgit v1.2.3 From b8b33cb5608a3bb1b072548dc89159ef614096ab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 18 Dec 2008 11:19:30 +0000 Subject: ASoC: Complain if we fail to create DAPM controls This should never happen and it's helpful to identify the specific control that failed when it does happen. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 61d7d85aa57..8863eddbac0 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1320,8 +1320,12 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, for (i = 0; i < num; i++) { ret = snd_soc_dapm_new_control(codec, widget); - if (ret < 0) + if (ret < 0) { + printk(KERN_ERR + "ASoC: Failed to create DAPM control %s: %d\n", + widget->name, ret); return ret; + } widget++; } return 0; -- cgit v1.2.3 From 40aa4a30d0fd075fb934de4ee8163056827052ab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Dec 2008 10:15:12 +0000 Subject: ASoC: Add WM8350 AudioPlus codec driver The WM8350 is an integrated audio and power management subsystem which provides a single-chip solution for portable audio and multimedia systems. The integrated audio CODEC provides all the necessary functions for high-quality stereo recording and playback. Programmable on-chip amplifiers allow for the direct connection of headphones and microphones with a minimum of external components. A programmable low-noise bias voltage is available to feed one or more electret microphones. Additional audio features include programmable high-pass filter in the ADC input path. This driver was originally written by Liam Girdwood with further updates from me. Signed-off-by: Mark Brown --- include/linux/mfd/wm8350/audio.h | 38 +- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8350.c | 1583 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8350.h | 20 + 5 files changed, 1643 insertions(+), 4 deletions(-) create mode 100644 sound/soc/codecs/wm8350.c create mode 100644 sound/soc/codecs/wm8350.h diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h index 217bb22ebb8..af95a1d2f3a 100644 --- a/include/linux/mfd/wm8350/audio.h +++ b/include/linux/mfd/wm8350/audio.h @@ -1,7 +1,7 @@ /* * audio.h -- Audio Driver for Wolfson WM8350 PMIC * - * Copyright 2007 Wolfson Microelectronics PLC + * Copyright 2007, 2008 Wolfson Microelectronics PLC * * 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 @@ -70,9 +70,9 @@ #define WM8350_CODEC_ISEL_0_5 3 /* x0.5 */ #define WM8350_VMID_OFF 0 -#define WM8350_VMID_500K 1 -#define WM8350_VMID_100K 2 -#define WM8350_VMID_10K 3 +#define WM8350_VMID_300K 1 +#define WM8350_VMID_50K 2 +#define WM8350_VMID_5K 3 /* * R40 (0x28) - Clock Control 1 @@ -591,8 +591,38 @@ #define WM8350_IRQ_CODEC_MICSCD 41 #define WM8350_IRQ_CODEC_MICD 42 +/* + * WM8350 Platform data. + * + * This must be initialised per platform for best audio performance. + * Please see WM8350 datasheet for information. + */ +struct wm8350_audio_platform_data { + int vmid_discharge_msecs; /* VMID --> OFF discharge time */ + int drain_msecs; /* OFF drain time */ + int cap_discharge_msecs; /* Cap ON (from OFF) discharge time */ + int vmid_charge_msecs; /* vmid power up time */ + u32 vmid_s_curve:2; /* vmid enable s curve speed */ + u32 dis_out4:2; /* out4 discharge speed */ + u32 dis_out3:2; /* out3 discharge speed */ + u32 dis_out2:2; /* out2 discharge speed */ + u32 dis_out1:2; /* out1 discharge speed */ + u32 vroi_out4:1; /* out4 tie off */ + u32 vroi_out3:1; /* out3 tie off */ + u32 vroi_out2:1; /* out2 tie off */ + u32 vroi_out1:1; /* out1 tie off */ + u32 vroi_enable:1; /* enable tie off */ + u32 codec_current_on:2; /* current level ON */ + u32 codec_current_standby:2; /* current level STANDBY */ + u32 codec_current_charge:2; /* codec current @ vmid charge */ +}; + +struct snd_soc_codec; + struct wm8350_codec { struct platform_device *pdev; + struct snd_soc_codec *codec; + struct wm8350_audio_platform_data *platform_data; }; #endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bf68052d692..c41289b5f58 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -13,6 +13,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C + select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8510 if (I2C || SPI_MASTER) select SND_SOC_WM8580 if I2C select SND_SOC_WM8728 if (I2C || SPI_MASTER) @@ -100,6 +101,9 @@ config SND_SOC_UDA134X config SND_SOC_UDA1380 tristate +config SND_SOC_WM8350 + tristate + config SND_SOC_WM8510 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9a20fddd09c..c4ddc9aa2bb 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -12,6 +12,7 @@ snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-twl4030-objs := twl4030.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o +snd-soc-wm8350-objs := wm8350.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o snd-soc-wm8728-objs := wm8728.o @@ -39,6 +40,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o +obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c new file mode 100644 index 00000000000..4bbfb5a5894 --- /dev/null +++ b/sound/soc/codecs/wm8350.c @@ -0,0 +1,1583 @@ +/* + * wm8350.c -- WM8350 ALSA SoC audio driver + * + * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC. + * + * Author: Liam Girdwood + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8350.h" + +#define WM8350_OUTn_0dB 0x39 + +#define WM8350_RAMP_NONE 0 +#define WM8350_RAMP_UP 1 +#define WM8350_RAMP_DOWN 2 + +/* We only include the analogue supplies here; the digital supplies + * need to be available well before this driver can be probed. + */ +static const char *supply_names[] = { + "AVDD", + "HPVDD", +}; + +struct wm8350_output { + u16 active; + u16 left_vol; + u16 right_vol; + u16 ramp; + u16 mute; +}; + +struct wm8350_data { + struct snd_soc_codec codec; + struct wm8350_output out1; + struct wm8350_output out2; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; +}; + +static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct wm8350 *wm8350 = codec->control_data; + return wm8350->reg_cache[reg]; +} + +static unsigned int wm8350_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct wm8350 *wm8350 = codec->control_data; + return wm8350_reg_read(wm8350, reg); +} + +static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct wm8350 *wm8350 = codec->control_data; + return wm8350_reg_write(wm8350, reg, value); +} + +/* + * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown. + */ +static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec) +{ + struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_output *out1 = &wm8350_data->out1; + struct wm8350 *wm8350 = codec->control_data; + int left_complete = 0, right_complete = 0; + u16 reg, val; + + /* left channel */ + reg = wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME); + val = (reg & WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; + + if (out1->ramp == WM8350_RAMP_UP) { + /* ramp step up */ + if (val < out1->left_vol) { + val++; + reg &= ~WM8350_OUT1L_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, + reg | (val << WM8350_OUT1L_VOL_SHIFT)); + } else + left_complete = 1; + } else if (out1->ramp == WM8350_RAMP_DOWN) { + /* ramp step down */ + if (val > 0) { + val--; + reg &= ~WM8350_OUT1L_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, + reg | (val << WM8350_OUT1L_VOL_SHIFT)); + } else + left_complete = 1; + } else + return 1; + + /* right channel */ + reg = wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME); + val = (reg & WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; + if (out1->ramp == WM8350_RAMP_UP) { + /* ramp step up */ + if (val < out1->right_vol) { + val++; + reg &= ~WM8350_OUT1R_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, + reg | (val << WM8350_OUT1R_VOL_SHIFT)); + } else + right_complete = 1; + } else if (out1->ramp == WM8350_RAMP_DOWN) { + /* ramp step down */ + if (val > 0) { + val--; + reg &= ~WM8350_OUT1R_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, + reg | (val << WM8350_OUT1R_VOL_SHIFT)); + } else + right_complete = 1; + } + + /* only hit the update bit if either volume has changed this step */ + if (!left_complete || !right_complete) + wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, WM8350_OUT1_VU); + + return left_complete & right_complete; +} + +/* + * Ramp OUT2 PGA volume to minimise pops at stream startup and shutdown. + */ +static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec) +{ + struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_output *out2 = &wm8350_data->out2; + struct wm8350 *wm8350 = codec->control_data; + int left_complete = 0, right_complete = 0; + u16 reg, val; + + /* left channel */ + reg = wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME); + val = (reg & WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; + if (out2->ramp == WM8350_RAMP_UP) { + /* ramp step up */ + if (val < out2->left_vol) { + val++; + reg &= ~WM8350_OUT2L_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, + reg | (val << WM8350_OUT1L_VOL_SHIFT)); + } else + left_complete = 1; + } else if (out2->ramp == WM8350_RAMP_DOWN) { + /* ramp step down */ + if (val > 0) { + val--; + reg &= ~WM8350_OUT2L_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, + reg | (val << WM8350_OUT1L_VOL_SHIFT)); + } else + left_complete = 1; + } else + return 1; + + /* right channel */ + reg = wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME); + val = (reg & WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; + if (out2->ramp == WM8350_RAMP_UP) { + /* ramp step up */ + if (val < out2->right_vol) { + val++; + reg &= ~WM8350_OUT2R_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, + reg | (val << WM8350_OUT1R_VOL_SHIFT)); + } else + right_complete = 1; + } else if (out2->ramp == WM8350_RAMP_DOWN) { + /* ramp step down */ + if (val > 0) { + val--; + reg &= ~WM8350_OUT2R_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, + reg | (val << WM8350_OUT1R_VOL_SHIFT)); + } else + right_complete = 1; + } + + /* only hit the update bit if either volume has changed this step */ + if (!left_complete || !right_complete) + wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, WM8350_OUT2_VU); + + return left_complete & right_complete; +} + +/* + * This work ramps both output PGAs at stream start/stop time to + * minimise pop associated with DAPM power switching. + * It's best to enable Zero Cross when ramping occurs to minimise any + * zipper noises. + */ +static void wm8350_pga_work(struct work_struct *work) +{ + struct snd_soc_codec *codec = + container_of(work, struct snd_soc_codec, delayed_work.work); + struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_output *out1 = &wm8350_data->out1, + *out2 = &wm8350_data->out2; + int i, out1_complete, out2_complete; + + /* do we need to ramp at all ? */ + if (out1->ramp == WM8350_RAMP_NONE && out2->ramp == WM8350_RAMP_NONE) + return; + + /* PGA volumes have 6 bits of resolution to ramp */ + for (i = 0; i <= 63; i++) { + out1_complete = 1, out2_complete = 1; + if (out1->ramp != WM8350_RAMP_NONE) + out1_complete = wm8350_out1_ramp_step(codec); + if (out2->ramp != WM8350_RAMP_NONE) + out2_complete = wm8350_out2_ramp_step(codec); + + /* ramp finished ? */ + if (out1_complete && out2_complete) + break; + + /* we need to delay longer on the up ramp */ + if (out1->ramp == WM8350_RAMP_UP || + out2->ramp == WM8350_RAMP_UP) { + /* delay is longer over 0dB as increases are larger */ + if (i >= WM8350_OUTn_0dB) + schedule_timeout_interruptible(msecs_to_jiffies + (2)); + else + schedule_timeout_interruptible(msecs_to_jiffies + (1)); + } else + udelay(50); /* doesn't matter if we delay longer */ + } + + out1->ramp = WM8350_RAMP_NONE; + out2->ramp = WM8350_RAMP_NONE; +} + +/* + * WM8350 Controls + */ + +static int pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_output *out; + + switch (w->shift) { + case 0: + case 1: + out = &wm8350_data->out1; + break; + case 2: + case 3: + out = &wm8350_data->out2; + break; + + default: + BUG(); + return -1; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + out->ramp = WM8350_RAMP_UP; + out->active = 1; + + if (!delayed_work_pending(&codec->delayed_work)) + schedule_delayed_work(&codec->delayed_work, + msecs_to_jiffies(1)); + break; + + case SND_SOC_DAPM_PRE_PMD: + out->ramp = WM8350_RAMP_DOWN; + out->active = 0; + + if (!delayed_work_pending(&codec->delayed_work)) + schedule_delayed_work(&codec->delayed_work, + msecs_to_jiffies(1)); + break; + } + + return 0; +} + +static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8350_data *wm8350_priv = codec->private_data; + struct wm8350_output *out = NULL; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int ret; + unsigned int reg = mc->reg; + u16 val; + + /* For OUT1 and OUT2 we shadow the values and only actually write + * them out when active in order to ensure the amplifier comes on + * as quietly as possible. */ + switch (reg) { + case WM8350_LOUT1_VOLUME: + out = &wm8350_priv->out1; + break; + case WM8350_LOUT2_VOLUME: + out = &wm8350_priv->out2; + break; + default: + break; + } + + if (out) { + out->left_vol = ucontrol->value.integer.value[0]; + out->right_vol = ucontrol->value.integer.value[1]; + if (!out->active) + return 1; + } + + ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); + if (ret < 0) + return ret; + + /* now hit the volume update bits (always bit 8) */ + val = wm8350_codec_read(codec, reg); + wm8350_codec_write(codec, reg, val | WM8350_OUT1_VU); + return 1; +} + +static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8350_data *wm8350_priv = codec->private_data; + struct wm8350_output *out1 = &wm8350_priv->out1; + struct wm8350_output *out2 = &wm8350_priv->out2; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + + /* If these are cached registers use the cache */ + switch (reg) { + case WM8350_LOUT1_VOLUME: + ucontrol->value.integer.value[0] = out1->left_vol; + ucontrol->value.integer.value[1] = out1->right_vol; + return 0; + + case WM8350_LOUT2_VOLUME: + ucontrol->value.integer.value[0] = out2->left_vol; + ucontrol->value.integer.value[1] = out2->right_vol; + return 0; + + default: + break; + } + + return snd_soc_get_volsw_2r(kcontrol, ucontrol); +} + +/* double control with volume update */ +#define SOC_WM8350_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, \ + xinvert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_2r, \ + .get = wm8350_get_volsw_2r, .put = wm8350_put_volsw_2r_vu, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ + .rshift = xshift, .max = xmax, .invert = xinvert}, } + +static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; +static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" }; +static const char *wm8350_dacmutem[] = { "Normal", "Soft" }; +static const char *wm8350_dacmutes[] = { "Fast", "Slow" }; +static const char *wm8350_dacfilter[] = { "Normal", "Sloping" }; +static const char *wm8350_adcfilter[] = { "None", "High Pass" }; +static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" }; +static const char *wm8350_lr[] = { "Left", "Right" }; + +static const struct soc_enum wm8350_enum[] = { + SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 4, 4, wm8350_deemp), + SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol), + SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem), + SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes), + SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 12, 2, wm8350_dacfilter), + SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter), + SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp), + SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol), + SOC_ENUM_SINGLE(WM8350_INPUT_MIXER_VOLUME, 15, 2, wm8350_lr), +}; + +static DECLARE_TLV_DB_LINEAR(pre_amp_tlv, -1200, 3525); +static DECLARE_TLV_DB_LINEAR(out_pga_tlv, -5700, 600); +static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1); +static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1); +static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1); + +static const unsigned int capture_sd_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 12, TLV_DB_SCALE_ITEM(-3600, 300, 1), + 13, 15, TLV_DB_SCALE_ITEM(0, 0, 0), +}; + +static const struct snd_kcontrol_new wm8350_snd_controls[] = { + SOC_ENUM("Playback Deemphasis", wm8350_enum[0]), + SOC_ENUM("Playback DAC Inversion", wm8350_enum[1]), + SOC_WM8350_DOUBLE_R_TLV("Playback PCM Volume", + WM8350_DAC_DIGITAL_VOLUME_L, + WM8350_DAC_DIGITAL_VOLUME_R, + 0, 255, 0, dac_pcm_tlv), + SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]), + SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]), + SOC_ENUM("Playback PCM Filter", wm8350_enum[4]), + SOC_ENUM("Capture PCM Filter", wm8350_enum[5]), + SOC_ENUM("Capture PCM HP Filter", wm8350_enum[6]), + SOC_ENUM("Capture ADC Inversion", wm8350_enum[7]), + SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume", + WM8350_ADC_DIGITAL_VOLUME_L, + WM8350_ADC_DIGITAL_VOLUME_R, + 0, 255, 0, adc_pcm_tlv), + SOC_DOUBLE_TLV("Capture Sidetone Volume", + WM8350_ADC_DIVIDER, + 8, 4, 15, 1, capture_sd_tlv), + SOC_WM8350_DOUBLE_R_TLV("Capture Volume", + WM8350_LEFT_INPUT_VOLUME, + WM8350_RIGHT_INPUT_VOLUME, + 2, 63, 0, pre_amp_tlv), + SOC_DOUBLE_R("Capture ZC Switch", + WM8350_LEFT_INPUT_VOLUME, + WM8350_RIGHT_INPUT_VOLUME, 13, 1, 0), + SOC_SINGLE_TLV("Left Input Left Sidetone Volume", + WM8350_OUTPUT_LEFT_MIXER_VOLUME, 1, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Left Input Right Sidetone Volume", + WM8350_OUTPUT_LEFT_MIXER_VOLUME, + 5, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Left Input Bypass Volume", + WM8350_OUTPUT_LEFT_MIXER_VOLUME, + 9, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Right Input Left Sidetone Volume", + WM8350_OUTPUT_RIGHT_MIXER_VOLUME, + 1, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Right Input Right Sidetone Volume", + WM8350_OUTPUT_RIGHT_MIXER_VOLUME, + 5, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Right Input Bypass Volume", + WM8350_OUTPUT_RIGHT_MIXER_VOLUME, + 13, 7, 0, out_mix_tlv), + SOC_SINGLE("Left Input Mixer +20dB Switch", + WM8350_INPUT_MIXER_VOLUME_L, 0, 1, 0), + SOC_SINGLE("Right Input Mixer +20dB Switch", + WM8350_INPUT_MIXER_VOLUME_R, 0, 1, 0), + SOC_SINGLE_TLV("Out4 Capture Volume", + WM8350_INPUT_MIXER_VOLUME, + 1, 7, 0, out_mix_tlv), + SOC_WM8350_DOUBLE_R_TLV("Out1 Playback Volume", + WM8350_LOUT1_VOLUME, + WM8350_ROUT1_VOLUME, + 2, 63, 0, out_pga_tlv), + SOC_DOUBLE_R("Out1 Playback ZC Switch", + WM8350_LOUT1_VOLUME, + WM8350_ROUT1_VOLUME, 13, 1, 0), + SOC_WM8350_DOUBLE_R_TLV("Out2 Playback Volume", + WM8350_LOUT2_VOLUME, + WM8350_ROUT2_VOLUME, + 2, 63, 0, out_pga_tlv), + SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8350_LOUT2_VOLUME, + WM8350_ROUT2_VOLUME, 13, 1, 0), + SOC_SINGLE("Out2 Right Invert Switch", WM8350_ROUT2_VOLUME, 10, 1, 0), + SOC_SINGLE_TLV("Out2 Beep Volume", WM8350_BEEP_VOLUME, + 5, 7, 0, out_mix_tlv), + + SOC_DOUBLE_R("Out1 Playback Switch", + WM8350_LOUT1_VOLUME, + WM8350_ROUT1_VOLUME, + 14, 1, 1), + SOC_DOUBLE_R("Out2 Playback Switch", + WM8350_LOUT2_VOLUME, + WM8350_ROUT2_VOLUME, + 14, 1, 1), +}; + +/* + * DAPM Controls + */ + +/* Left Playback Mixer */ +static const struct snd_kcontrol_new wm8350_left_play_mixer_controls[] = { + SOC_DAPM_SINGLE("Playback Switch", + WM8350_LEFT_MIXER_CONTROL, 11, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", + WM8350_LEFT_MIXER_CONTROL, 2, 1, 0), + SOC_DAPM_SINGLE("Right Playback Switch", + WM8350_LEFT_MIXER_CONTROL, 12, 1, 0), + SOC_DAPM_SINGLE("Left Sidetone Switch", + WM8350_LEFT_MIXER_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("Right Sidetone Switch", + WM8350_LEFT_MIXER_CONTROL, 1, 1, 0), +}; + +/* Right Playback Mixer */ +static const struct snd_kcontrol_new wm8350_right_play_mixer_controls[] = { + SOC_DAPM_SINGLE("Playback Switch", + WM8350_RIGHT_MIXER_CONTROL, 12, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", + WM8350_RIGHT_MIXER_CONTROL, 3, 1, 0), + SOC_DAPM_SINGLE("Left Playback Switch", + WM8350_RIGHT_MIXER_CONTROL, 11, 1, 0), + SOC_DAPM_SINGLE("Left Sidetone Switch", + WM8350_RIGHT_MIXER_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("Right Sidetone Switch", + WM8350_RIGHT_MIXER_CONTROL, 1, 1, 0), +}; + +/* Out4 Mixer */ +static const struct snd_kcontrol_new wm8350_out4_mixer_controls[] = { + SOC_DAPM_SINGLE("Right Playback Switch", + WM8350_OUT4_MIXER_CONTROL, 12, 1, 0), + SOC_DAPM_SINGLE("Left Playback Switch", + WM8350_OUT4_MIXER_CONTROL, 11, 1, 0), + SOC_DAPM_SINGLE("Right Capture Switch", + WM8350_OUT4_MIXER_CONTROL, 9, 1, 0), + SOC_DAPM_SINGLE("Out3 Playback Switch", + WM8350_OUT4_MIXER_CONTROL, 2, 1, 0), + SOC_DAPM_SINGLE("Right Mixer Switch", + WM8350_OUT4_MIXER_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("Left Mixer Switch", + WM8350_OUT4_MIXER_CONTROL, 0, 1, 0), +}; + +/* Out3 Mixer */ +static const struct snd_kcontrol_new wm8350_out3_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", + WM8350_OUT3_MIXER_CONTROL, 11, 1, 0), + SOC_DAPM_SINGLE("Left Capture Switch", + WM8350_OUT3_MIXER_CONTROL, 8, 1, 0), + SOC_DAPM_SINGLE("Out4 Playback Switch", + WM8350_OUT3_MIXER_CONTROL, 3, 1, 0), + SOC_DAPM_SINGLE("Left Mixer Switch", + WM8350_OUT3_MIXER_CONTROL, 0, 1, 0), +}; + +/* Left Input Mixer */ +static const struct snd_kcontrol_new wm8350_left_capt_mixer_controls[] = { + SOC_DAPM_SINGLE_TLV("L2 Capture Volume", + WM8350_INPUT_MIXER_VOLUME_L, 1, 7, 0, out_mix_tlv), + SOC_DAPM_SINGLE_TLV("L3 Capture Volume", + WM8350_INPUT_MIXER_VOLUME_L, 9, 7, 0, out_mix_tlv), + SOC_DAPM_SINGLE("PGA Capture Switch", + WM8350_LEFT_INPUT_VOLUME, 14, 1, 0), +}; + +/* Right Input Mixer */ +static const struct snd_kcontrol_new wm8350_right_capt_mixer_controls[] = { + SOC_DAPM_SINGLE_TLV("L2 Capture Volume", + WM8350_INPUT_MIXER_VOLUME_R, 5, 7, 0, out_mix_tlv), + SOC_DAPM_SINGLE_TLV("L3 Capture Volume", + WM8350_INPUT_MIXER_VOLUME_R, 13, 7, 0, out_mix_tlv), + SOC_DAPM_SINGLE("PGA Capture Switch", + WM8350_RIGHT_INPUT_VOLUME, 14, 1, 0), +}; + +/* Left Mic Mixer */ +static const struct snd_kcontrol_new wm8350_left_mic_mixer_controls[] = { + SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 2, 1, 0), +}; + +/* Right Mic Mixer */ +static const struct snd_kcontrol_new wm8350_right_mic_mixer_controls[] = { + SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 9, 1, 0), + SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 8, 1, 0), + SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 10, 1, 0), +}; + +/* Beep Switch */ +static const struct snd_kcontrol_new wm8350_beep_switch_controls = +SOC_DAPM_SINGLE("Switch", WM8350_BEEP_VOLUME, 15, 1, 1); + +/* Out4 Capture Mux */ +static const struct snd_kcontrol_new wm8350_out4_capture_controls = +SOC_DAPM_ENUM("Route", wm8350_enum[8]); + +static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = { + + SND_SOC_DAPM_PGA("IN3R PGA", WM8350_POWER_MGMT_2, 11, 0, NULL, 0), + SND_SOC_DAPM_PGA("IN3L PGA", WM8350_POWER_MGMT_2, 10, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("Right Out2 PGA", WM8350_POWER_MGMT_3, 3, 0, NULL, + 0, pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Left Out2 PGA", WM8350_POWER_MGMT_3, 2, 0, NULL, 0, + pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Right Out1 PGA", WM8350_POWER_MGMT_3, 1, 0, NULL, + 0, pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Left Out1 PGA", WM8350_POWER_MGMT_3, 0, 0, NULL, 0, + pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MIXER("Right Capture Mixer", WM8350_POWER_MGMT_2, + 7, 0, &wm8350_right_capt_mixer_controls[0], + ARRAY_SIZE(wm8350_right_capt_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left Capture Mixer", WM8350_POWER_MGMT_2, + 6, 0, &wm8350_left_capt_mixer_controls[0], + ARRAY_SIZE(wm8350_left_capt_mixer_controls)), + + SND_SOC_DAPM_MIXER("Out4 Mixer", WM8350_POWER_MGMT_2, 5, 0, + &wm8350_out4_mixer_controls[0], + ARRAY_SIZE(wm8350_out4_mixer_controls)), + + SND_SOC_DAPM_MIXER("Out3 Mixer", WM8350_POWER_MGMT_2, 4, 0, + &wm8350_out3_mixer_controls[0], + ARRAY_SIZE(wm8350_out3_mixer_controls)), + + SND_SOC_DAPM_MIXER("Right Playback Mixer", WM8350_POWER_MGMT_2, 1, 0, + &wm8350_right_play_mixer_controls[0], + ARRAY_SIZE(wm8350_right_play_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left Playback Mixer", WM8350_POWER_MGMT_2, 0, 0, + &wm8350_left_play_mixer_controls[0], + ARRAY_SIZE(wm8350_left_play_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left Mic Mixer", WM8350_POWER_MGMT_2, 8, 0, + &wm8350_left_mic_mixer_controls[0], + ARRAY_SIZE(wm8350_left_mic_mixer_controls)), + + SND_SOC_DAPM_MIXER("Right Mic Mixer", WM8350_POWER_MGMT_2, 9, 0, + &wm8350_right_mic_mixer_controls[0], + ARRAY_SIZE(wm8350_right_mic_mixer_controls)), + + /* virtual mixer for Beep and Out2R */ + SND_SOC_DAPM_MIXER("Out2 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Beep", WM8350_POWER_MGMT_3, 7, 0, + &wm8350_beep_switch_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", + WM8350_POWER_MGMT_4, 3, 0), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", + WM8350_POWER_MGMT_4, 2, 0), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", + WM8350_POWER_MGMT_4, 5, 0), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", + WM8350_POWER_MGMT_4, 4, 0), + + SND_SOC_DAPM_MICBIAS("Mic Bias", WM8350_POWER_MGMT_1, 4, 0), + + SND_SOC_DAPM_MUX("Out4 Capture Channel", SND_SOC_NOPM, 0, 0, + &wm8350_out4_capture_controls), + + SND_SOC_DAPM_OUTPUT("OUT1R"), + SND_SOC_DAPM_OUTPUT("OUT1L"), + SND_SOC_DAPM_OUTPUT("OUT2R"), + SND_SOC_DAPM_OUTPUT("OUT2L"), + SND_SOC_DAPM_OUTPUT("OUT3"), + SND_SOC_DAPM_OUTPUT("OUT4"), + + SND_SOC_DAPM_INPUT("IN1RN"), + SND_SOC_DAPM_INPUT("IN1RP"), + SND_SOC_DAPM_INPUT("IN2R"), + SND_SOC_DAPM_INPUT("IN1LP"), + SND_SOC_DAPM_INPUT("IN1LN"), + SND_SOC_DAPM_INPUT("IN2L"), + SND_SOC_DAPM_INPUT("IN3R"), + SND_SOC_DAPM_INPUT("IN3L"), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + + /* left playback mixer */ + {"Left Playback Mixer", "Playback Switch", "Left DAC"}, + {"Left Playback Mixer", "Left Bypass Switch", "IN3L PGA"}, + {"Left Playback Mixer", "Right Playback Switch", "Right DAC"}, + {"Left Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"}, + {"Left Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"}, + + /* right playback mixer */ + {"Right Playback Mixer", "Playback Switch", "Right DAC"}, + {"Right Playback Mixer", "Right Bypass Switch", "IN3R PGA"}, + {"Right Playback Mixer", "Left Playback Switch", "Left DAC"}, + {"Right Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"}, + {"Right Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"}, + + /* out4 playback mixer */ + {"Out4 Mixer", "Right Playback Switch", "Right DAC"}, + {"Out4 Mixer", "Left Playback Switch", "Left DAC"}, + {"Out4 Mixer", "Right Capture Switch", "Right Capture Mixer"}, + {"Out4 Mixer", "Out3 Playback Switch", "Out3 Mixer"}, + {"Out4 Mixer", "Right Mixer Switch", "Right Playback Mixer"}, + {"Out4 Mixer", "Left Mixer Switch", "Left Playback Mixer"}, + {"OUT4", NULL, "Out4 Mixer"}, + + /* out3 playback mixer */ + {"Out3 Mixer", "Left Playback Switch", "Left DAC"}, + {"Out3 Mixer", "Left Capture Switch", "Left Capture Mixer"}, + {"Out3 Mixer", "Left Mixer Switch", "Left Playback Mixer"}, + {"Out3 Mixer", "Out4 Playback Switch", "Out4 Mixer"}, + {"OUT3", NULL, "Out3 Mixer"}, + + /* out2 */ + {"Right Out2 PGA", NULL, "Right Playback Mixer"}, + {"Left Out2 PGA", NULL, "Left Playback Mixer"}, + {"OUT2L", NULL, "Left Out2 PGA"}, + {"OUT2R", NULL, "Right Out2 PGA"}, + + /* out1 */ + {"Right Out1 PGA", NULL, "Right Playback Mixer"}, + {"Left Out1 PGA", NULL, "Left Playback Mixer"}, + {"OUT1L", NULL, "Left Out1 PGA"}, + {"OUT1R", NULL, "Right Out1 PGA"}, + + /* ADCs */ + {"Left ADC", NULL, "Left Capture Mixer"}, + {"Right ADC", NULL, "Right Capture Mixer"}, + + /* Left capture mixer */ + {"Left Capture Mixer", "L2 Capture Volume", "IN2L"}, + {"Left Capture Mixer", "L3 Capture Volume", "IN3L PGA"}, + {"Left Capture Mixer", "PGA Capture Switch", "Left Mic Mixer"}, + {"Left Capture Mixer", NULL, "Out4 Capture Channel"}, + + /* Right capture mixer */ + {"Right Capture Mixer", "L2 Capture Volume", "IN2R"}, + {"Right Capture Mixer", "L3 Capture Volume", "IN3R PGA"}, + {"Right Capture Mixer", "PGA Capture Switch", "Right Mic Mixer"}, + {"Right Capture Mixer", NULL, "Out4 Capture Channel"}, + + /* L3 Inputs */ + {"IN3L PGA", NULL, "IN3L"}, + {"IN3R PGA", NULL, "IN3R"}, + + /* Left Mic mixer */ + {"Left Mic Mixer", "INN Capture Switch", "IN1LN"}, + {"Left Mic Mixer", "INP Capture Switch", "IN1LP"}, + {"Left Mic Mixer", "IN2 Capture Switch", "IN2L"}, + + /* Right Mic mixer */ + {"Right Mic Mixer", "INN Capture Switch", "IN1RN"}, + {"Right Mic Mixer", "INP Capture Switch", "IN1RP"}, + {"Right Mic Mixer", "IN2 Capture Switch", "IN2R"}, + + /* out 4 capture */ + {"Out4 Capture Channel", NULL, "Out4 Mixer"}, + + /* Beep */ + {"Beep", NULL, "IN3R PGA"}, +}; + +static int wm8350_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8350_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8350_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +static int wm8350_add_widgets(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, + wm8350_dapm_widgets, + ARRAY_SIZE(wm8350_dapm_widgets)); + if (ret != 0) { + dev_err(codec->dev, "dapm control register failed\n"); + return ret; + } + + /* set up audio paths */ + ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + if (ret != 0) { + dev_err(codec->dev, "DAPM route register failed\n"); + return ret; + } + + return snd_soc_dapm_new_widgets(codec); +} + +static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8350 *wm8350 = codec->control_data; + u16 fll_4; + + switch (clk_id) { + case WM8350_MCLK_SEL_MCLK: + wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_1, + WM8350_MCLK_SEL); + break; + case WM8350_MCLK_SEL_PLL_MCLK: + case WM8350_MCLK_SEL_PLL_DAC: + case WM8350_MCLK_SEL_PLL_ADC: + case WM8350_MCLK_SEL_PLL_32K: + wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1, + WM8350_MCLK_SEL); + fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & + ~WM8350_FLL_CLK_SRC_MASK; + wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id); + break; + } + + /* MCLK direction */ + if (dir == WM8350_MCLK_DIR_OUT) + wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2, + WM8350_MCLK_DIR); + else + wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2, + WM8350_MCLK_DIR); + + return 0; +} + +static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 val; + + switch (div_id) { + case WM8350_ADC_CLKDIV: + val = wm8350_codec_read(codec, WM8350_ADC_DIVIDER) & + ~WM8350_ADC_CLKDIV_MASK; + wm8350_codec_write(codec, WM8350_ADC_DIVIDER, val | div); + break; + case WM8350_DAC_CLKDIV: + val = wm8350_codec_read(codec, WM8350_DAC_CLOCK_CONTROL) & + ~WM8350_DAC_CLKDIV_MASK; + wm8350_codec_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div); + break; + case WM8350_BCLK_CLKDIV: + val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) & + ~WM8350_BCLK_DIV_MASK; + wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div); + break; + case WM8350_OPCLK_CLKDIV: + val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) & + ~WM8350_OPCLK_DIV_MASK; + wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div); + break; + case WM8350_SYS_CLKDIV: + val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) & + ~WM8350_MCLK_DIV_MASK; + wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div); + break; + case WM8350_DACLR_CLKDIV: + val = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) & + ~WM8350_DACLRC_RATE_MASK; + wm8350_codec_write(codec, WM8350_DAC_LR_RATE, val | div); + break; + case WM8350_ADCLR_CLKDIV: + val = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) & + ~WM8350_ADCLRC_RATE_MASK; + wm8350_codec_write(codec, WM8350_ADC_LR_RATE, val | div); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) & + ~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK); + u16 master = wm8350_codec_read(codec, WM8350_AI_DAC_CONTROL) & + ~WM8350_BCLK_MSTR; + u16 dac_lrc = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) & + ~WM8350_DACLRC_ENA; + u16 adc_lrc = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) & + ~WM8350_ADCLRC_ENA; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + master |= WM8350_BCLK_MSTR; + dac_lrc |= WM8350_DACLRC_ENA; + adc_lrc |= WM8350_ADCLRC_ENA; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x2 << 8; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x1 << 8; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x3 << 8; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x3 << 8; /* lg not sure which mode */ + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= WM8350_AIF_LRCLK_INV | WM8350_AIF_BCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= WM8350_AIF_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= WM8350_AIF_LRCLK_INV; + break; + default: + return -EINVAL; + } + + wm8350_codec_write(codec, WM8350_AI_FORMATING, iface); + wm8350_codec_write(codec, WM8350_AI_DAC_CONTROL, master); + wm8350_codec_write(codec, WM8350_DAC_LR_RATE, dac_lrc); + wm8350_codec_write(codec, WM8350_ADC_LR_RATE, adc_lrc); + return 0; +} + +static int wm8350_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int master = wm8350_codec_cache_read(codec, WM8350_AI_DAC_CONTROL) & + WM8350_BCLK_MSTR; + int enabled = 0; + + /* Check that the DACs or ADCs are enabled since they are + * required for LRC in master mode. The DACs or ADCs need a + * valid audio path i.e. pin -> ADC or DAC -> pin before + * the LRC will be enabled in master mode. */ + if (!master && cmd != SNDRV_PCM_TRIGGER_START) + return 0; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) & + (WM8350_ADCR_ENA | WM8350_ADCL_ENA); + } else { + enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) & + (WM8350_DACR_ENA | WM8350_DACL_ENA); + } + + if (!enabled) { + dev_err(codec->dev, + "%s: invalid audio path - no clocks available\n", + __func__); + return -EINVAL; + } + return 0; +} + +static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) & + ~WM8350_AIF_WL_MASK; + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x1 << 10; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x2 << 10; + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x3 << 10; + break; + } + + wm8350_codec_write(codec, WM8350_AI_FORMATING, iface); + return 0; +} + +static int wm8350_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8350 *wm8350 = codec->control_data; + + if (mute) + wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA); + else + wm8350_clear_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA); + return 0; +} + +/* FLL divisors */ +struct _fll_div { + int div; /* FLL_OUTDIV */ + int n; + int k; + int ratio; /* FLL_FRATIO */ +}; + +/* The size in bits of the fll divide multiplied by 10 + * to allow rounding later */ +#define FIXED_FLL_SIZE ((1 << 16) * 10) + +static inline int fll_factors(struct _fll_div *fll_div, unsigned int input, + unsigned int output) +{ + u64 Kpart; + unsigned int t1, t2, K, Nmod; + + if (output >= 2815250 && output <= 3125000) + fll_div->div = 0x4; + else if (output >= 5625000 && output <= 6250000) + fll_div->div = 0x3; + else if (output >= 11250000 && output <= 12500000) + fll_div->div = 0x2; + else if (output >= 22500000 && output <= 25000000) + fll_div->div = 0x1; + else { + printk(KERN_ERR "wm8350: fll freq %d out of range\n", output); + return -EINVAL; + } + + if (input > 48000) + fll_div->ratio = 1; + else + fll_div->ratio = 8; + + t1 = output * (1 << (fll_div->div + 1)); + t2 = input * fll_div->ratio; + + fll_div->n = t1 / t2; + Nmod = t1 % t2; + + if (Nmod) { + Kpart = FIXED_FLL_SIZE * (long long)Nmod; + do_div(Kpart, t2); + K = Kpart & 0xFFFFFFFF; + + /* Check if we need to round */ + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + K /= 10; + fll_div->k = K; + } else + fll_div->k = 0; + + return 0; +} + +static int wm8350_set_fll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, + unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8350 *wm8350 = codec->control_data; + struct _fll_div fll_div; + int ret = 0; + u16 fll_1, fll_4; + + /* power down FLL - we need to do this for reconfiguration */ + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, + WM8350_FLL_ENA | WM8350_FLL_OSC_ENA); + + if (freq_out == 0 || freq_in == 0) + return ret; + + ret = fll_factors(&fll_div, freq_in, freq_out); + if (ret < 0) + return ret; + dev_dbg(wm8350->dev, + "FLL in %d FLL out %d N 0x%x K 0x%x div %d ratio %d", + freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div, + fll_div.ratio); + + /* set up N.K & dividers */ + fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) & + ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000); + wm8350_codec_write(codec, WM8350_FLL_CONTROL_1, + fll_1 | (fll_div.div << 8) | 0x50); + wm8350_codec_write(codec, WM8350_FLL_CONTROL_2, + (fll_div.ratio << 11) | (fll_div. + n & WM8350_FLL_N_MASK)); + wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k); + fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & + ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF); + wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, + fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) | + (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0)); + + /* power FLL on */ + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA); + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA); + + return 0; +} + +static int wm8350_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm8350 *wm8350 = codec->control_data; + struct wm8350_data *priv = codec->private_data; + struct wm8350_audio_platform_data *platform = + wm8350->codec.platform_data; + u16 pm1; + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1 | WM8350_VMID_50K | + platform->codec_current_on << 14); + break; + + case SND_SOC_BIAS_PREPARE: + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1); + pm1 &= ~WM8350_VMID_MASK; + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1 | WM8350_VMID_50K); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret != 0) + return ret; + + /* Enable the system clock */ + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, + WM8350_SYSCLK_ENA); + + /* mute DAC & outputs */ + wm8350_set_bits(wm8350, WM8350_DAC_MUTE, + WM8350_DAC_MUTE_ENA); + + /* discharge cap memory */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, + platform->dis_out1 | + (platform->dis_out2 << 2) | + (platform->dis_out3 << 4) | + (platform->dis_out4 << 6)); + + /* wait for discharge */ + schedule_timeout_interruptible(msecs_to_jiffies + (platform-> + cap_discharge_msecs)); + + /* enable antipop */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, + (platform->vmid_s_curve << 8)); + + /* ramp up vmid */ + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + (platform-> + codec_current_charge << 14) | + WM8350_VMID_5K | WM8350_VMIDEN | + WM8350_VBUFEN); + + /* wait for vmid */ + schedule_timeout_interruptible(msecs_to_jiffies + (platform-> + vmid_charge_msecs)); + + /* turn on vmid 300k */ + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK); + pm1 |= WM8350_VMID_300K | + (platform->codec_current_standby << 14); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1); + + + /* enable analogue bias */ + pm1 |= WM8350_BIASEN; + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1); + + /* disable antipop */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0); + + } else { + /* turn on vmid 300k and reduce current */ + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1 | WM8350_VMID_300K | + (platform-> + codec_current_standby << 14)); + + } + break; + + case SND_SOC_BIAS_OFF: + + /* mute DAC & enable outputs */ + wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA); + + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_3, + WM8350_OUT1L_ENA | WM8350_OUT1R_ENA | + WM8350_OUT2L_ENA | WM8350_OUT2R_ENA); + + /* enable anti pop S curve */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, + (platform->vmid_s_curve << 8)); + + /* turn off vmid */ + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~WM8350_VMIDEN; + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1); + + /* wait */ + schedule_timeout_interruptible(msecs_to_jiffies + (platform-> + vmid_discharge_msecs)); + + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, + (platform->vmid_s_curve << 8) | + platform->dis_out1 | + (platform->dis_out2 << 2) | + (platform->dis_out3 << 4) | + (platform->dis_out4 << 6)); + + /* turn off VBuf and drain */ + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~(WM8350_VBUFEN | WM8350_VMID_MASK); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1 | WM8350_OUTPUT_DRAIN_EN); + + /* wait */ + schedule_timeout_interruptible(msecs_to_jiffies + (platform->drain_msecs)); + + pm1 &= ~WM8350_BIASEN; + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1); + + /* disable anti-pop */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0); + + wm8350_clear_bits(wm8350, WM8350_LOUT1_VOLUME, + WM8350_OUT1L_ENA); + wm8350_clear_bits(wm8350, WM8350_ROUT1_VOLUME, + WM8350_OUT1R_ENA); + wm8350_clear_bits(wm8350, WM8350_LOUT2_VOLUME, + WM8350_OUT2L_ENA); + wm8350_clear_bits(wm8350, WM8350_ROUT2_VOLUME, + WM8350_OUT2R_ENA); + + /* disable clock gen */ + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, + WM8350_SYSCLK_ENA); + + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + priv->supplies); + break; + } + codec->bias_level = level; + return 0; +} + +static int wm8350_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int wm8350_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + if (codec->suspend_bias_level == SND_SOC_BIAS_ON) + wm8350_set_bias_level(codec, SND_SOC_BIAS_ON); + + return 0; +} + +static struct snd_soc_codec *wm8350_codec; + +static int wm8350_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct wm8350 *wm8350; + struct wm8350_data *priv; + int ret; + struct wm8350_output *out1; + struct wm8350_output *out2; + + BUG_ON(!wm8350_codec); + + socdev->codec = wm8350_codec; + codec = socdev->codec; + wm8350 = codec->control_data; + priv = codec->private_data; + + /* Enable the codec */ + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); + + /* Enable robust clocking mode in ADC */ + wm8350_codec_write(codec, WM8350_SECURITY, 0xa7); + wm8350_codec_write(codec, 0xde, 0x13); + wm8350_codec_write(codec, WM8350_SECURITY, 0); + + /* read OUT1 & OUT2 volumes */ + out1 = &priv->out1; + out2 = &priv->out2; + out1->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME) & + WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; + out1->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME) & + WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; + out2->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME) & + WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; + out2->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME) & + WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; + wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 0); + wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 0); + wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0); + wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0); + + /* Latch VU bits & mute */ + wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, + WM8350_OUT1_VU | WM8350_OUT1L_MUTE); + wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, + WM8350_OUT2_VU | WM8350_OUT2L_MUTE); + wm8350_set_bits(wm8350, WM8350_ROUT1_VOLUME, + WM8350_OUT1_VU | WM8350_OUT1R_MUTE); + wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, + WM8350_OUT2_VU | WM8350_OUT2R_MUTE); + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to create pcms\n"); + return ret; + } + + wm8350_add_controls(codec); + wm8350_add_widgets(codec); + + wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register card\n"); + goto card_err; + } + + return 0; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + return ret; +} + +static int wm8350_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct wm8350 *wm8350 = codec->control_data; + int ret; + + /* cancel any work waiting to be queued. */ + ret = cancel_delayed_work(&codec->delayed_work); + + /* if there was any work waiting then we run it now and + * wait for its completion */ + if (ret) { + schedule_delayed_work(&codec->delayed_work, 0); + flush_scheduled_work(); + } + + wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); + + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); + + return 0; +} + +#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000) + +#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +struct snd_soc_dai wm8350_dai = { + .name = "WM8350", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8350_RATES, + .formats = WM8350_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8350_RATES, + .formats = WM8350_FORMATS, + }, + .ops = { + .hw_params = wm8350_pcm_hw_params, + .digital_mute = wm8350_mute, + .trigger = wm8350_pcm_trigger, + .set_fmt = wm8350_set_dai_fmt, + .set_sysclk = wm8350_set_dai_sysclk, + .set_pll = wm8350_set_fll, + .set_clkdiv = wm8350_set_clkdiv, + }, +}; +EXPORT_SYMBOL_GPL(wm8350_dai); + +struct snd_soc_codec_device soc_codec_dev_wm8350 = { + .probe = wm8350_probe, + .remove = wm8350_remove, + .suspend = wm8350_suspend, + .resume = wm8350_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350); + +static int wm8350_codec_probe(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = platform_get_drvdata(pdev); + struct wm8350_data *priv; + struct snd_soc_codec *codec; + int ret, i; + + if (wm8350->codec.platform_data == NULL) { + dev_err(&pdev->dev, "No audio platform data supplied\n"); + return -EINVAL; + } + + priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + priv->supplies[i].supply = supply_names[i]; + + ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret != 0) + goto err_priv; + + codec = &priv->codec; + wm8350->codec.codec = codec; + + wm8350_dai.dev = &pdev->dev; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + codec->dev = &pdev->dev; + codec->name = "WM8350"; + codec->owner = THIS_MODULE; + codec->read = wm8350_codec_read; + codec->write = wm8350_codec_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8350_set_bias_level; + codec->dai = &wm8350_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8350_MAX_REGISTER; + codec->private_data = priv; + codec->control_data = wm8350; + + /* Put the codec into reset if it wasn't already */ + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); + + INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work); + ret = snd_soc_register_codec(codec); + if (ret != 0) + goto err_supply; + + wm8350_codec = codec; + + ret = snd_soc_register_dai(&wm8350_dai); + if (ret != 0) + goto err_codec; + return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err_supply: + regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies); +err_priv: + kfree(priv); + wm8350_codec = NULL; + return ret; +} + +static int wm8350_codec_remove(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = wm8350->codec.codec; + struct wm8350_data *priv = codec->private_data; + + snd_soc_unregister_dai(&wm8350_dai); + snd_soc_unregister_codec(codec); + regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies); + kfree(priv); + wm8350_codec = NULL; + return 0; +} + +static struct platform_driver wm8350_codec_driver = { + .driver = { + .name = "wm8350-codec", + .owner = THIS_MODULE, + }, + .probe = wm8350_codec_probe, + .remove = __devexit_p(wm8350_codec_remove), +}; + +static __init int wm8350_init(void) +{ + return platform_driver_register(&wm8350_codec_driver); +} +module_init(wm8350_init); + +static __exit void wm8350_exit(void) +{ + platform_driver_unregister(&wm8350_codec_driver); +} +module_exit(wm8350_exit); + +MODULE_DESCRIPTION("ASoC WM8350 driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8350-codec"); diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h new file mode 100644 index 00000000000..cc2887aa6c3 --- /dev/null +++ b/sound/soc/codecs/wm8350.h @@ -0,0 +1,20 @@ +/* + * wm8350.h - WM8903 audio codec interface + * + * Copyright 2008 Wolfson Microelectronics PLC. + * + * 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. + */ + +#ifndef _WM8350_H +#define _WM8350_H + +#include + +extern struct snd_soc_dai wm8350_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8350; + +#endif -- cgit v1.2.3 From 1152a1959f8440db9536f6df758274443f9b5b37 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 18 Dec 2008 12:36:40 -0700 Subject: ALSA: ASoC: DaVinci: davinvi-evm, make requests explicit Add constants with a value of 0 to show more explicitly what is being requested. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-evm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index d87b91179cc..5c041bf05f3 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -38,12 +38,14 @@ static int evm_hw_params(struct snd_pcm_substream *substream, /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM); + SND_SOC_DAIFMT_CBM_CFM | + SND_SOC_DAIFMT_NB_NF); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF); if (ret < 0) return ret; -- cgit v1.2.3 From 664b4af859d43714fd2a90aa434e454355659d0e Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 18 Dec 2008 12:36:41 -0700 Subject: ALSA: ASoC: DaVinci: davinci-i2s add comments to explain polarity Document the current polarity choices. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 81ff5c37ab5..156e3e95d91 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -235,18 +235,45 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_NF: + /* CLKRP Receive clock polarity, + * 1 - sampled on rising edge of CLKR + * valid on rising edge + * CLKXP Transmit clock polarity, + * 1 - clocked on falling edge of CLKX + * valid on rising edge + * FSRP Receive frame sync pol, 0 - active high + * FSXP Transmit frame sync pol, 0 - active high + */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP, 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); break; case SND_SOC_DAIFMT_NB_IF: + /* CLKRP Receive clock polarity, + * 0 - sampled on falling edge of CLKR + * valid on falling edge + * CLKXP Transmit clock polarity, + * 0 - clocked on rising edge of CLKX + * valid on falling edge + * FSRP Receive frame sync pol, 1 - active low + * FSXP Transmit frame sync pol, 1 - active low + */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP, 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); break; case SND_SOC_DAIFMT_IB_IF: + /* CLKRP Receive clock polarity, + * 1 - sampled on rising edge of CLKR + * valid on rising edge + * CLKXP Transmit clock polarity, + * 1 - clocked on falling edge of CLKX + * valid on rising edge + * FSRP Receive frame sync pol, 1 - active low + * FSXP Transmit frame sync pol, 1 - active low + */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | @@ -255,6 +282,15 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); break; case SND_SOC_DAIFMT_NB_NF: + /* CLKRP Receive clock polarity, + * 0 - sampled on falling edge of CLKR + * valid on falling edge + * CLKXP Transmit clock polarity, + * 0 - clocked on rising edge of CLKX + * valid on falling edge + * FSRP Receive frame sync pol, 0 - active high + * FSXP Transmit frame sync pol, 0 - active high + */ break; default: return -EINVAL; -- cgit v1.2.3 From 21903c1c9ecb7a210eb985aa8d82ad68c78283cc Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 18 Dec 2008 12:36:43 -0700 Subject: ALSA: ASoC: DaVinci: davinci-i2s clean up Just at little cleanup of davinci_i2s_set_dai_fmt Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 85 ++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 48 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 156e3e95d91..028682846f4 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -200,36 +200,41 @@ static int davinci_i2s_startup(struct snd_pcm_substream *substream, return 0; } +#define DEFAULT_BITPERSAMPLE 16 + static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct davinci_mcbsp_dev *dev = cpu_dai->private_data; - u32 w; + unsigned int pcr; + unsigned int srgr; + unsigned int rcr; + unsigned int xcr; + srgr = DAVINCI_MCBSP_SRGR_FSGM | + DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | + DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, - DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM | - DAVINCI_MCBSP_PCR_CLKXM | - DAVINCI_MCBSP_PCR_CLKRM); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, - DAVINCI_MCBSP_SRGR_FSGM); + /* cpu is master */ + pcr = DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM | + DAVINCI_MCBSP_PCR_CLKXM | + DAVINCI_MCBSP_PCR_CLKRM; break; case SND_SOC_DAIFMT_CBM_CFS: /* McBSP CLKR pin is the input for the Sample Rate Generator. * McBSP FSR and FSX are driven by the Sample Rate Generator. */ - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, - DAVINCI_MCBSP_PCR_SCLKME | - DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, - DAVINCI_MCBSP_SRGR_FSGM); + pcr = DAVINCI_MCBSP_PCR_SCLKME | + DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM; break; case SND_SOC_DAIFMT_CBM_CFM: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); + /* codec is master */ + pcr = 0; break; default: + printk(KERN_ERR "%s:bad master\n", __func__); return -EINVAL; } @@ -244,10 +249,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, * FSRP Receive frame sync pol, 0 - active high * FSXP Transmit frame sync pol, 0 - active high */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | - DAVINCI_MCBSP_PCR_CLKRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP); break; case SND_SOC_DAIFMT_NB_IF: /* CLKRP Receive clock polarity, @@ -259,10 +261,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, * FSRP Receive frame sync pol, 1 - active low * FSXP Transmit frame sync pol, 1 - active low */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_FSXP | - DAVINCI_MCBSP_PCR_FSRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; case SND_SOC_DAIFMT_IB_IF: /* CLKRP Receive clock polarity, @@ -274,12 +273,8 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, * FSRP Receive frame sync pol, 1 - active low * FSXP Transmit frame sync pol, 1 - active low */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | - DAVINCI_MCBSP_PCR_CLKRP | - DAVINCI_MCBSP_PCR_FSXP | - DAVINCI_MCBSP_PCR_FSRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | + DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; case SND_SOC_DAIFMT_NB_NF: /* CLKRP Receive clock polarity, @@ -296,28 +291,24 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } + rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); + xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(0)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(0) | - DAVINCI_MCBSP_XCR_XFIG); break; case SND_SOC_DAIFMT_I2S: - default: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(1)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(1) | - DAVINCI_MCBSP_XCR_XFIG); + case SND_SOC_DAIFMT_DSP_B: + rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); + xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); break; + default: + printk(KERN_ERR "%s:bad format\n", __func__); + return -EINVAL; } - + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); return 0; } @@ -343,12 +334,10 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, } i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); + w = DAVINCI_MCBSP_SRGR_FSGM; MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1), 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w); -- cgit v1.2.3 From 69ab820c862250d460dfaaf82164972a4a69418a Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 18 Dec 2008 12:36:44 -0700 Subject: ALSA: ASoC: DaVinci: davinci-i2s clean up Minor, just move a block of code to make next patch clearer. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 028682846f4..24fe9db2c75 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -238,6 +238,21 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } + rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); + xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_DSP_B: + rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); + xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); + break; + default: + printk(KERN_ERR "%s:bad format\n", __func__); + return -EINVAL; + } + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_NF: /* CLKRP Receive clock polarity, @@ -290,21 +305,6 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, default: return -EINVAL; } - - rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); - xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_RIGHT_J: - break; - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_DSP_B: - rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); - xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); - break; - default: - printk(KERN_ERR "%s:bad format\n", __func__); - return -EINVAL; - } davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); -- cgit v1.2.3 From 07d8d9dca4615821d928f4b5087fdc61e292e1dc Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 19 Dec 2008 13:05:24 -0700 Subject: ALSA: ASoC: DaVinci: document I2S limitations DaVinci does not support true I2S or right justified mode so not all I2S codecs will work with it when the codec is master. Document this limitation. Add dsp_a, dsp_b mode options Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 24fe9db2c75..51ceded8a24 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -241,10 +241,27 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_DSP_B: break; case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_DSP_B: + /* Davinci doesn't support TRUE I2S, but some codecs will have + * the left and right channels contiguous. This allows + * dsp_a mode to be used with an inverted normal frame clk. + * If your codec is master and does not have contiguous + * channels, then you will have sound on only one channel. + * Try using a different mode, or codec as slave. + * + * The TLV320AIC33 is an example of a codec where this works. + * It has a variable bit clock frequency allowing it to have + * valid data on every bit clock. + * + * The TLV320AIC23 is an example of a codec where this does not + * work. It has a fixed bit clock frequency with progressively + * more empty bit clock slots between channels as the sample + * rate is lowered. + */ + fmt ^= SND_SOC_DAIFMT_NB_IF; + case SND_SOC_DAIFMT_DSP_A: rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); break; -- cgit v1.2.3 From a24f4f682661b8069d374a9197bc491525a7c799 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 19 Dec 2008 13:05:22 -0700 Subject: ALSA: ASoC: tlv320aic3x add dsp_a Add SND_SOC_DAIFMT_DSP_A mode option. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 4 ++++ sound/soc/codecs/tlv320aic3x.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 8da9e5d2e2f..b47a749c5ea 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -891,6 +891,7 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; struct aic3x_priv *aic3x = codec->private_data; u8 iface_areg, iface_breg; + int delay = 0; iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; @@ -916,6 +917,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, SND_SOC_DAIFMT_INV_MASK)) { case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): break; + case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF): + delay = 1; case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF): iface_breg |= (0x01 << 6); break; @@ -932,6 +935,7 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set iface */ aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); + aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay); return 0; } diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 73e35b6ec92..ac827e578c4 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -35,6 +35,8 @@ #define AIC3X_ASD_INTF_CTRLA 8 /* Audio serial data interface control register B */ #define AIC3X_ASD_INTF_CTRLB 9 +/* Audio serial data interface control register C */ +#define AIC3X_ASD_INTF_CTRLC 10 /* Audio overflow status and PLL R value programming register */ #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 /* Audio codec digital filter control register */ -- cgit v1.2.3 From 9e031624d50c82a47671e09cc996eebb9e36f698 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 19 Dec 2008 13:05:23 -0700 Subject: ALSA: ASoC: DaVinci: i2s, evm, pass same value to codec and cpu_dai Fix the meaning of SND_SOC_DAIFMT_NB_NF to match that used in the codec. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-evm.c | 10 ++++------ sound/soc/davinci/davinci-i2s.c | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 5c041bf05f3..d2476e206a8 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -28,6 +28,8 @@ #define EVM_CODEC_CLOCK 22579200 +#define AUDIO_FORMAT (SND_SOC_DAIFMT_I2S | \ + SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF) static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -37,16 +39,12 @@ static int evm_hw_params(struct snd_pcm_substream *substream, int ret = 0; /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_NB_NF); + ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_IB_NF); + ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); if (ret < 0) return ret; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 51ceded8a24..0fee779e3c7 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -271,7 +271,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_NF: + case SND_SOC_DAIFMT_NB_NF: /* CLKRP Receive clock polarity, * 1 - sampled on rising edge of CLKR * valid on rising edge @@ -283,7 +283,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, */ pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP); break; - case SND_SOC_DAIFMT_NB_IF: + case SND_SOC_DAIFMT_IB_IF: /* CLKRP Receive clock polarity, * 0 - sampled on falling edge of CLKR * valid on falling edge @@ -295,7 +295,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, */ pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; - case SND_SOC_DAIFMT_IB_IF: + case SND_SOC_DAIFMT_NB_IF: /* CLKRP Receive clock polarity, * 1 - sampled on rising edge of CLKR * valid on rising edge @@ -308,7 +308,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; - case SND_SOC_DAIFMT_NB_NF: + case SND_SOC_DAIFMT_IB_NF: /* CLKRP Receive clock polarity, * 0 - sampled on falling edge of CLKR * valid on falling edge -- cgit v1.2.3 From d6f833965e594015ee05341e43ff4a86f11596b3 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 19 Dec 2008 13:05:25 -0700 Subject: ALSA: ASoc: DaVinci: davinci-evm use dsp_b mode Sense DaVinci does not support true I2S mode and we don't have to use the hack, use dsp_b mode instead Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-evm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index d2476e206a8..01b948bb55a 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -28,8 +28,8 @@ #define EVM_CODEC_CLOCK 22579200 -#define AUDIO_FORMAT (SND_SOC_DAIFMT_I2S | \ - SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF) +#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ + SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { -- cgit v1.2.3 From a31501d1041c9d0a6c3f520736ae2b2fa081493a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 16:50:53 +0100 Subject: ALSA: ASoC - Add missing __devexit annotation to wm8350.c Added the missing __devexit annotation to wm8350_codec_remove(): sound/soc/codecs/wm8350.c:1546: warning: 'wm8350_codec_remove' defined but not used Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8350.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 4bbfb5a5894..e3989d406f5 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1542,7 +1542,7 @@ err_priv: return ret; } -static int wm8350_codec_remove(struct platform_device *pdev) +static int __devexit wm8350_codec_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct snd_soc_codec *codec = wm8350->codec.codec; -- cgit v1.2.3 From bd25867a6cbe7a00ef7dbe8d9ddebc91b00b9b3f Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 22 Dec 2008 10:21:36 +0200 Subject: ASoC: Fix incorrect DSP format in OMAP McBSP DAI and affected drivers - OMAP McBSP DAI driver claims to support DSP_A format which has 1-bit data delay but configures link for 0-bit data delay which is in fact DSP_B - Fix this by changing format from DSP_A to DSP_B - Fix also TLV320AIC23 codec and OSK5912 machine drivers since the same error is populated also there Signed-off-by: Jarkko Nikula Acked-by: Arun KS Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 2 +- sound/soc/omap/omap-mcbsp.c | 4 ++-- sound/soc/omap/osk5912.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 39f5b981d25..cfdea007c4c 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -541,7 +541,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_I2S: iface_reg |= TLV320AIC23_FOR_I2S; break; - case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: iface_reg |= TLV320AIC23_FOR_DSP; break; case SND_SOC_DAIFMT_RIGHT_J: diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 7b86373007c..ec5e18a7875 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -270,7 +270,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, regs->srgr2 |= FPER(wlen * 2 - 1); regs->srgr1 |= FWID(wlen - 1); break; - case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: regs->srgr2 |= FPER(wlen * channels - 1); regs->srgr1 |= FWID(wlen * channels - 2); break; @@ -309,7 +309,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); break; - case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: /* 0-bit data delay */ regs->rcr2 |= RDATDLY(0); regs->xcr2 |= XDATDLY(0); diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 845bf41335b..cd41a948df7 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -61,7 +61,7 @@ static int osk_hw_params(struct snd_pcm_substream *substream, /* Set codec DAI configuration */ err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBM_CFM); if (err < 0) { @@ -71,7 +71,7 @@ static int osk_hw_params(struct snd_pcm_substream *substream, /* Set cpu DAI configuration */ err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBM_CFM); if (err < 0) { -- cgit v1.2.3 From c69134858722977a82f58cae88e7ffdb28e1e858 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 22 Dec 2008 10:57:33 +0200 Subject: ASoC: Fix DSP formats in SSM2602 audio codec Thanks to Troy Kisky for noticing. - DSP_A format has 1-bit data delay which corresponds to SSM6202 submode 2 - DSP_B has 0-bit data delay which corresponds to submode 1 - Currently driver sets them opposite so swap the submode setting Signed-off-by: Jarkko Nikula Cc: Cliff Cai Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 2325aefea41..cac37361676 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -454,10 +454,10 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, iface |= 0x0001; break; case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; + iface |= 0x0013; break; case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0013; + iface |= 0x0003; break; default: return -EINVAL; -- cgit v1.2.3 From 472346da9cc4231bec03ff2032e0d5fd4037232c Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 22 Dec 2008 17:40:45 +0100 Subject: ALSA: ASoC: fix a typo in omp-pcm.c Fix a typo (& and &&) Signed-off-by: Roel Kluin Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- sound/soc/omap/omap-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 803581c9280..b0362dfd5b7 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, prtd->dma_data = dma_data; err = omap_request_dma(dma_data->dma_req, dma_data->name, omap_pcm_dma_irq, substream, &prtd->dma_ch); - if (!err & !cpu_is_omap1510()) { + if (!err && !cpu_is_omap1510()) { /* * Link channel with itself so DMA doesn't need any * reprogramming while looping the buffer -- cgit v1.2.3