summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra_i2s_audio.c
diff options
context:
space:
mode:
authorIliyan Malchev <malchev@google.com>2010-08-20 15:09:59 -0700
committerColin Cross <ccross@android.com>2010-10-06 16:27:52 -0700
commit4615839033086478c1ff700f9f17758124305a5c (patch)
tree67f85cb7bb77f69bcaed90843584ca3dc22ff495 /arch/arm/mach-tegra/tegra_i2s_audio.c
parentca2ab5954d26d78f32aeaa84af43a3fc02c741a6 (diff)
[ARM] tegra: tegra_i2s_audio: remove debugfs, add sysfs interface
-- Removed debugfs interface for toggling DMA -- Added it under sysfs -- Also added attributes for settings the attention levels of the i2s fifos Signed-off-by: Iliyan Malchev <malchev@google.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra_i2s_audio.c')
-rw-r--r--arch/arm/mach-tegra/tegra_i2s_audio.c308
1 files changed, 194 insertions, 114 deletions
diff --git a/arch/arm/mach-tegra/tegra_i2s_audio.c b/arch/arm/mach-tegra/tegra_i2s_audio.c
index 04f947793201..314bb0482d7f 100644
--- a/arch/arm/mach-tegra/tegra_i2s_audio.c
+++ b/arch/arm/mach-tegra/tegra_i2s_audio.c
@@ -36,8 +36,10 @@
#include <linux/debugfs.h>
#include <linux/completion.h>
#include <linux/platform_device.h>
+#include <linux/device.h>
#include <linux/io.h>
#include <linux/ktime.h>
+#include <linux/sysfs.h>
#include <linux/tegra_audio.h>
@@ -1726,113 +1728,6 @@ static int tegra_audio_in_release(struct inode *inode, struct file *file)
return 0;
}
-#ifdef CONFIG_DEBUG_FS
-static int debugfs_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static DEFINE_MUTEX(debugfs_lock);
-
-ssize_t debugfs_read(struct file *file, char __user *buf,
- size_t size, loff_t *off)
-{
- int rc = 0;
- struct audio_driver_state *ads = file->private_data;
- static bool r;
-
- mutex_lock(&debugfs_lock);
-
- if (r) {
- r = false;
- goto done;
- }
-
- if (size < 5) {
- rc = -ETOOSMALL;
- goto done;
- }
-
- if (copy_to_user(buf, ads->using_dma ? "dma\n" : "pio\n", 5)) {
- rc = -EFAULT;
- goto done;
- }
-
- r = true;
- rc = *off = 5;
-done:
- mutex_unlock(&debugfs_lock);
- return rc;
-}
-
-ssize_t debugfs_write(struct file *file,
- const char __user *buf, size_t size, loff_t *off)
-{
- char cmd[5];
- int use_dma;
-
- struct audio_driver_state *ads = file->private_data;
-
- if (size < 4) {
- pr_err("%s: buffer size %d too small\n", __func__, size);
- return -ETOOSMALL;
- }
-
- if (copy_from_user(cmd, buf, 4)) {
- pr_err("%s: could not copy from user\n", __func__);
- return -EFAULT;
- }
- cmd[3] = 0;
-
- use_dma = 0;
- if (!strcmp(cmd, "dma"))
- use_dma = 1;
- else if (strcmp(cmd, "pio")) {
- pr_err("%s: invalid string [%s]\n", __func__, cmd);
- return -EINVAL;
- }
-
- mutex_lock(&ads->out.lock);
- mutex_lock(&ads->in.lock);
- if (ads->out.active || ads->in.active) {
- pr_err("%s: playback or recording in progress.\n", __func__);
- mutex_unlock(&ads->in.lock);
- mutex_unlock(&ads->out.lock);
- return -EBUSY;
- }
- if (!!use_dma ^ !!ads->using_dma)
- toggle_dma(ads);
- else
- pr_info("%s: no change\n", __func__);
- mutex_unlock(&ads->in.lock);
- mutex_unlock(&ads->out.lock);
-
- return 5;
-}
-
-static const struct file_operations debugfs_ops = {
- .read = debugfs_read,
- .write = debugfs_write,
- .open = debugfs_open,
-};
-
-static void setup_tegra_audio_debugfs(struct audio_driver_state *ads)
-{
- struct dentry *dent;
-
- dent = debugfs_create_dir("tegra_audio", 0);
- if (IS_ERR(dent)) {
- pr_err("%s: could not create dentry\n", __func__);
- return;
- }
-
- debugfs_create_file("dma", 0666, dent, ads, &debugfs_ops);
-}
-#else
-static inline void setup_tegra_audio_debugfs(struct audio_driver_state *ads) {}
-#endif
-
static const struct file_operations tegra_audio_out_fops = {
.owner = THIS_MODULE,
.open = tegra_audio_out_open,
@@ -1956,6 +1851,166 @@ done:
return rc;
}
+static ssize_t dma_toggle_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tegra_audio_platform_data *pdata = dev->platform_data;
+ struct audio_driver_state *ads = pdata->driver_data;
+ return sprintf(buf, "%s\n", ads->using_dma ? "dma" : "pio");
+}
+
+static ssize_t dma_toggle_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int use_dma;
+ struct tegra_audio_platform_data *pdata = dev->platform_data;
+ struct audio_driver_state *ads = pdata->driver_data;
+
+ if (count < 4)
+ return -EINVAL;
+
+ use_dma = 0;
+ if (!strncmp(buf, "dma", 3))
+ use_dma = 1;
+ else if (strncmp(buf, "pio", 3)) {
+ dev_err(dev, "%s: invalid string [%s]\n", __func__, buf);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ads->out.lock);
+ mutex_lock(&ads->in.lock);
+ if (ads->out.active || ads->in.active) {
+ dev_err(dev, "%s: playback or recording in progress.\n",
+ __func__);
+ mutex_unlock(&ads->in.lock);
+ mutex_unlock(&ads->out.lock);
+ return -EBUSY;
+ }
+ if (!!use_dma ^ !!ads->using_dma)
+ toggle_dma(ads);
+ else
+ dev_info(dev, "%s: no change\n", __func__);
+ mutex_unlock(&ads->in.lock);
+ mutex_unlock(&ads->out.lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(dma_toggle, 0644, dma_toggle_show, dma_toggle_store);
+
+static ssize_t __attr_fifo_atn_read(char *buf, int atn_lvl)
+{
+ switch (atn_lvl) {
+ case I2S_FIFO_ATN_LVL_ONE_SLOT:
+ strncpy(buf, "1\n", 2);
+ return 2;
+ case I2S_FIFO_ATN_LVL_FOUR_SLOTS:
+ strncpy(buf, "4\n", 2);
+ return 2;
+ case I2S_FIFO_ATN_LVL_EIGHT_SLOTS:
+ strncpy(buf, "8\n", 2);
+ return 2;
+ case I2S_FIFO_ATN_LVL_TWELVE_SLOTS:
+ strncpy(buf, "12\n", 3);
+ return 3;
+ default:
+ BUG_ON(1);
+ return -EIO;
+ }
+}
+
+static ssize_t __attr_fifo_atn_write(struct audio_driver_state *ads,
+ struct audio_stream *as,
+ int *fifo_lvl,
+ const char *buf, size_t size)
+{
+ int lvl;
+
+ if (size > 3) {
+ pr_err("%s: buffer size %d too big\n", __func__, size);
+ return -EINVAL;
+ }
+
+ if (sscanf(buf, "%d", &lvl) != 1) {
+ pr_err("%s: invalid input string [%s]\n", __func__, buf);
+ return -EINVAL;
+ }
+
+ switch (lvl) {
+ case 1:
+ lvl = I2S_FIFO_ATN_LVL_ONE_SLOT;
+ break;
+ case 4:
+ lvl = I2S_FIFO_ATN_LVL_FOUR_SLOTS;
+ break;
+ case 8:
+ lvl = I2S_FIFO_ATN_LVL_EIGHT_SLOTS;
+ break;
+ case 12:
+ lvl = I2S_FIFO_ATN_LVL_TWELVE_SLOTS;
+ break;
+ default:
+ pr_err("%s: invalid attention level %d\n", __func__, lvl);
+ return -EINVAL;
+ }
+
+ mutex_lock(&as->lock);
+ if (as->active) {
+ pr_err("%s: in progress.\n", __func__);
+ mutex_unlock(&as->lock);
+ return -EBUSY;
+ }
+ *fifo_lvl = lvl;
+ pr_info("%s: fifo level %d\n", __func__, *fifo_lvl);
+ mutex_unlock(&as->lock);
+
+ return size;
+}
+
+static ssize_t tx_fifo_atn_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tegra_audio_platform_data *pdata = dev->platform_data;
+ struct audio_driver_state *ads = pdata->driver_data;
+ return __attr_fifo_atn_read(buf, ads->out.i2s_fifo_atn_level);
+}
+
+static ssize_t tx_fifo_atn_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tegra_audio_platform_data *pdata = dev->platform_data;
+ struct audio_driver_state *ads = pdata->driver_data;
+ return __attr_fifo_atn_write(ads, &ads->out,
+ &ads->out.i2s_fifo_atn_level, buf, count);
+}
+
+static DEVICE_ATTR(tx_fifo_atn, 0644, tx_fifo_atn_show, tx_fifo_atn_store);
+
+static ssize_t rx_fifo_atn_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tegra_audio_platform_data *pdata = dev->platform_data;
+ struct audio_driver_state *ads = pdata->driver_data;
+ return __attr_fifo_atn_read(buf, ads->in.i2s_fifo_atn_level);
+}
+
+static ssize_t rx_fifo_atn_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tegra_audio_platform_data *pdata = dev->platform_data;
+ struct audio_driver_state *ads = pdata->driver_data;
+ return __attr_fifo_atn_write(ads, &ads->in,
+ &ads->in.i2s_fifo_atn_level, buf, count);
+}
+
+static DEVICE_ATTR(rx_fifo_atn, 0644, rx_fifo_atn_show, rx_fifo_atn_store);
+
static int tegra_audio_probe(struct platform_device *pdev)
{
int rc;
@@ -1971,6 +2026,7 @@ static int tegra_audio_probe(struct platform_device *pdev)
state->pdev = pdev;
state->pdata = pdev->dev.platform_data;
+ state->pdata->driver_data = state;
BUG_ON(!state->pdata);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2013,27 +2069,31 @@ static int tegra_audio_probe(struct platform_device *pdev)
i2s_clk = clk_get(&pdev->dev, NULL);
if (!i2s_clk) {
- pr_err("%s: could not get i2s1 clock\n", __func__);
+ dev_err(&pdev->dev, "%s: could not get i2s1 clock\n",
+ __func__);
return -EIO;
}
clk_set_rate(i2s_clk, state->pdata->i2s_clk_rate);
if (clk_enable(i2s_clk)) {
- pr_err("%s: failed to enable i2s1 clock\n", __func__);
+ dev_err(&pdev->dev, "%s: failed to enable i2s1 clock\n",
+ __func__);
return -EIO;
}
pr_info("%s: i2s_clk rate %ld\n", __func__, clk_get_rate(i2s_clk));
dap_mclk = tegra_get_clock_by_name(state->pdata->dap_clk);
if (!dap_mclk) {
- pr_err("%s: could not get DAP clock\n", __func__);
+ dev_err(&pdev->dev, "%s: could not get DAP clock\n",
+ __func__);
return -EIO;
}
clk_enable(dap_mclk);
audio_sync_clk = tegra_get_clock_by_name(state->pdata->audio_sync_clk);
if (!audio_sync_clk) {
- pr_err("%s: could not get audio_2x clock\n", __func__);
+ dev_err(&pdev->dev, "%s: could not get audio_2x clock\n",
+ __func__);
return -EIO;
}
clk_enable(audio_sync_clk);
@@ -2096,7 +2156,8 @@ static int tegra_audio_probe(struct platform_device *pdev)
if (request_irq(state->irq, i2s_interrupt,
IRQF_DISABLED, state->pdev->name, state) < 0) {
- pr_err("%s: could not register handler for irq %d\n",
+ dev_err(&pdev->dev,
+ "%s: could not register handler for irq %d\n",
__func__, state->irq);
return -EIO;
}
@@ -2130,13 +2191,32 @@ static int tegra_audio_probe(struct platform_device *pdev)
sound_ops = &pio_sound_ops;
sound_ops->setup(state);
+ rc = device_create_file(&pdev->dev, &dev_attr_dma_toggle);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "%s: could not create sysfs entry %s: %d\n",
+ __func__, dev_attr_dma_toggle.attr.name, rc);
+ return rc;
+ }
+
+ rc = device_create_file(&pdev->dev, &dev_attr_tx_fifo_atn);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "%s: could not create sysfs entry %s: %d\n",
+ __func__, dev_attr_tx_fifo_atn.attr.name, rc);
+ return rc;
+ }
+
+ rc = device_create_file(&pdev->dev, &dev_attr_rx_fifo_atn);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "%s: could not create sysfs entry %s: %d\n",
+ __func__, dev_attr_rx_fifo_atn.attr.name, rc);
+ return rc;
+ }
+
state->in_config.rate = 11025;
state->in_config.stereo = false;
state->in_divs = divs_11025;
state->in_divs_len = ARRAY_SIZE(divs_11025);
- setup_tegra_audio_debugfs(state);
-
return 0;
}