aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorMarkus Pargmann <mpa@pengutronix.de>2013-12-20 08:11:29 -0500
committerMark Brown <broonie@linaro.org>2014-01-08 12:18:30 -0500
commit9368acc4383bd8cca671fdc49c5f7e241b6909b3 (patch)
tree9f3dfcf23c95a91b0aa622d6b4dfd37dd0551580 /sound/soc/fsl
parent2841be9afa6c9d37d41386af30cd8813acd06739 (diff)
ASoC: fsl-ssi: Move sysfs stats to debugfs
Interrupt statistics of fsl_ssi are mainly for debugging purpose. Most of those interrupts show error states, e.g. under/overflow. The stats should be exposed via debugfs instead of sysfs. This patch moves the statistics file to debugfs. Signed-off-by: Markus Pargmann <mpa@pengutronix.de> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/fsl_ssi.c184
1 files changed, 117 insertions, 67 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 19891f2a5de4..e483e9d84f8b 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -35,6 +35,7 @@
35#include <linux/module.h> 35#include <linux/module.h>
36#include <linux/interrupt.h> 36#include <linux/interrupt.h>
37#include <linux/clk.h> 37#include <linux/clk.h>
38#include <linux/debugfs.h>
38#include <linux/device.h> 39#include <linux/device.h>
39#include <linux/delay.h> 40#include <linux/delay.h>
40#include <linux/slab.h> 41#include <linux/slab.h>
@@ -114,6 +115,14 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
114 CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | \ 115 CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | \
115 CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN) 116 CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN)
116 117
118#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \
119 CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \
120 CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN)
121#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \
122 CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \
123 CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN)
124#define FSLSSI_SISR_MASK (FSLSSI_SIER_DBG_RX_FLAGS | FSLSSI_SIER_DBG_TX_FLAGS)
125
117/** 126/**
118 * fsl_ssi_private: per-SSI private data 127 * fsl_ssi_private: per-SSI private data
119 * 128 *
@@ -133,7 +142,6 @@ struct fsl_ssi_private {
133 unsigned int irq; 142 unsigned int irq;
134 unsigned int fifo_depth; 143 unsigned int fifo_depth;
135 struct snd_soc_dai_driver cpu_dai_drv; 144 struct snd_soc_dai_driver cpu_dai_drv;
136 struct device_attribute dev_attr;
137 struct platform_device *pdev; 145 struct platform_device *pdev;
138 146
139 bool new_binding; 147 bool new_binding;
@@ -175,6 +183,8 @@ struct fsl_ssi_private {
175 unsigned int tfe1; 183 unsigned int tfe1;
176 unsigned int tfe0; 184 unsigned int tfe0;
177 } stats; 185 } stats;
186 struct dentry *dbg_dir;
187 struct dentry *dbg_stats;
178 188
179 char name[1]; 189 char name[1];
180}; 190};
@@ -203,7 +213,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
203 were interrupted for. We mask it with the Interrupt Enable register 213 were interrupted for. We mask it with the Interrupt Enable register
204 so that we only check for events that we're interested in. 214 so that we only check for events that we're interested in.
205 */ 215 */
206 sisr = read_ssi(&ssi->sisr) & SIER_FLAGS; 216 sisr = read_ssi(&ssi->sisr) & FSLSSI_SISR_MASK;
207 217
208 if (sisr & CCSR_SSI_SISR_RFRC) { 218 if (sisr & CCSR_SSI_SISR_RFRC) {
209 ssi_private->stats.rfrc++; 219 ssi_private->stats.rfrc++;
@@ -323,6 +333,102 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
323 return ret; 333 return ret;
324} 334}
325 335
336#if IS_ENABLED(CONFIG_DEBUG_FS)
337/* Show the statistics of a flag only if its interrupt is enabled. The
338 * compiler will optimze this code to a no-op if the interrupt is not
339 * enabled.
340 */
341#define SIER_SHOW(flag, name) \
342 do { \
343 if (FSLSSI_SISR_MASK & CCSR_SSI_SIER_##flag) \
344 seq_printf(s, #name "=%u\n", ssi_private->stats.name); \
345 } while (0)
346
347
348/**
349 * fsl_sysfs_ssi_show: display SSI statistics
350 *
351 * Display the statistics for the current SSI device. To avoid confusion,
352 * we only show those counts that are enabled.
353 */
354static ssize_t fsl_ssi_stats_show(struct seq_file *s, void *unused)
355{
356 struct fsl_ssi_private *ssi_private = s->private;
357
358 SIER_SHOW(RFRC_EN, rfrc);
359 SIER_SHOW(TFRC_EN, tfrc);
360 SIER_SHOW(CMDAU_EN, cmdau);
361 SIER_SHOW(CMDDU_EN, cmddu);
362 SIER_SHOW(RXT_EN, rxt);
363 SIER_SHOW(RDR1_EN, rdr1);
364 SIER_SHOW(RDR0_EN, rdr0);
365 SIER_SHOW(TDE1_EN, tde1);
366 SIER_SHOW(TDE0_EN, tde0);
367 SIER_SHOW(ROE1_EN, roe1);
368 SIER_SHOW(ROE0_EN, roe0);
369 SIER_SHOW(TUE1_EN, tue1);
370 SIER_SHOW(TUE0_EN, tue0);
371 SIER_SHOW(TFS_EN, tfs);
372 SIER_SHOW(RFS_EN, rfs);
373 SIER_SHOW(TLS_EN, tls);
374 SIER_SHOW(RLS_EN, rls);
375 SIER_SHOW(RFF1_EN, rff1);
376 SIER_SHOW(RFF0_EN, rff0);
377 SIER_SHOW(TFE1_EN, tfe1);
378 SIER_SHOW(TFE0_EN, tfe0);
379
380 return 0;
381}
382
383static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
384{
385 return single_open(file, fsl_ssi_stats_show, inode->i_private);
386}
387
388static const struct file_operations fsl_ssi_stats_ops = {
389 .open = fsl_ssi_stats_open,
390 .read = seq_read,
391 .llseek = seq_lseek,
392 .release = single_release,
393};
394
395static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private,
396 struct device *dev)
397{
398 ssi_private->dbg_dir = debugfs_create_dir(dev_name(dev), NULL);
399 if (!ssi_private->dbg_dir)
400 return -ENOMEM;
401
402 ssi_private->dbg_stats = debugfs_create_file("stats", S_IRUGO,
403 ssi_private->dbg_dir, ssi_private, &fsl_ssi_stats_ops);
404 if (!ssi_private->dbg_stats) {
405 debugfs_remove(ssi_private->dbg_dir);
406 return -ENOMEM;
407 }
408
409 return 0;
410}
411
412static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
413{
414 debugfs_remove(ssi_private->dbg_stats);
415 debugfs_remove(ssi_private->dbg_dir);
416}
417
418#else
419
420static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private,
421 struct device *dev)
422{
423 return 0;
424}
425
426static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
427{
428}
429
430#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */
431
326static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) 432static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
327{ 433{
328 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 434 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
@@ -991,56 +1097,6 @@ static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = {
991 .write = fsl_ssi_ac97_write, 1097 .write = fsl_ssi_ac97_write,
992}; 1098};
993 1099
994/* Show the statistics of a flag only if its interrupt is enabled. The
995 * compiler will optimze this code to a no-op if the interrupt is not
996 * enabled.
997 */
998#define SIER_SHOW(flag, name) \
999 do { \
1000 if (SIER_FLAGS & CCSR_SSI_SIER_##flag) \
1001 length += sprintf(buf + length, #name "=%u\n", \
1002 ssi_private->stats.name); \
1003 } while (0)
1004
1005
1006/**
1007 * fsl_sysfs_ssi_show: display SSI statistics
1008 *
1009 * Display the statistics for the current SSI device. To avoid confusion,
1010 * we only show those counts that are enabled.
1011 */
1012static ssize_t fsl_sysfs_ssi_show(struct device *dev,
1013 struct device_attribute *attr, char *buf)
1014{
1015 struct fsl_ssi_private *ssi_private =
1016 container_of(attr, struct fsl_ssi_private, dev_attr);
1017 ssize_t length = 0;
1018
1019 SIER_SHOW(RFRC_EN, rfrc);
1020 SIER_SHOW(TFRC_EN, tfrc);
1021 SIER_SHOW(CMDAU_EN, cmdau);
1022 SIER_SHOW(CMDDU_EN, cmddu);
1023 SIER_SHOW(RXT_EN, rxt);
1024 SIER_SHOW(RDR1_EN, rdr1);
1025 SIER_SHOW(RDR0_EN, rdr0);
1026 SIER_SHOW(TDE1_EN, tde1);
1027 SIER_SHOW(TDE0_EN, tde0);
1028 SIER_SHOW(ROE1_EN, roe1);
1029 SIER_SHOW(ROE0_EN, roe0);
1030 SIER_SHOW(TUE1_EN, tue1);
1031 SIER_SHOW(TUE0_EN, tue0);
1032 SIER_SHOW(TFS_EN, tfs);
1033 SIER_SHOW(RFS_EN, rfs);
1034 SIER_SHOW(TLS_EN, tls);
1035 SIER_SHOW(RLS_EN, rls);
1036 SIER_SHOW(RFF1_EN, rff1);
1037 SIER_SHOW(RFF0_EN, rff0);
1038 SIER_SHOW(TFE1_EN, tfe1);
1039 SIER_SHOW(TFE0_EN, tfe0);
1040
1041 return length;
1042}
1043
1044/** 1100/**
1045 * Make every character in a string lower-case 1101 * Make every character in a string lower-case
1046 */ 1102 */
@@ -1233,20 +1289,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
1233 } 1289 }
1234 } 1290 }
1235 1291
1236 /* Initialize the the device_attribute structure */
1237 dev_attr = &ssi_private->dev_attr;
1238 sysfs_attr_init(&dev_attr->attr);
1239 dev_attr->attr.name = "statistics";
1240 dev_attr->attr.mode = S_IRUGO;
1241 dev_attr->show = fsl_sysfs_ssi_show;
1242
1243 ret = device_create_file(&pdev->dev, dev_attr);
1244 if (ret) {
1245 dev_err(&pdev->dev, "could not create sysfs %s file\n",
1246 ssi_private->dev_attr.attr.name);
1247 goto error_clk;
1248 }
1249
1250 /* Register with ASoC */ 1292 /* Register with ASoC */
1251 dev_set_drvdata(&pdev->dev, ssi_private); 1293 dev_set_drvdata(&pdev->dev, ssi_private);
1252 1294
@@ -1257,6 +1299,10 @@ static int fsl_ssi_probe(struct platform_device *pdev)
1257 goto error_dev; 1299 goto error_dev;
1258 } 1300 }
1259 1301
1302 ret = fsl_ssi_debugfs_create(ssi_private, &pdev->dev);
1303 if (ret)
1304 goto error_dbgfs;
1305
1260 if (ssi_private->ssi_on_imx) { 1306 if (ssi_private->ssi_on_imx) {
1261 if (!ssi_private->use_dma) { 1307 if (!ssi_private->use_dma) {
1262 1308
@@ -1326,6 +1372,9 @@ error_dai:
1326 imx_pcm_fiq_exit(pdev); 1372 imx_pcm_fiq_exit(pdev);
1327 1373
1328error_pcm: 1374error_pcm:
1375 fsl_ssi_debugfs_remove(ssi_private);
1376
1377error_dbgfs:
1329 snd_soc_unregister_component(&pdev->dev); 1378 snd_soc_unregister_component(&pdev->dev);
1330 1379
1331error_dev: 1380error_dev:
@@ -1349,10 +1398,11 @@ static int fsl_ssi_remove(struct platform_device *pdev)
1349{ 1398{
1350 struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev); 1399 struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
1351 1400
1401 fsl_ssi_debugfs_remove(ssi_private);
1402
1352 if (!ssi_private->new_binding) 1403 if (!ssi_private->new_binding)
1353 platform_device_unregister(ssi_private->pdev); 1404 platform_device_unregister(ssi_private->pdev);
1354 snd_soc_unregister_component(&pdev->dev); 1405 snd_soc_unregister_component(&pdev->dev);
1355 device_remove_file(&pdev->dev, &ssi_private->dev_attr);
1356 if (ssi_private->ssi_on_imx) { 1406 if (ssi_private->ssi_on_imx) {
1357 if (!IS_ERR(ssi_private->baudclk)) 1407 if (!IS_ERR(ssi_private->baudclk))
1358 clk_disable_unprepare(ssi_private->baudclk); 1408 clk_disable_unprepare(ssi_private->baudclk);