Loading asoc/codecs/csra66x0/csra66x0.c +197 −4 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <sound/soc.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/fs.h> #include <linux/debugfs.h> #include "csra66x0.h" /* CSRA66X0 register default values */ Loading Loading @@ -258,8 +260,137 @@ struct csra66x0_priv { u32 irq_active_low; u32 in_cluster; u32 is_master; #if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *debugfs_dir; struct dentry *debugfs_file_wo; struct dentry *debugfs_file_ro; #endif /* CONFIG_DEBUG_FS */ }; #if IS_ENABLED(CONFIG_DEBUG_FS) static int debugfs_codec_open_op(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; } static int debugfs_get_parameters(char *buf, u32 *param1, int num_of_par) { char *token; int base, cnt; token = strsep(&buf, " "); for (cnt = 0; cnt < num_of_par; cnt++) { if (token) { if ((token[1] == 'x') || (token[1] == 'X')) base = 16; else base = 10; if (kstrtou32(token, base, ¶m1[cnt]) != 0) return -EINVAL; token = strsep(&buf, " "); } else { return -EINVAL; } } return 0; } static ssize_t debugfs_codec_write_op(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) filp->private_data; struct snd_soc_codec *codec = csra66x0->codec; char lbuf[32]; int rc; u32 param[2]; if (!filp || !ppos || !ubuf) return -EINVAL; if (cnt > sizeof(lbuf) - 1) return -EINVAL; rc = copy_from_user(lbuf, ubuf, cnt); if (rc) return -EFAULT; lbuf[cnt] = '\0'; rc = debugfs_get_parameters(lbuf, param, 2); if ((param[0] < CSRA66X0_AUDIO_IF_RX_CONFIG1) || (param[0] > CSRA66X0_MAX_REGISTER_ADDR)) { dev_err(codec->dev, "%s: register address 0x%04X out of range\n", __func__, param[0]); return -EINVAL; } if ((param[1] < 0) || (param[1] > 255)) { dev_err(codec->dev, "%s: register data 0x%02X out of range\n", __func__, param[1]); return -EINVAL; } if (rc == 0) { rc = cnt; dev_info(codec->dev, "%s: reg[0x%04X]=0x%02X\n", __func__, param[0], param[1]); snd_soc_write(codec, param[0], param[1]); } else { dev_err(codec->dev, "%s: write to register addr=0x%04X failed\n", __func__, param[0]); } return rc; } static ssize_t debugfs_csra66x0_reg_show(struct snd_soc_codec *codec, char __user *ubuf, size_t count, loff_t *ppos) { int i, reg_val, len; ssize_t total = 0; char tmp_buf[20]; if (!ubuf || !ppos || !codec || *ppos < 0) return -EINVAL; for (i = ((int) *ppos + CSRA66X0_BASE); i <= CSRA66X0_MAX_REGISTER_ADDR; i++) { reg_val = snd_soc_read(codec, i); len = snprintf(tmp_buf, 20, "0x%04X: 0x%02X\n", i, (reg_val & 0xFF)); if ((total + len) >= count - 1) break; if (copy_to_user((ubuf + total), tmp_buf, len)) { dev_err(codec->dev, "%s: fail to copy reg dump\n", __func__); total = -EFAULT; goto copy_err; } *ppos += len; total += len; } copy_err: return total; } static ssize_t debugfs_codec_read_op(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) filp->private_data; struct snd_soc_codec *codec = csra66x0->codec; ssize_t ret_cnt; if (!filp || !ppos || !ubuf || *ppos < 0) return -EINVAL; ret_cnt = debugfs_csra66x0_reg_show(codec, ubuf, cnt, ppos); return ret_cnt; } static const struct file_operations debugfs_codec_ops = { .open = debugfs_codec_open_op, .write = debugfs_codec_write_op, .read = debugfs_codec_read_op, }; #endif /* CONFIG_DEBUG_FS */ /* * CSRA66X0 Controls */ Loading Loading @@ -442,7 +573,7 @@ static int csra66x0_soc_probe(struct snd_soc_codec *codec) if (csra66x0->in_cluster) { dapm = snd_soc_codec_get_dapm(codec); dev_dbg(codec->dev, "%s: setting %s to codec %s\n", dev_dbg(codec->dev, "%s: assign prefix %s to codec device %s\n", __func__, codec->component.name_prefix, codec->component.name); snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, Loading Loading @@ -580,6 +711,31 @@ static irqreturn_t csra66x0_irq(int irq, void *data) /* clear fault state and re-init */ snd_soc_write(codec, CSRA66X0_FAULT_STATUS_FA, 0x00); snd_soc_write(codec, CSRA66X0_IRQ_OUTPUT_STATUS_FA, 0x00); /* apply reset to CSRA66X0 */ val = snd_soc_read(codec, CSRA66X0_MISC_CONTROL_STATUS_1_FA); snd_soc_write(codec, CSRA66X0_MISC_CONTROL_STATUS_1_FA, val | 0x08); /* wait 2s after reset to recover CSRA66X0 */ msleep(2000); /* re-init */ snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, CONFIG_STATE); /* settle time in HW is min. 500ms before proceeding */ msleep(500); snd_soc_write(codec, CSRA66X0_PIO7_SELECT, 0x04); snd_soc_write(codec, CSRA66X0_PIO8_SELECT, 0x04); if (csra66x0->is_master) { /* Master specific config */ snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0xFF); snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR0, 0x80); snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x01); snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR1, 0x01); } else { /* Slave specific config */ snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0x7F); snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x00); } snd_soc_write(codec, CSRA66X0_DCA_CTRL, 0x05); csra66x0_init(codec, csra66x0); } else { return IRQ_NONE; Loading @@ -599,6 +755,7 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, { struct csra66x0_priv *csra66x0; int ret, irq_trigger; char debugfs_dir_name[32]; csra66x0 = devm_kzalloc(&client_i2c->dev, sizeof(struct csra66x0_priv), GFP_KERNEL); Loading Loading @@ -662,7 +819,7 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, } } else { gpio_direction_output(csra66x0->vreg_gpio, 1); gpio_set_value(csra66x0->vreg_gpio, 1); gpio_set_value(csra66x0->vreg_gpio, 0); } /* register interrupt handle */ Loading Loading @@ -695,11 +852,44 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, } } #if IS_ENABLED(CONFIG_DEBUG_FS) /* debugfs interface */ snprintf(debugfs_dir_name, sizeof(debugfs_dir_name), "%s-%s", client_i2c->name, dev_name(&client_i2c->dev)); csra66x0->debugfs_dir = debugfs_create_dir(debugfs_dir_name, NULL); if (!csra66x0->debugfs_dir) { dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s for debugfs\n", __func__, debugfs_dir_name); return -ENOMEM; } csra66x0->debugfs_file_wo = debugfs_create_file( "write_reg_val", S_IFREG | S_IRUGO, csra66x0->debugfs_dir, (void *) csra66x0, &debugfs_codec_ops); if (!csra66x0->debugfs_file_wo) { dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s/write_reg_val\n", __func__, debugfs_dir_name); return -ENOMEM; } csra66x0->debugfs_file_ro = debugfs_create_file( "show_reg_dump", S_IFREG | S_IRUGO, csra66x0->debugfs_dir, (void *) csra66x0, &debugfs_codec_ops); if (!csra66x0->debugfs_file_ro) { dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s/show_reg_dump\n", __func__, debugfs_dir_name); return -ENOMEM; } #endif /* CONFIG_DEBUG_FS */ /* register codec */ ret = snd_soc_register_codec(&client_i2c->dev, &soc_codec_drv_csra66x0, NULL, 0); if (ret != 0) { dev_err(&client_i2c->dev, "%s %d: Failed to register CODEC: %d\n", dev_err(&client_i2c->dev, "%s %d: Failed to register codec: %d\n", __func__, __LINE__, ret); if (gpio_is_valid(csra66x0->vreg_gpio)) { gpio_set_value(csra66x0->vreg_gpio, 0); Loading @@ -719,6 +909,9 @@ static int csra66x0_i2c_remove(struct i2c_client *i2c_client) gpio_set_value(csra66x0->vreg_gpio, 0); gpio_free(csra66x0->vreg_gpio); } #if IS_ENABLED(CONFIG_DEBUG_FS) debugfs_remove_recursive(csra66x0->debugfs_dir); #endif } snd_soc_unregister_codec(&i2c_client->dev); return 0; Loading Loading
asoc/codecs/csra66x0/csra66x0.c +197 −4 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <sound/soc.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/fs.h> #include <linux/debugfs.h> #include "csra66x0.h" /* CSRA66X0 register default values */ Loading Loading @@ -258,8 +260,137 @@ struct csra66x0_priv { u32 irq_active_low; u32 in_cluster; u32 is_master; #if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *debugfs_dir; struct dentry *debugfs_file_wo; struct dentry *debugfs_file_ro; #endif /* CONFIG_DEBUG_FS */ }; #if IS_ENABLED(CONFIG_DEBUG_FS) static int debugfs_codec_open_op(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; } static int debugfs_get_parameters(char *buf, u32 *param1, int num_of_par) { char *token; int base, cnt; token = strsep(&buf, " "); for (cnt = 0; cnt < num_of_par; cnt++) { if (token) { if ((token[1] == 'x') || (token[1] == 'X')) base = 16; else base = 10; if (kstrtou32(token, base, ¶m1[cnt]) != 0) return -EINVAL; token = strsep(&buf, " "); } else { return -EINVAL; } } return 0; } static ssize_t debugfs_codec_write_op(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) filp->private_data; struct snd_soc_codec *codec = csra66x0->codec; char lbuf[32]; int rc; u32 param[2]; if (!filp || !ppos || !ubuf) return -EINVAL; if (cnt > sizeof(lbuf) - 1) return -EINVAL; rc = copy_from_user(lbuf, ubuf, cnt); if (rc) return -EFAULT; lbuf[cnt] = '\0'; rc = debugfs_get_parameters(lbuf, param, 2); if ((param[0] < CSRA66X0_AUDIO_IF_RX_CONFIG1) || (param[0] > CSRA66X0_MAX_REGISTER_ADDR)) { dev_err(codec->dev, "%s: register address 0x%04X out of range\n", __func__, param[0]); return -EINVAL; } if ((param[1] < 0) || (param[1] > 255)) { dev_err(codec->dev, "%s: register data 0x%02X out of range\n", __func__, param[1]); return -EINVAL; } if (rc == 0) { rc = cnt; dev_info(codec->dev, "%s: reg[0x%04X]=0x%02X\n", __func__, param[0], param[1]); snd_soc_write(codec, param[0], param[1]); } else { dev_err(codec->dev, "%s: write to register addr=0x%04X failed\n", __func__, param[0]); } return rc; } static ssize_t debugfs_csra66x0_reg_show(struct snd_soc_codec *codec, char __user *ubuf, size_t count, loff_t *ppos) { int i, reg_val, len; ssize_t total = 0; char tmp_buf[20]; if (!ubuf || !ppos || !codec || *ppos < 0) return -EINVAL; for (i = ((int) *ppos + CSRA66X0_BASE); i <= CSRA66X0_MAX_REGISTER_ADDR; i++) { reg_val = snd_soc_read(codec, i); len = snprintf(tmp_buf, 20, "0x%04X: 0x%02X\n", i, (reg_val & 0xFF)); if ((total + len) >= count - 1) break; if (copy_to_user((ubuf + total), tmp_buf, len)) { dev_err(codec->dev, "%s: fail to copy reg dump\n", __func__); total = -EFAULT; goto copy_err; } *ppos += len; total += len; } copy_err: return total; } static ssize_t debugfs_codec_read_op(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) filp->private_data; struct snd_soc_codec *codec = csra66x0->codec; ssize_t ret_cnt; if (!filp || !ppos || !ubuf || *ppos < 0) return -EINVAL; ret_cnt = debugfs_csra66x0_reg_show(codec, ubuf, cnt, ppos); return ret_cnt; } static const struct file_operations debugfs_codec_ops = { .open = debugfs_codec_open_op, .write = debugfs_codec_write_op, .read = debugfs_codec_read_op, }; #endif /* CONFIG_DEBUG_FS */ /* * CSRA66X0 Controls */ Loading Loading @@ -442,7 +573,7 @@ static int csra66x0_soc_probe(struct snd_soc_codec *codec) if (csra66x0->in_cluster) { dapm = snd_soc_codec_get_dapm(codec); dev_dbg(codec->dev, "%s: setting %s to codec %s\n", dev_dbg(codec->dev, "%s: assign prefix %s to codec device %s\n", __func__, codec->component.name_prefix, codec->component.name); snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, Loading Loading @@ -580,6 +711,31 @@ static irqreturn_t csra66x0_irq(int irq, void *data) /* clear fault state and re-init */ snd_soc_write(codec, CSRA66X0_FAULT_STATUS_FA, 0x00); snd_soc_write(codec, CSRA66X0_IRQ_OUTPUT_STATUS_FA, 0x00); /* apply reset to CSRA66X0 */ val = snd_soc_read(codec, CSRA66X0_MISC_CONTROL_STATUS_1_FA); snd_soc_write(codec, CSRA66X0_MISC_CONTROL_STATUS_1_FA, val | 0x08); /* wait 2s after reset to recover CSRA66X0 */ msleep(2000); /* re-init */ snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, CONFIG_STATE); /* settle time in HW is min. 500ms before proceeding */ msleep(500); snd_soc_write(codec, CSRA66X0_PIO7_SELECT, 0x04); snd_soc_write(codec, CSRA66X0_PIO8_SELECT, 0x04); if (csra66x0->is_master) { /* Master specific config */ snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0xFF); snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR0, 0x80); snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x01); snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR1, 0x01); } else { /* Slave specific config */ snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0x7F); snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x00); } snd_soc_write(codec, CSRA66X0_DCA_CTRL, 0x05); csra66x0_init(codec, csra66x0); } else { return IRQ_NONE; Loading @@ -599,6 +755,7 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, { struct csra66x0_priv *csra66x0; int ret, irq_trigger; char debugfs_dir_name[32]; csra66x0 = devm_kzalloc(&client_i2c->dev, sizeof(struct csra66x0_priv), GFP_KERNEL); Loading Loading @@ -662,7 +819,7 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, } } else { gpio_direction_output(csra66x0->vreg_gpio, 1); gpio_set_value(csra66x0->vreg_gpio, 1); gpio_set_value(csra66x0->vreg_gpio, 0); } /* register interrupt handle */ Loading Loading @@ -695,11 +852,44 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, } } #if IS_ENABLED(CONFIG_DEBUG_FS) /* debugfs interface */ snprintf(debugfs_dir_name, sizeof(debugfs_dir_name), "%s-%s", client_i2c->name, dev_name(&client_i2c->dev)); csra66x0->debugfs_dir = debugfs_create_dir(debugfs_dir_name, NULL); if (!csra66x0->debugfs_dir) { dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s for debugfs\n", __func__, debugfs_dir_name); return -ENOMEM; } csra66x0->debugfs_file_wo = debugfs_create_file( "write_reg_val", S_IFREG | S_IRUGO, csra66x0->debugfs_dir, (void *) csra66x0, &debugfs_codec_ops); if (!csra66x0->debugfs_file_wo) { dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s/write_reg_val\n", __func__, debugfs_dir_name); return -ENOMEM; } csra66x0->debugfs_file_ro = debugfs_create_file( "show_reg_dump", S_IFREG | S_IRUGO, csra66x0->debugfs_dir, (void *) csra66x0, &debugfs_codec_ops); if (!csra66x0->debugfs_file_ro) { dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s/show_reg_dump\n", __func__, debugfs_dir_name); return -ENOMEM; } #endif /* CONFIG_DEBUG_FS */ /* register codec */ ret = snd_soc_register_codec(&client_i2c->dev, &soc_codec_drv_csra66x0, NULL, 0); if (ret != 0) { dev_err(&client_i2c->dev, "%s %d: Failed to register CODEC: %d\n", dev_err(&client_i2c->dev, "%s %d: Failed to register codec: %d\n", __func__, __LINE__, ret); if (gpio_is_valid(csra66x0->vreg_gpio)) { gpio_set_value(csra66x0->vreg_gpio, 0); Loading @@ -719,6 +909,9 @@ static int csra66x0_i2c_remove(struct i2c_client *i2c_client) gpio_set_value(csra66x0->vreg_gpio, 0); gpio_free(csra66x0->vreg_gpio); } #if IS_ENABLED(CONFIG_DEBUG_FS) debugfs_remove_recursive(csra66x0->debugfs_dir); #endif } snd_soc_unregister_codec(&i2c_client->dev); return 0; Loading