diff --git a/asoc/codecs/csra66x0/csra66x0.c b/asoc/codecs/csra66x0/csra66x0.c index 595e7ca8fa..42768f10ca 100644 --- a/asoc/codecs/csra66x0/csra66x0.c +++ b/asoc/codecs/csra66x0/csra66x0.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include #include @@ -20,6 +20,7 @@ #include "csra66x0.h" #define DRV_NAME "csra66x0_codec" +#define CSRA66X0_SYSFS_ENTRY_MAX_LEN 64 /* CSRA66X0 register default values */ static struct reg_default csra66x0_reg_defaults[] = { @@ -204,8 +205,24 @@ static struct reg_default csra66x0_reg_defaults[] = { /* RESERVED */ }; +static bool csra66x0_addr_is_in_range(unsigned int addr, + unsigned int addr_min, unsigned int addr_max) +{ + if ((addr >= addr_min) + && (addr <= addr_max)) + return true; + else + return false; +} + static bool csra66x0_volatile_register(struct device *dev, unsigned int reg) { + /* coeff registers */ + if (csra66x0_addr_is_in_range(reg, CSRA66X0_COEFF_BASE, + CSRA66X0_MAX_COEFF_ADDR)) + return true; + + /* control registers */ switch (reg) { case CSRA66X0_CHIP_ID_FA: case CSRA66X0_ROM_VER_FA: @@ -213,6 +230,7 @@ static bool csra66x0_volatile_register(struct device *dev, unsigned int reg) case CSRA66X0_CHIP_REV_1_FA: case CSRA66X0_TEMP_READ0_FA: case CSRA66X0_TEMP_READ1_FA: + case CSRA66X0_CHIP_STATE_CTRL_FA: case CSRA66X0_MISC_CONTROL_STATUS_1_FA: case CSRA66X0_IRQ_OUTPUT_STATUS_FA: case CSRA66X0_CLIP_DCA_STATUS_FA: @@ -222,6 +240,41 @@ static bool csra66x0_volatile_register(struct device *dev, unsigned int reg) case CSRA66X0_AUDIO_IF_STATUS_FA: case CSRA66X0_DSP_SATURATION_STATUS_FA: case CSRA66X0_AUDIO_RATE_STATUS_FA: + case CSRA66X0_CH1_MIX_SEL: + case CSRA66X0_CH2_MIX_SEL: + case CSRA66X0_CH1_SAMPLE1_SCALE_0: + case CSRA66X0_CH1_SAMPLE1_SCALE_1: + case CSRA66X0_CH1_SAMPLE3_SCALE_0: + case CSRA66X0_CH1_SAMPLE3_SCALE_1: + case CSRA66X0_CH1_SAMPLE5_SCALE_0: + case CSRA66X0_CH1_SAMPLE5_SCALE_1: + case CSRA66X0_CH1_SAMPLE7_SCALE_0: + case CSRA66X0_CH1_SAMPLE7_SCALE_1: + case CSRA66X0_CH1_SAMPLE2_SCALE_0: + case CSRA66X0_CH1_SAMPLE2_SCALE_1: + case CSRA66X0_CH1_SAMPLE4_SCALE_0: + case CSRA66X0_CH1_SAMPLE4_SCALE_1: + case CSRA66X0_CH1_SAMPLE6_SCALE_0: + case CSRA66X0_CH1_SAMPLE6_SCALE_1: + case CSRA66X0_CH1_SAMPLE8_SCALE_0: + case CSRA66X0_CH1_SAMPLE8_SCALE_1: + case CSRA66X0_CH2_SAMPLE1_SCALE_0: + case CSRA66X0_CH2_SAMPLE1_SCALE_1: + case CSRA66X0_CH2_SAMPLE3_SCALE_0: + case CSRA66X0_CH2_SAMPLE3_SCALE_1: + case CSRA66X0_CH2_SAMPLE5_SCALE_0: + case CSRA66X0_CH2_SAMPLE5_SCALE_1: + case CSRA66X0_CH2_SAMPLE7_SCALE_0: + case CSRA66X0_CH2_SAMPLE7_SCALE_1: + case CSRA66X0_CH2_SAMPLE2_SCALE_0: + case CSRA66X0_CH2_SAMPLE2_SCALE_1: + case CSRA66X0_CH2_SAMPLE4_SCALE_0: + case CSRA66X0_CH2_SAMPLE4_SCALE_1: + case CSRA66X0_CH2_SAMPLE6_SCALE_0: + case CSRA66X0_CH2_SAMPLE6_SCALE_1: + case CSRA66X0_CH2_SAMPLE8_SCALE_0: + case CSRA66X0_CH2_SAMPLE8_SCALE_1: + case CSRA66X0_RAM_VER_FA: return true; default: return false; @@ -230,20 +283,24 @@ static bool csra66x0_volatile_register(struct device *dev, unsigned int reg) static bool csra66x0_writeable_registers(struct device *dev, unsigned int reg) { - if ((reg >= CSRA66X0_AUDIO_IF_RX_CONFIG1) - && (reg <= CSRA66X0_MAX_REGISTER_ADDR)) + if (csra66x0_addr_is_in_range(reg, CSRA66X0_BASE, + CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(reg, CSRA66X0_COEFF_BASE, + CSRA66X0_MAX_COEFF_ADDR)) return true; - - return false; + else + return false; } static bool csra66x0_readable_registers(struct device *dev, unsigned int reg) { - if ((reg >= CSRA66X0_AUDIO_IF_RX_CONFIG1) - && (reg <= CSRA66X0_MAX_REGISTER_ADDR)) + if (csra66x0_addr_is_in_range(reg, CSRA66X0_BASE, + CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(reg, CSRA66X0_COEFF_BASE, + CSRA66X0_MAX_COEFF_ADDR)) return true; - - return false; + else + return false; } /* codec private data */ @@ -257,6 +314,10 @@ struct csra66x0_priv { u32 irq_active_low; u32 in_cluster; u32 is_master; + bool is_probed; + u32 max_num_cluster_devices; + u32 num_cluster_devices; + u32 sysfs_reg_addr; #if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *debugfs_dir; struct dentry *debugfs_file_wo; @@ -278,14 +339,7 @@ struct csra66x0_cluster_device csra_clust_dev_tbl[] = { {NULL, "CSRA_BC"} }; -#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) +static int sysfs_get_param(char *buf, u32 *param, int num_of_par) { char *token; int base, cnt; @@ -298,7 +352,7 @@ static int debugfs_get_parameters(char *buf, u32 *param1, int num_of_par) else base = 10; - if (kstrtou32(token, base, ¶m1[cnt]) != 0) + if (kstrtou32(token, base, ¶m[cnt]) != 0) return -EINVAL; token = strsep(&buf, " "); @@ -309,6 +363,13 @@ static int debugfs_get_parameters(char *buf, u32 *param1, int num_of_par) return 0; } +#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 ssize_t debugfs_codec_write_op(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { @@ -319,7 +380,7 @@ static ssize_t debugfs_codec_write_op(struct file *filp, int rc; u32 param[2]; - if (!filp || !ppos || !ubuf) + if (!filp || !ppos || !ubuf || !component) return -EINVAL; if (cnt > sizeof(lbuf) - 1) return -EINVAL; @@ -327,9 +388,12 @@ static ssize_t debugfs_codec_write_op(struct file *filp, 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)) { + rc = sysfs_get_param(lbuf, param, 2); + + if (!(csra66x0_addr_is_in_range(param[0], + CSRA66X0_BASE, CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(param[0], + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR))) { dev_err(component->dev, "%s: register address 0x%04X out of range\n", __func__, param[0]); return -EINVAL; @@ -352,18 +416,30 @@ static ssize_t debugfs_codec_write_op(struct file *filp, return rc; } -static ssize_t debugfs_csra66x0_reg_show(struct snd_soc_component *component, +static ssize_t debugfs_csra66x0_reg_show(struct csra66x0_priv *csra66x0, char __user *ubuf, size_t count, loff_t *ppos) { int i, reg_val, len; + int addr_min, addr_max; ssize_t total = 0; char tmp_buf[20]; + struct snd_soc_component *component = csra66x0->component; if (!ubuf || !ppos || !component || *ppos < 0) return -EINVAL; - for (i = ((int) *ppos + CSRA66X0_BASE); - i <= CSRA66X0_MAX_REGISTER_ADDR; i++) { + if (csra66x0_addr_is_in_range(csra66x0->sysfs_reg_addr, + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR)) { + addr_min = CSRA66X0_COEFF_BASE; + addr_max = CSRA66X0_MAX_COEFF_ADDR; + csra66x0->sysfs_reg_addr = CSRA66X0_BASE; + } else { + addr_min = CSRA66X0_BASE; + addr_max = CSRA66X0_MAX_REGISTER_ADDR; + } + + for (i = ((int) *ppos + addr_min); + i <= addr_max; i++) { reg_val = snd_soc_component_read32(component, i); len = snprintf(tmp_buf, 20, "0x%04X: 0x%02X\n", i, (reg_val & 0xFF)); if ((total + len) >= count - 1) @@ -387,12 +463,11 @@ static ssize_t debugfs_codec_read_op(struct file *filp, { struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) filp->private_data; - struct snd_soc_component *component = csra66x0->component; ssize_t ret_cnt; if (!filp || !ppos || !ubuf || *ppos < 0) return -EINVAL; - ret_cnt = debugfs_csra66x0_reg_show(component, ubuf, cnt, ppos); + ret_cnt = debugfs_csra66x0_reg_show(csra66x0, ubuf, cnt, ppos); return ret_cnt; } @@ -515,11 +590,8 @@ static const struct snd_soc_dapm_widget csra66x0_dapm_widgets[] = { SND_SOC_DAPM_MIXER("MIXER", SND_SOC_NOPM, 0, 0, csra_mix_switch, ARRAY_SIZE(csra_mix_switch)), SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_PGA("PGA", CSRA66X0_CHIP_STATE_CTRL_FA, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("SPKR"), - - SND_SOC_DAPM_SUPPLY("POWER", CSRA66X0_CHIP_STATE_CTRL_FA, - 1, 1, NULL, 0), }; static const struct snd_soc_dapm_route csra66x0_dapm_routes[] = { @@ -527,20 +599,140 @@ static const struct snd_soc_dapm_route csra66x0_dapm_routes[] = { {"DAC", NULL, "MIXER"}, {"PGA", NULL, "DAC"}, {"SPKR", NULL, "PGA"}, - {"SPKR", NULL, "POWER"}, }; +static int csra66x0_wait_for_config_state(struct snd_soc_component *component) +{ + u16 val; + int cntdwn = WAIT_FOR_CONFIG_STATE_TIMEOUT_MS; + + do { + /* wait >= 100ms to check if HW has moved to config state */ + msleep(100); + val = snd_soc_component_read32(component, + CSRA66X0_CHIP_STATE_STATUS_FA); + if (val == CONFIG_STATE_ID) + break; + + cntdwn = cntdwn - 100; + } while (cntdwn > 0); + if (cntdwn <= 0) + return -EFAULT; + + return 0; +} + +static int csra66x0_allow_run(struct csra66x0_priv *csra66x0) +{ + struct snd_soc_component *component = csra66x0->component; + int i; + + /* csra66x0 is not in cluster */ + if (!csra66x0->in_cluster) { + /* enable interrupts */ + if (csra66x0->irq) { + snd_soc_component_write(component, + CSRA66X0_PIO0_SELECT, 0x1); + if (csra66x0->irq_active_low) + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_POLARITY, 0x0); + else + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_POLARITY, 0x1); + + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_ENABLE, 0x01); + } else { + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_ENABLE, 0x00); + } + /* allow run */ + snd_soc_component_write(component, + CSRA66X0_CHIP_STATE_CTRL_FA, SET_RUN_STATE); + return 0; + } + + /* csra66x0 is part of cluster */ + /* get number of probed cluster devices */ + csra66x0->num_cluster_devices = 0; + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_probed) + csra66x0->num_cluster_devices++; + } + + /* check if all cluster devices are probed */ + if (csra66x0->num_cluster_devices + == component->card->num_aux_devs) { + /* allow run of all slave components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + continue; + snd_soc_component_write( + csra_clust_dev_tbl[i].csra66x0_ptr->component, + CSRA66X0_CHIP_STATE_CTRL_FA, SET_RUN_STATE); + } + /* allow run of all master components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (!csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + continue; + + /* enable interrupts */ + if (csra66x0->irq) { + snd_soc_component_write(component, + CSRA66X0_PIO0_SELECT, 0x1); + if (csra66x0->irq_active_low) + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_POLARITY, + 0x0); + else + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_POLARITY, + 0x1); + + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_ENABLE, 0x01); + } else { + snd_soc_component_write(component, + CSRA66X0_IRQ_OUTPUT_ENABLE, 0x00); + } + /* allow run */ + snd_soc_component_write( + csra_clust_dev_tbl[i].csra66x0_ptr->component, + CSRA66X0_CHIP_STATE_CTRL_FA, SET_RUN_STATE); + } + } + return 0; +} + static int csra66x0_init(struct csra66x0_priv *csra66x0) { struct snd_soc_component *component = csra66x0->component; + int ret; dev_dbg(component->dev, "%s: initialize %s\n", __func__, component->name); + csra66x0->sysfs_reg_addr = CSRA66X0_BASE; /* config */ snd_soc_component_write(component, CSRA66X0_CHIP_STATE_CTRL_FA, - CONFIG_STATE); - /* settle time in HW is min. 500ms before proceeding */ - msleep(500); + SET_CONFIG_STATE); + /* wait until HW is in config state before proceeding */ + ret = csra66x0_wait_for_config_state(component); + if (ret) { + dev_err(component->dev, "%s: timeout while %s is waiting for config state\n", + __func__, component->name); + } /* setup */ snd_soc_component_write(component, CSRA66X0_MISC_CONTROL_STATUS_0, @@ -578,23 +770,7 @@ static int csra66x0_init(struct csra66x0_priv *csra66x0) snd_soc_component_write(component, CSRA66X0_DCA_ATTACK_RATE, 0x00); snd_soc_component_write(component, CSRA66X0_DCA_RELEASE_RATE, 0x00); - if (csra66x0->irq) { - snd_soc_component_write(component, CSRA66X0_PIO0_SELECT, 0x1); - if (csra66x0->irq_active_low) - snd_soc_component_write(component, - CSRA66X0_IRQ_OUTPUT_POLARITY, 0x0); - else - snd_soc_component_write(component, - CSRA66X0_IRQ_OUTPUT_POLARITY, 0x1); - - snd_soc_component_write(component, - CSRA66X0_IRQ_OUTPUT_ENABLE, 0x01); - } else { - snd_soc_component_write(component, - CSRA66X0_IRQ_OUTPUT_ENABLE, 0x00); - } - /* settle time in HW is min. 500ms before slave initializing */ - msleep(500); + csra66x0_allow_run(csra66x0); return 0; } @@ -641,14 +817,20 @@ static int csra66x0_reset(struct csra66x0_priv *csra66x0) static int csra66x0_msconfig(struct csra66x0_priv *csra66x0) { struct snd_soc_component *component = csra66x0->component; + int ret; dev_dbg(component->dev, "%s: configure %s\n", __func__, component->name); /* config */ snd_soc_component_write(component, CSRA66X0_CHIP_STATE_CTRL_FA, - CONFIG_STATE); - /* settle time in HW is min. 500ms before proceeding */ - msleep(500); + SET_CONFIG_STATE); + /* wait until HW is in config state before proceeding */ + ret = csra66x0_wait_for_config_state(component); + if (ret) { + dev_err(component->dev, "%s: timeout while %s is waiting for config state\n", + __func__, component->name); + return ret; + } snd_soc_component_write(component, CSRA66X0_PIO7_SELECT, 0x04); snd_soc_component_write(component, CSRA66X0_PIO8_SELECT, 0x04); if (csra66x0->is_master) { @@ -678,27 +860,29 @@ static int csra66x0_soc_probe(struct snd_soc_component *component) snd_soc_component_get_drvdata(component); struct snd_soc_dapm_context *dapm; char name[50]; - unsigned int i, max_num_cluster_devices; + unsigned int i; csra66x0->component = component; if (csra66x0->in_cluster) { dapm = snd_soc_component_get_dapm(component); - dev_dbg(component->dev, "%s: assign prefix %s to codec device %s\n", + dev_dbg(component->dev, "%s: assign prefix %s to component device %s\n", __func__, component->name_prefix, component->name); /* add device to cluster table */ - max_num_cluster_devices = sizeof(csra_clust_dev_tbl)/ - sizeof(csra_clust_dev_tbl[0]); - for (i = 0; i < max_num_cluster_devices; i++) { + csra66x0->max_num_cluster_devices = + ARRAY_SIZE(csra_clust_dev_tbl); + for (i = 0; i < csra66x0->max_num_cluster_devices; i++) { if (!strncmp(component->name_prefix, - csra_clust_dev_tbl[i].csra66x0_prefix, - strlen( - csra_clust_dev_tbl[i].csra66x0_prefix))) { + csra_clust_dev_tbl[i].csra66x0_prefix, + strnlen( + csra_clust_dev_tbl[i].csra66x0_prefix, + sizeof( + csra_clust_dev_tbl[i].csra66x0_prefix)))) { csra_clust_dev_tbl[i].csra66x0_ptr = csra66x0; break; } - if (i == max_num_cluster_devices-1) + if (i == csra66x0->max_num_cluster_devices - 1) dev_warn(component->dev, "%s: Unknown prefix %s of cluster device %s\n", __func__, component->name_prefix, @@ -720,6 +904,7 @@ static int csra66x0_soc_probe(struct snd_soc_component *component) } /* common initialization */ + csra66x0->is_probed = 1; csra66x0_init(csra66x0); return 0; } @@ -727,36 +912,14 @@ static int csra66x0_soc_probe(struct snd_soc_component *component) static void csra66x0_soc_remove(struct snd_soc_component *component) { snd_soc_component_write(component, CSRA66X0_CHIP_STATE_CTRL_FA, - STDBY_STATE); + SET_STDBY_STATE); return; } -static int csra66x0_soc_suspend(struct snd_soc_component *component) -{ - u16 state_reg = snd_soc_component_read32(component, - CSRA66X0_CHIP_STATE_CTRL_FA) & 0xFC; - - snd_soc_component_write(component, CSRA66X0_CHIP_STATE_CTRL_FA, - state_reg | STDBY_STATE); - return 0; -} - -static int csra66x0_soc_resume(struct snd_soc_component *component) -{ - u16 state_reg = snd_soc_component_read32( - component, CSRA66X0_CHIP_STATE_CTRL_FA) & 0xFC; - - snd_soc_component_write(component, CSRA66X0_CHIP_STATE_CTRL_FA, - state_reg | RUN_STATE); - return 0; -} - static const struct snd_soc_component_driver soc_codec_drv_csra66x0 = { .name = DRV_NAME, .probe = csra66x0_soc_probe, .remove = csra66x0_soc_remove, - .suspend = csra66x0_soc_suspend, - .resume = csra66x0_soc_resume, .controls = csra66x0_snd_controls, .num_controls = ARRAY_SIZE(csra66x0_snd_controls), .dapm_widgets = csra66x0_dapm_widgets, @@ -771,7 +934,7 @@ static struct regmap_config csra66x0_regmap_config = { .cache_type = REGCACHE_RBTREE, .reg_defaults = csra66x0_reg_defaults, .num_reg_defaults = ARRAY_SIZE(csra66x0_reg_defaults), - .max_register = CSRA66X0_MAX_REGISTER_ADDR, + .max_register = CSRA66X0_MAX_COEFF_ADDR, .volatile_reg = csra66x0_volatile_register, .writeable_reg = csra66x0_writeable_registers, .readable_reg = csra66x0_readable_registers, @@ -782,7 +945,7 @@ static irqreturn_t csra66x0_irq(int irq, void *data) struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) data; struct snd_soc_component *component = csra66x0->component; u16 val; - unsigned int i, max_num_cluster_devices; + unsigned int i; /* Treat interrupt before component is initialized as spurious */ if (component == NULL) @@ -798,12 +961,9 @@ static irqreturn_t csra66x0_irq(int irq, void *data) return IRQ_HANDLED; if (csra66x0->in_cluster) { - /* reset all slave codecs */ - max_num_cluster_devices = - sizeof(csra_clust_dev_tbl) / - sizeof(csra_clust_dev_tbl[0]); - for (i = 0; i < max_num_cluster_devices; i++) { - if (i >= component->card->num_aux_devs) + /* reset all slave components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) break; if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) continue; @@ -811,9 +971,9 @@ static irqreturn_t csra66x0_irq(int irq, void *data) continue; csra66x0_reset(csra_clust_dev_tbl[i].csra66x0_ptr); } - /* reset all master codecs */ - for (i = 0; i < max_num_cluster_devices; i++) { - if (i >= component->card->num_aux_devs) + /* reset all master components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) break; if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) continue; @@ -821,9 +981,9 @@ static irqreturn_t csra66x0_irq(int irq, void *data) csra66x0_reset( csra_clust_dev_tbl[i].csra66x0_ptr); } - /* recover all codecs */ - for (i = 0; i < max_num_cluster_devices; i++) { - if (i >= component->card->num_aux_devs) + /* recover all components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) break; if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) continue; @@ -843,13 +1003,275 @@ static const struct of_device_id csra66x0_of_match[] = { }; MODULE_DEVICE_TABLE(of, csra66x0_of_match); +static ssize_t csra66x0_sysfs_write2reg_addr_value(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + u32 param[2]; /*reg_addr, reg_value */ + char lbuf[CSRA66X0_SYSFS_ENTRY_MAX_LEN]; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + struct snd_soc_component *component = csra66x0->component; + + if (!csra66x0) { + dev_err(component->dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + + if (count > sizeof(lbuf) - 1) + return -EINVAL; + + ret = strlcpy(lbuf, buf, count); + if (ret != count) { + dev_err(component->dev, "%s: copy input from user space failed. ret=%d\n", + __func__, ret); + ret = -EFAULT; + goto end; + } + + lbuf[count] = '\0'; + ret = sysfs_get_param(lbuf, param, 2); + if (ret) { + dev_err(component->dev, "%s: get sysfs parameter failed. ret=%d\n", + __func__, ret); + goto end; + } + + if (!(csra66x0_addr_is_in_range(param[0], + CSRA66X0_BASE, CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(param[0], + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR))) { + dev_err(component->dev, "%s: register address 0x%04X out of range\n", + __func__, param[0]); + ret = -EINVAL; + goto end; + } + + if ((param[1] < 0) || (param[1] > 255)) { + dev_err(component->dev, "%s: register data 0x%02X out of range\n", + __func__, param[1]); + ret = -EINVAL; + goto end; + } + + snd_soccomponent_component_write(component, param[0], param[1]); + ret = count; + +end: + return ret; +} + +static ssize_t csra66x0_sysfs_read2reg_addr_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + u32 reg_addr; + char lbuf[CSRA66X0_SYSFS_ENTRY_MAX_LEN]; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + + if (!csra66x0) { + dev_err(dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + + if (count > sizeof(lbuf) - 1) + return -EINVAL; + + ret = strlcpy(lbuf, buf, count); + if (ret != count) { + dev_err(dev, "%s: copy input from user space failed. ret=%d\n", + __func__, ret); + ret = -EFAULT; + goto end; + } + + lbuf[count] = '\0'; + ret = sysfs_get_param(lbuf, ®_addr, 1); + if (ret) { + dev_err(dev, "%s: get sysfs parameter failed. ret=%d\n", + __func__, ret); + goto end; + } + + if (!(csra66x0_addr_is_in_range(reg_addr, + CSRA66X0_BASE, CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(reg_addr, + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR))) { + dev_err(dev, "%s: register address 0x%04X out of range\n", + __func__, reg_addr); + ret = -EINVAL; + goto end; + } + + csra66x0->sysfs_reg_addr = reg_addr; + ret = count; + +end: + return ret; +} + +static ssize_t csra66x0_sysfs_read2reg_addr_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + u32 reg_addr; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + + if (!csra66x0) { + dev_err(dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + + reg_addr = csra66x0->sysfs_reg_addr; + + ret = snprintf(buf, CSRA66X0_SYSFS_ENTRY_MAX_LEN, + "0x%04X\n", reg_addr); + pr_debug("%s: 0x%04X\n", __func__, reg_addr); + + return ret; +} + +static ssize_t csra66x0_sysfs_read2reg_value(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + u32 reg_val, reg_addr; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + struct snd_soc_component *component = csra66x0->component; + + if (!csra66x0) { + dev_err(dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + + reg_addr = csra66x0->sysfs_reg_addr; + if (!(csra66x0_addr_is_in_range(reg_addr, + CSRA66X0_BASE, CSRA66X0_MAX_REGISTER_ADDR) + || csra66x0_addr_is_in_range(reg_addr, + CSRA66X0_COEFF_BASE, CSRA66X0_MAX_COEFF_ADDR))) { + pr_debug("%s: 0x%04X: register address out of range\n", + __func__, reg_addr); + ret = snprintf(buf, CSRA66X0_SYSFS_ENTRY_MAX_LEN, + "0x%04X: register address out of range\n", reg_addr); + goto end; + } + + reg_val = snd_soc_component_read32(component, csra66x0->sysfs_reg_addr); + ret = snprintf(buf, CSRA66X0_SYSFS_ENTRY_MAX_LEN, + "0x%04X: 0x%02X\n", csra66x0->sysfs_reg_addr, reg_val); + pr_debug("%s: 0x%04X: 0x%02X\n", __func__, + csra66x0->sysfs_reg_addr, reg_val); + +end: + return ret; +} + +static ssize_t csra66x0_sysfs_reset(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int val, rc; + struct csra66x0_priv *csra66x0 = dev_get_drvdata(dev); + struct snd_soc_component *component = csra66x0->component; + unsigned int i; + + if (!csra66x0) { + dev_err(dev, "%s: invalid input\n", __func__); + return -EINVAL; + } + rc = kstrtoint(buf, 10, &val); + if (rc) { + dev_err(dev, "%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if (val != SYSFS_RESET) { + dev_err(dev, "%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + pr_debug("%s: reset device\n", __func__); + if (csra66x0->in_cluster) { + /* reset all slave components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + continue; + csra66x0_reset(csra_clust_dev_tbl[i].csra66x0_ptr); + } + /* reset all master components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master) + csra66x0_reset( + csra_clust_dev_tbl[i].csra66x0_ptr); + } + /* recover all components */ + for (i = 0; i < component->card->num_aux_devs; i++) { + if (i >= csra66x0->max_num_cluster_devices) + break; + if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL) + continue; + csra66x0_msconfig(csra_clust_dev_tbl[i].csra66x0_ptr); + csra66x0_init(csra_clust_dev_tbl[i].csra66x0_ptr); + } + } else { + csra66x0_reset(csra66x0); + csra66x0_init(csra66x0); + } + + rc = strnlen(buf, CSRA66X0_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static DEVICE_ATTR(write2reg_addr_value, 0200, NULL, + csra66x0_sysfs_write2reg_addr_value); +static DEVICE_ATTR(read2reg_addr, 0644, csra66x0_sysfs_read2reg_addr_get, + csra66x0_sysfs_read2reg_addr_set); +static DEVICE_ATTR(read2reg_value, 0444, csra66x0_sysfs_read2reg_value, NULL); +static DEVICE_ATTR(reset, 0200, NULL, csra66x0_sysfs_reset); + +static struct attribute *csra66x0_fs_attrs[] = { + &dev_attr_write2reg_addr_value.attr, + &dev_attr_read2reg_addr.attr, + &dev_attr_read2reg_value.attr, + &dev_attr_reset.attr, + NULL, +}; + +static struct attribute_group csra66x0_fs_attrs_group = { + .attrs = csra66x0_fs_attrs, +}; + +static int csra66x0_sysfs_create(struct i2c_client *client, + struct csra66x0_priv *csra66x0) +{ + int rc; + + rc = sysfs_create_group(&client->dev.kobj, &csra66x0_fs_attrs_group); + return rc; +} + +static void csra66x0_sysfs_remove(struct i2c_client *client, + struct csra66x0_priv *csra66x0) +{ + sysfs_remove_group(&client->dev.kobj, &csra66x0_fs_attrs_group); +} + #if IS_ENABLED(CONFIG_I2C) static int csra66x0_i2c_probe(struct i2c_client *client_i2c, const struct i2c_device_id *id) { struct csra66x0_priv *csra66x0; int ret, irq_trigger; +#if IS_ENABLED(CONFIG_DEBUG_FS) char debugfs_dir_name[32]; +#endif csra66x0 = devm_kzalloc(&client_i2c->dev, sizeof(struct csra66x0_priv), GFP_KERNEL); @@ -956,7 +1378,8 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s for debugfs\n", __func__, debugfs_dir_name); - return -ENOMEM; + ret = -ENOMEM; + goto err_debugfs; } csra66x0->debugfs_file_wo = debugfs_create_file( "write_reg_val", S_IFREG | S_IRUGO, csra66x0->debugfs_dir, @@ -966,7 +1389,8 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s/write_reg_val\n", __func__, debugfs_dir_name); - return -ENOMEM; + ret = -ENOMEM; + goto err_debugfs; } csra66x0->debugfs_file_ro = debugfs_create_file( "show_reg_dump", S_IFREG | S_IRUGO, csra66x0->debugfs_dir, @@ -976,15 +1400,16 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, dev_dbg(&client_i2c->dev, "%s: Failed to create /sys/kernel/debug/%s/show_reg_dump\n", __func__, debugfs_dir_name); - return -ENOMEM; + ret = -ENOMEM; + goto err_debugfs; } #endif /* CONFIG_DEBUG_FS */ - /* register codec */ + /* register component */ ret = snd_soc_register_component(&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 component: %d\n", __func__, __LINE__, ret); if (gpio_is_valid(csra66x0->vreg_gpio)) { gpio_set_value(csra66x0->vreg_gpio, 0); @@ -992,12 +1417,30 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c, } return ret; } + + ret = csra66x0_sysfs_create(client_i2c, csra66x0); + if (ret) { + dev_err(&client_i2c->dev, "%s: sysfs creation failed ret=%d\n", + __func__, ret); + goto err_sysfs; + } + return 0; + +err_sysfs: + snd_soc_unregister_component(&client_i2c->dev); + return ret; + +#if IS_ENABLED(CONFIG_DEBUG_FS) +err_debugfs: + debugfs_remove_recursive(csra66x0->debugfs_dir); + return ret; +#endif } -static int csra66x0_i2c_remove(struct i2c_client *i2c_client) +static int csra66x0_i2c_remove(struct i2c_client *client_i2c) { - struct csra66x0_priv *csra66x0 = i2c_get_clientdata(i2c_client); + struct csra66x0_priv *csra66x0 = i2c_get_clientdata(client_i2c); if (csra66x0) { if (gpio_is_valid(csra66x0->vreg_gpio)) { @@ -1008,7 +1451,10 @@ static int csra66x0_i2c_remove(struct i2c_client *i2c_client) debugfs_remove_recursive(csra66x0->debugfs_dir); #endif } + + csra66x0_sysfs_remove(client_i2c, csra66x0); snd_soc_unregister_component(&i2c_client->dev); + return 0; } diff --git a/asoc/codecs/csra66x0/csra66x0.h b/asoc/codecs/csra66x0/csra66x0.h index 2ff651c735..04d9ef836d 100644 --- a/asoc/codecs/csra66x0/csra66x0.h +++ b/asoc/codecs/csra66x0/csra66x0.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #ifndef _CSRA66X0_H @@ -198,7 +198,10 @@ /* RESERVED (CSRA66X0_BASE+0x00C6) */ /* ... */ /* RESERVED (CSRA66X0_BASE+0x00FF) */ -#define CSRA66X0_MAX_REGISTER_ADDR CSRA66X0_DCA_FREEZE_CTRL +#define CSRA66X0_MAX_REGISTER_ADDR CSRA66X0_DCA_FREEZE_CTRL + +#define CSRA66X0_COEFF_BASE 0xD000 +#define CSRA66X0_MAX_COEFF_ADDR 0xD6DF #define EXPECTED_CSRA66X0_CHIP_ID 0x39 @@ -208,9 +211,13 @@ #define SPK_VOLUME_LSB_MSK 0x00FF #define SPK_VOLUME_MSB_MSK 0x0100 -#define CONFIG_STATE 0x0 -#define RUN_STATE 0x1 -#define STDBY_STATE 0x2 +#define SET_CONFIG_STATE 0x0 +#define SET_RUN_STATE 0x1 +#define SET_STDBY_STATE 0x2 + +#define CONFIG_STATE_ID 0x3 +#define WAIT_FOR_CONFIG_STATE_TIMEOUT_MS 2000 +#define SYSFS_RESET 1 #define FAULT_STATUS_INTERNAL 0x01 #define FAULT_STATUS_OTP_INTEGRITY 0x02