diff --git a/asoc/codecs/ep92/ep92.c b/asoc/codecs/ep92/ep92.c index 73110da7ec04..52f5e6d0b98a 100644 --- a/asoc/codecs/ep92/ep92.c +++ b/asoc/codecs/ep92/ep92.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -27,9 +29,10 @@ #include #include "ep92.h" -#define EP92_POLL_INTERVAL_OFF_MSEC 2000 -#define EP92_POLL_INTERVAL_ON_MSEC 100 - +#define EP92_POLL_INTERVAL_OFF_MSEC 200 +#define EP92_POLL_INTERVAL_ON_MSEC 20 +#define EP92_SYSFS_ENTRY_MAX_LEN 64 +#define EP92_HYST_CNT 5 #define EP92_RATES (SNDRV_PCM_RATE_32000 |\ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ @@ -38,71 +41,10 @@ #define EP92_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) -#define EP92_UEVENT_CTRL_NUM_KEYS 8 -#define EP92_UEVENT_AUDIO_NUM_KEYS 9 - static const unsigned int ep92_samp_freq_table[8] = { 32000, 44100, 48000, 88200, 96000, 176400, 192000, 768000 }; -static const char hex_to_char[] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - -struct ep92_uevent_data { - struct kobject kobj; - struct kobj_type ktype; -}; - -static struct kset *ep92_uevent_kset; -static struct ep92_uevent_data *ep92_uevent_ctrl; -static struct ep92_uevent_data *ep92_uevent_audio; - -static void ep92_release_uevent_data(struct kobject *kobj) -{ - struct ep92_uevent_data *data = container_of(kobj, - struct ep92_uevent_data, kobj); - - kfree(data); -} - -static int ep92_init_uevent_data(struct ep92_uevent_data *uevent_data, - char *name) -{ - int ret = -EINVAL; - - if (!uevent_data || !name) - return ret; - - /* Set kset for kobject before initializing the kobject */ - uevent_data->kobj.kset = ep92_uevent_kset; - - /* Initialize kobject and add it to kernel */ - ret = kobject_init_and_add(&uevent_data->kobj, &uevent_data->ktype, - NULL, "%s", name); - if (ret) { - pr_err("%s: error initializing uevent kernel object: %d", - __func__, ret); - kobject_put(&uevent_data->kobj); - return ret; - } - - /* Send kobject add event to the system */ - kobject_uevent(&uevent_data->kobj, KOBJ_ADD); - - return ret; -} - -/** - * ep92_destroy_uevent_data - destroy kernel object. - * - * @uevent_data: uevent data. - */ -static void ep92_destroy_uevent_data(struct ep92_uevent_data *uevent_data) -{ - if (uevent_data) - kobject_put(&uevent_data->kobj); -} - static bool ep92_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { @@ -162,10 +104,25 @@ struct ep92_pdata { struct work_struct read_status_worker; int irq; + int hyst_tx_plug; + int hyst_link_on0; + int hyst_link_on1; + int hyst_link_on2; + int filt_tx_plug; + int filt_link_on0; + int filt_link_on1; + int filt_link_on2; + struct { + u8 tx_info; + u8 video_latency; + } gi; /* General Info block */ + struct { u8 ctl; u8 rx_sel; + u8 ctl2; u8 cec_volume; + u8 link; } gc; /* General Control block */ struct { @@ -178,442 +135,144 @@ struct ep92_pdata { } ai; /* Audio Info block */ u8 old_mode; +#if IS_ENABLED(CONFIG_DEBUG_FS) + struct dentry *debugfs_dir; + struct dentry *debugfs_file_wo; + struct dentry *debugfs_file_ro; +#endif /* CONFIG_DEBUG_FS */ }; -/* - * EP92 Controls - */ - -/* enumerated controls */ -static const char * const ep92_off_on_text[] = {"Off", "On"}; -static const char * const ep92_aud_path_text[] = {"TV", "Speaker"}; -static const char * const ep92_rx_sel_text[] = {"Port 0", "Port 1", "Port 2", - "Res 3", "Res 4", "Res 5", "None", "Res 7"}; -static const char * const ep92_cec_mute_text[] = {"Normal", "Muted"}; - -static const char * const ep92_state_text[] = {"Inactive", "Active"}; -static const char * const ep92_avmute_text[] = {"Normal", "Muted"}; -static const char * const ep92_layout_text[] = {"Layout 0", "Layout 1"}; -static const char * const ep92_mode_text[] = {"LPCM", "Compr"}; - -SOC_ENUM_SINGLE_DECL(ep92_power_enum, EP92_GENERAL_CONTROL_0, - EP92_GC_POWER_SHIFT, ep92_off_on_text); -SOC_ENUM_SINGLE_DECL(ep92_audio_path_enum, EP92_GENERAL_CONTROL_0, - EP92_GC_AUDIO_PATH_SHIFT, ep92_aud_path_text); -SOC_ENUM_SINGLE_DECL(ep92_rx_sel_enum, EP92_GENERAL_CONTROL_1, - EP92_GC_RX_SEL_SHIFT, ep92_rx_sel_text); -SOC_ENUM_SINGLE_DECL(ep92_arc_en_enum, EP92_GENERAL_CONTROL_0, - EP92_GC_ARC_EN_SHIFT, ep92_off_on_text); -SOC_ENUM_SINGLE_DECL(ep92_cec_mute_enum, EP92_GENERAL_CONTROL_0, - EP92_GC_CEC_MUTE_SHIFT, ep92_cec_mute_text); - -SOC_ENUM_SINGLE_DECL(ep92_state_enum, EP92_AUDIO_INFO_SYSTEM_STATUS_0, - EP92_AI_MCLK_ON_SHIFT, ep92_state_text); -SOC_ENUM_SINGLE_DECL(ep92_avmute_enum, EP92_AUDIO_INFO_SYSTEM_STATUS_0, - EP92_AI_AVMUTE_SHIFT, ep92_avmute_text); -SOC_ENUM_SINGLE_DECL(ep92_layout_enum, EP92_AUDIO_INFO_SYSTEM_STATUS_0, - EP92_AI_LAYOUT_SHIFT, ep92_layout_text); -SOC_ENUM_SINGLE_DECL(ep92_mode_enum, EP92_AUDIO_INFO_AUDIO_STATUS, - EP92_AI_STD_ADO_SHIFT, ep92_mode_text); - -/* get/set functions */ -static int ep92_power_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +#if IS_ENABLED(CONFIG_DEBUG_FS) +static int debugfs_codec_open_op(struct inode *inode, struct file *file) { - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = - (val >> e->shift_l) & EP92_2CHOICE_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_off_on_text[ucontrol->value.enumerated.item[0]]); + file->private_data = inode->i_private; return 0; } -static int ep92_power_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int debugfs_get_parameters(char *buf, u32 *param1, int num_of_par) { - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct ep92_pdata *ep92 = snd_soc_codec_get_drvdata(codec); - unsigned int val; + char *token; + int base, cnt; - val = snd_soc_read(codec, e->reg); - val &= ~EP92_GC_POWER_MASK; - val |= (ucontrol->value.enumerated.item[0] & EP92_2CHOICE_MASK) - << e->shift_l; - snd_soc_write(codec, e->reg, val); - ep92->gc.ctl &= ~EP92_GC_POWER_MASK; - ep92->gc.ctl |= val & EP92_GC_POWER_MASK; + 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; - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_off_on_text[ucontrol->value.enumerated.item[0] & - EP92_2CHOICE_MASK]); - return 0; -} + if (kstrtou32(token, base, ¶m1[cnt]) != 0) + return -EINVAL; -static int ep92_audio_path_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & - EP92_2CHOICE_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_aud_path_text[ucontrol->value.enumerated.item[0]]); - return 0; -} - -static int ep92_audio_path_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct ep92_pdata *ep92 = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - val &= ~EP92_GC_AUDIO_PATH_MASK; - val |= (ucontrol->value.enumerated.item[0] & EP92_2CHOICE_MASK) - << e->shift_l; - snd_soc_write(codec, e->reg, val); - ep92->gc.ctl &= ~EP92_GC_AUDIO_PATH_MASK; - ep92->gc.ctl |= val & EP92_GC_AUDIO_PATH_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_aud_path_text[ucontrol->value.enumerated.item[0] & - EP92_2CHOICE_MASK]); - return 0; -} - -static int ep92_cec_mute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & - EP92_2CHOICE_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_cec_mute_text[ucontrol->value.enumerated.item[0]]); - return 0; -} - -static int ep92_cec_mute_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct ep92_pdata *ep92 = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - val &= ~EP92_GC_CEC_MUTE_MASK; - val |= (ucontrol->value.enumerated.item[0] & EP92_2CHOICE_MASK) - << e->shift_l; - snd_soc_write(codec, e->reg, val); - ep92->gc.ctl &= ~EP92_GC_CEC_MUTE_MASK; - ep92->gc.ctl |= val & EP92_GC_CEC_MUTE_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_cec_mute_text[ucontrol->value.enumerated.item[0] & - EP92_2CHOICE_MASK]); - return 0; -} - -static int ep92_arc_en_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & - EP92_2CHOICE_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_off_on_text[ucontrol->value.enumerated.item[0]]); - return 0; -} - -static int ep92_arc_en_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct ep92_pdata *ep92 = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - val &= ~EP92_GC_ARC_EN_MASK; - val |= (ucontrol->value.enumerated.item[0] & EP92_2CHOICE_MASK) - << e->shift_l; - snd_soc_write(codec, e->reg, val); - ep92->gc.ctl &= ~EP92_GC_ARC_EN_MASK; - ep92->gc.ctl |= val & EP92_GC_ARC_EN_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_off_on_text[ucontrol->value.enumerated.item[0] & 0x01]); - return 0; -} - -static int ep92_rx_sel_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & - EP92_GC_RX_SEL_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_rx_sel_text[ucontrol->value.enumerated.item[0]]); - return 0; -} - -static int ep92_rx_sel_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct ep92_pdata *ep92 = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - val &= ~EP92_GC_RX_SEL_MASK; - val |= (ucontrol->value.enumerated.item[0] & EP92_GC_RX_SEL_MASK) - << e->shift_l; - snd_soc_write(codec, e->reg, val); - ep92->gc.rx_sel &= ~EP92_GC_RX_SEL_MASK; - ep92->gc.rx_sel |= val & EP92_GC_RX_SEL_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_rx_sel_text[ucontrol->value.enumerated.item[0] & - EP92_GC_RX_SEL_MASK]); - return 0; -} - -static int ep92_cec_volume_get(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_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, mc->reg); - ucontrol->value.integer.value[0] = (val >> mc->shift) & - EP92_GC_CEC_VOLUME_MASK; - - pr_debug("%s: volume = %ld\n", __func__, - ucontrol->value.integer.value[0]); - return 0; -} - -static int ep92_cec_volume_put(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_soc_kcontrol_codec(kcontrol); - struct ep92_pdata *ep92 = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - val = ucontrol->value.integer.value[0] & EP92_GC_CEC_VOLUME_MASK; - if (val > EP92_GC_CEC_VOLUME_MAX) - val = EP92_GC_CEC_VOLUME_MAX; - snd_soc_write(codec, mc->reg, val); - ep92->gc.cec_volume = val; - - pr_debug("%s: volume = %ld\n", __func__, - ucontrol->value.integer.value[0]); - return 0; -} - -static int ep92_state_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & - EP92_2CHOICE_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_state_text[ucontrol->value.enumerated.item[0]]); - return 0; -} - -static int ep92_avmute_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & - EP92_2CHOICE_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_avmute_text[ucontrol->value.enumerated.item[0]]); - return 0; -} - -static int ep92_layout_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & - EP92_2CHOICE_MASK; - - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_layout_text[ucontrol->value.enumerated.item[0]]); - return 0; -} - -static int ep92_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct ep92_pdata *ep92 = snd_soc_codec_get_drvdata(codec); - unsigned int val; - - val = snd_soc_read(codec, e->reg); - if (val & EP92_AI_STD_ADO_MASK) { - val = snd_soc_read(codec, EP92_AUDIO_INFO_CHANNEL_STATUS_0); - if (val & EP92_AI_NPCM_MASK) - ucontrol->value.enumerated.item[0] = 1; /* Compr */ - else - ucontrol->value.enumerated.item[0] = 0; /* LPCM */ - } else if (val & EP92_AI_HBR_ADO_MASK) { - ucontrol->value.enumerated.item[0] = 1; /* Compr */ - } else { - ucontrol->value.enumerated.item[0] = ep92->old_mode; + token = strsep(&buf, " "); + } else { + return -EINVAL; + } } - pr_debug("%s: item = %d (%s)\n", __func__, - ucontrol->value.enumerated.item[0], - ep92_mode_text[ucontrol->value.enumerated.item[0]]); return 0; } -static int ep92_rate_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static ssize_t debugfs_codec_write_op(struct file *filp, + const char __user *ubuf, size_t cnt, loff_t *ppos) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; + struct ep92_pdata *ep92 = (struct ep92_pdata *) filp->private_data; + struct snd_soc_codec *codec = ep92->codec; + char lbuf[32]; + int rc; + u32 param[2]; - val = snd_soc_read(codec, mc->reg); - val &= EP92_AI_RATE_MASK; - val = ep92_samp_freq_table[val]; - ucontrol->value.integer.value[0] = val; - - pr_debug("%s: rate = %ld\n", __func__, - ucontrol->value.integer.value[0]); - return 0; + 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] < EP92_ISP_MODE_ENTER_ISP) + || (param[0] > EP92_GENERAL_CONTROL_4)) { + dev_err(codec->dev, "%s: reg address 0x%02X out of range\n", + __func__, param[0]); + return -EINVAL; + } + if ((param[1] < 0) || (param[1] > 255)) { + dev_err(codec->dev, "%s: reg data 0x%02X out of range\n", + __func__, param[1]); + return -EINVAL; + } + if (rc == 0) { + rc = cnt; + dev_info(codec->dev, "%s: reg[0x%02X]=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%02X failed\n", + __func__, param[0]); + } + return rc; } -static int ep92_ch_count_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static ssize_t debugfs_ep92_reg_show(struct snd_soc_codec *codec, + char __user *ubuf, size_t count, loff_t *ppos) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[20]; - val = snd_soc_read(codec, mc->reg) & EP92_AI_CH_COUNT_MASK; - /* mapping is ch_count = reg_val + 1, with exception: 0 = unknown */ - if (val > 0) - val += 1; + if (!ubuf || !ppos || !codec || *ppos < 0) + return -EINVAL; - ucontrol->value.integer.value[0] = val; + for (i = (int) *ppos / 11; i <= EP92_MAX_REGISTER_ADDR; i++) { + reg_val = snd_soc_read(codec, i); + len = snprintf(tmp_buf, 20, "0x%02X: 0x%02X\n", i, + (reg_val & 0xFF)); + if ((total + len) > count) + 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; + } - pr_debug("%s: ch_count = %ld\n", __func__, - ucontrol->value.integer.value[0]); - return 0; +copy_err: + return total; } -static int ep92_ch_alloc_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static ssize_t debugfs_codec_read_op(struct file *filp, + char __user *ubuf, size_t cnt, loff_t *ppos) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int val; + struct ep92_pdata *ep92 = (struct ep92_pdata *) filp->private_data; + struct snd_soc_codec *codec = ep92->codec; + ssize_t ret_cnt; - val = snd_soc_read(codec, mc->reg); - ucontrol->value.integer.value[0] = (val >> mc->shift) & - EP92_AI_CH_ALLOC_MASK; - - pr_debug("%s: ch_alloc = 0x%02lx\n", __func__, - ucontrol->value.integer.value[0]); - return 0; + if (!filp || !ppos || !ubuf || *ppos < 0) + return -EINVAL; + ret_cnt = debugfs_ep92_reg_show(codec, ubuf, cnt, ppos); + return ret_cnt; } -static const struct snd_kcontrol_new ep92_snd_controls[] = { - - SOC_ENUM_EXT("HDMI_IN POWER", ep92_power_enum, - ep92_power_get, ep92_power_put), - SOC_ENUM_EXT("HDMI_IN AUDIO_PATH", ep92_audio_path_enum, - ep92_audio_path_get, ep92_audio_path_put), - SOC_ENUM_EXT("HDMI_IN RX_SEL", ep92_rx_sel_enum, - ep92_rx_sel_get, ep92_rx_sel_put), - SOC_ENUM_EXT("HDMI_IN ARC_EN", ep92_arc_en_enum, - ep92_arc_en_get, ep92_arc_en_put), - SOC_ENUM_EXT("HDMI_IN CEC_MUTE", ep92_cec_mute_enum, - ep92_cec_mute_get, ep92_cec_mute_put), - SOC_SINGLE_EXT("HDMI_IN CEC_VOLUME", EP92_GENERAL_CONTROL_3, - EP92_GC_CEC_VOLUME_MIN, EP92_GC_CEC_VOLUME_MAX, - 0, ep92_cec_volume_get, ep92_cec_volume_put), - - SOC_ENUM_EXT("HDMI_IN STATE", ep92_state_enum, ep92_state_get, NULL), - SOC_ENUM_EXT("HDMI_IN AVMUTE", ep92_avmute_enum, ep92_avmute_get, NULL), - SOC_ENUM_EXT("HDMI_IN LAYOUT", ep92_layout_enum, ep92_layout_get, NULL), - SOC_ENUM_EXT("HDMI_IN MODE", ep92_mode_enum, ep92_mode_get, NULL), - SOC_SINGLE_EXT("HDMI_IN RATE", EP92_AUDIO_INFO_AUDIO_STATUS, - EP92_AI_RATE_MIN, EP92_AI_RATE_MAX, 0, ep92_rate_get, NULL), - SOC_SINGLE_EXT("HDMI_IN CH_COUNT", EP92_AUDIO_INFO_ADO_INFO_FRAME_1, - EP92_AI_CH_COUNT_MIN, EP92_AI_CH_COUNT_MAX, - 0, ep92_ch_count_get, NULL), - SOC_SINGLE_EXT("HDMI_IN CH_ALLOC", EP92_AUDIO_INFO_ADO_INFO_FRAME_4, - EP92_AI_CH_ALLOC_MIN, EP92_AI_CH_ALLOC_MAX, 0, - ep92_ch_alloc_get, NULL), +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 */ + +static int ep92_send_uevent(struct ep92_pdata *ep92, char *event) +{ + char *env[] = { event, NULL }; + + if (!event || !ep92) + return -EINVAL; + + return kobject_uevent_env(&ep92->codec->dev->kobj, KOBJ_CHANGE, env); +} static int ep92_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -669,328 +328,208 @@ static struct snd_soc_dai_driver ep92_dai[] = { }, }; -static const char * const ep92_event_power_text[] = { - "POWER=Off", - "POWER=On", -}; - -static const char * const ep92_event_arc_en_text[] = { - "ARC_EN=Off", - "ARC_EN=On", -}; - -static const char * const ep92_event_audio_path_text[] = { - "AUDIO_PATH=TV", - "AUDIO_PATH=Speaker", -}; - -static const char *const ep92_event_rx_sel_text[] = { - "RX_SEL=Port0", - "RX_SEL=Port1", - "RX_SEL=Port2", - "RX_SEL=Res3", - "RX_SEL=Res4", - "RX_SEL=Res5", - "RX_SEL=None", - "RX_SEL=Res7", -}; - -static const char *const ep92_event_cec_mute_text[] = { - "CEC_MUTE=Normal", - "CEC_MUTE=Muted", -}; - -static int ep92_send_uevent_ctrl(struct ep92_pdata *ep92) -{ - char *env[EP92_UEVENT_CTRL_NUM_KEYS]; - u8 idx = 0; - u8 cec_volume; - char cec_volume_text[] = "CEC_VOLUME=0x00"; - char *ptr; - - env[idx++] = "HDMI_CONTROL=TRUE"; - - if ((ep92->gc.ctl >> EP92_GC_POWER_SHIFT) & - EP92_2CHOICE_MASK) - env[idx++] = (char *)ep92_event_power_text[1]; - else - env[idx++] = (char *)ep92_event_power_text[0]; - - if (ep92->gc.ctl & EP92_2CHOICE_MASK) - env[idx++] = (char *)ep92_event_arc_en_text[1]; - else - env[idx++] = (char *)ep92_event_arc_en_text[0]; - - if ((ep92->gc.ctl >> EP92_GC_AUDIO_PATH_SHIFT) & - EP92_2CHOICE_MASK) - env[idx++] = (char *)ep92_event_audio_path_text[1]; - else - env[idx++] = (char *)ep92_event_audio_path_text[0]; - - switch (ep92->gc.rx_sel & EP92_GC_RX_SEL_MASK) { - case 0: - env[idx++] = (char *)ep92_event_rx_sel_text[0]; - break; - case 1: - env[idx++] = (char *)ep92_event_rx_sel_text[1]; - break; - case 2: - env[idx++] = (char *)ep92_event_rx_sel_text[2]; - break; - case 3: - env[idx++] = (char *)ep92_event_rx_sel_text[3]; - break; - case 4: - env[idx++] = (char *)ep92_event_rx_sel_text[4]; - break; - case 5: - env[idx++] = (char *)ep92_event_rx_sel_text[5]; - break; - case 6: - env[idx++] = (char *)ep92_event_rx_sel_text[6]; - break; - case 7: - env[idx++] = (char *)ep92_event_rx_sel_text[7]; - break; - default: - env[idx++] = (char *)ep92_event_rx_sel_text[0]; - } - - if ((ep92->gc.ctl >> EP92_GC_CEC_MUTE_SHIFT) & - EP92_2CHOICE_MASK) - env[idx++] = (char *)ep92_event_cec_mute_text[1]; - else - env[idx++] = (char *)ep92_event_cec_mute_text[0]; - - ptr = &cec_volume_text[strlen(cec_volume_text)-2]; - cec_volume = (ep92->ai.ca) & EP92_GC_CEC_VOLUME_MASK; - *ptr++ = hex_to_char[(cec_volume >> 4) & 0x0f]; - *ptr++ = hex_to_char[cec_volume & 0x0f]; - env[idx++] = (char *)cec_volume_text; - - env[idx++] = NULL; - - if (idx != EP92_UEVENT_CTRL_NUM_KEYS) { - pr_err("ep92 wrong number of audio uevent keys (%d).\n", - idx); - return -EINVAL; - } - - return kobject_uevent_env(&ep92_uevent_ctrl->kobj, KOBJ_CHANGE, env); -} - -static const char * const ep92_event_state_text[] = { - "STATE=Inactive", - "STATE=Active", -}; - -static const char *const ep92_event_rate_text[] = { - "RATE=32000", - "RATE=44100", - "RATE=48000", - "RATE=88200", - "RATE=96000", - "RATE=176400", - "RATE=192000", - "RATE=768000", -}; - -static const char *const ep92_event_format_text[] = { - "FORMAT=LPCM", - "FORMAT=Compr", -}; - -static const char *const ep92_event_layout_text[] = { - "LAYOUT=2ch", - "LAYOUT=8ch", -}; - -static const char *const ep92_event_avmute_text[] = { - "AVMUTE=Normal", - "AVMUTE=Muted", -}; - -static const char *const ep92_event_ch_count_text[] = { - "CH_COUNT=One", - "CH_COUNT=Two", - "CH_COUNT=Three", - "CH_COUNT=Four", - "CH_COUNT=Five", - "CH_COUNT=Six", - "CH_COUNT=Seven", - "CH_COUNT=Eight", -}; - -static int ep92_send_uevent_audio(struct ep92_pdata *ep92) -{ - char *env[EP92_UEVENT_AUDIO_NUM_KEYS]; - u8 idx = 0; - u8 ch_alloc; - char ch_alloc_text[] = "CH_ALLOC=0x00"; - char *ptr; - - env[idx++] = "HDMI_FMT_UPDATE=TRUE"; - - if (((ep92->ai.system_status_0 >> EP92_AI_MCLK_ON_SHIFT) & - EP92_2CHOICE_MASK) == EP92_STATUS_AUDIO_ACTIVE) - env[idx++] = (char *)ep92_event_state_text[1]; - else - env[idx++] = (char *)ep92_event_state_text[0]; - - switch (ep92->ai.audio_status & EP92_AI_RATE_MASK) { - case 0: - env[idx++] = (char *)ep92_event_rate_text[0]; - break; - case 1: - env[idx++] = (char *)ep92_event_rate_text[1]; - break; - case 2: - env[idx++] = (char *)ep92_event_rate_text[2]; - break; - case 3: - env[idx++] = (char *)ep92_event_rate_text[3]; - break; - case 4: - env[idx++] = (char *)ep92_event_rate_text[4]; - break; - case 5: - env[idx++] = (char *)ep92_event_rate_text[5]; - break; - case 6: - env[idx++] = (char *)ep92_event_rate_text[6]; - break; - case 7: - env[idx++] = (char *)ep92_event_rate_text[7]; - break; - default: - env[idx++] = (char *)ep92_event_rate_text[2]; - } - - if (ep92->old_mode) - env[idx++] = (char *)ep92_event_format_text[1]; - else - env[idx++] = (char *)ep92_event_format_text[0]; - - if (ep92->ai.system_status_0 & EP92_2CHOICE_MASK) - env[idx++] = (char *)ep92_event_layout_text[1]; - else - env[idx++] = (char *)ep92_event_layout_text[0]; - - if ((ep92->ai.system_status_0 >> EP92_AI_AVMUTE_SHIFT) & - EP92_2CHOICE_MASK) - env[idx++] = (char *)ep92_event_avmute_text[1]; - else - env[idx++] = (char *)ep92_event_avmute_text[0]; - - /* cc==0 signals n/a and is treated as stereo */ - switch (ep92->ai.cc & EP92_AI_CH_COUNT_MASK) { - case 0: - env[idx++] = (char *)ep92_event_ch_count_text[1]; - break; - case 1: - env[idx++] = (char *)ep92_event_ch_count_text[1]; - break; - case 2: - env[idx++] = (char *)ep92_event_ch_count_text[2]; - break; - case 3: - env[idx++] = (char *)ep92_event_ch_count_text[3]; - break; - case 4: - env[idx++] = (char *)ep92_event_ch_count_text[4]; - break; - case 5: - env[idx++] = (char *)ep92_event_ch_count_text[5]; - break; - case 6: - env[idx++] = (char *)ep92_event_ch_count_text[6]; - break; - case 7: - env[idx++] = (char *)ep92_event_ch_count_text[7]; - break; - default: - env[idx++] = (char *)ep92_event_ch_count_text[1]; - } - - ptr = &ch_alloc_text[strlen(ch_alloc_text)-2]; - ch_alloc = (ep92->ai.ca) & EP92_AI_CH_ALLOC_MASK; - *ptr++ = hex_to_char[(ch_alloc >> 4) & 0x0f]; - *ptr++ = hex_to_char[ch_alloc & 0x0f]; - env[idx++] = (char *)ch_alloc_text; - - env[idx++] = NULL; - - if (idx != EP92_UEVENT_AUDIO_NUM_KEYS) { - pr_err("ep92 wrong number of audio uevent keys (%d).\n", - idx); - return -EINVAL; - } - - return kobject_uevent_env(&ep92_uevent_audio->kobj, KOBJ_CHANGE, env); -} - static void ep92_read_general_control(struct snd_soc_codec *codec, struct ep92_pdata *ep92) { u8 old, change; - bool send_uevent = false; + int val; + + old = ep92->gi.tx_info; + ep92->gi.tx_info = snd_soc_read(codec, EP92_BI_GENERAL_INFO_0); + if (ep92->gi.tx_info == 0xff) { + pr_debug("ep92 EP92_BI_GENERAL_INFO_0 read 0xff\n"); + ep92->gi.tx_info = old; + } + /* implement hysteresis to prevent events on glitches */ + if (ep92->gi.tx_info & EP92_GI_TX_HOT_PLUG_MASK) { + if (ep92->hyst_tx_plug < EP92_HYST_CNT) { + ep92->hyst_tx_plug++; + if ((ep92->hyst_tx_plug == EP92_HYST_CNT) && + (ep92->filt_tx_plug == 0)) { + ep92->filt_tx_plug = 1; + pr_debug("ep92 out_plug changed to 1\n"); + ep92_send_uevent(ep92, + "EP92EVT_OUT_PLUG=CONNECTED"); + } + } + } else { + if (ep92->hyst_tx_plug > 0) { + ep92->hyst_tx_plug--; + if ((ep92->hyst_tx_plug == 0) && + (ep92->filt_tx_plug == 1)) { + ep92->filt_tx_plug = 0; + pr_debug("ep92 out_plug changed to 0\n"); + ep92_send_uevent(ep92, + "EP92EVT_OUT_PLUG=DISCONNECTED"); + } + } + } + + old = ep92->gi.video_latency; + ep92->gi.video_latency = snd_soc_read(codec, EP92_BI_GENERAL_INFO_4); + if (ep92->gi.video_latency == 0xff) { + pr_debug("ep92 EP92_BI_GENERAL_INFO_4 read 0xff\n"); + ep92->gi.video_latency = old; + } + change = ep92->gi.video_latency ^ old; + if (change & EP92_GI_VIDEO_LATENCY_MASK) { + val = ep92->gi.video_latency; + if (val > 0) + val = (val - 1) * 2; + pr_debug("ep92 video latency changed to %d\n", val); + ep92_send_uevent(ep92, "EP92EVT_VIDEO_LATENCY=CHANGED"); + } old = ep92->gc.ctl; ep92->gc.ctl = snd_soc_read(codec, EP92_GENERAL_CONTROL_0); + if (ep92->gc.ctl == 0xff) { + pr_debug("ep92 EP92_GENERAL_CONTROL_0 read 0xff\n"); + ep92->gc.ctl = old; + } change = ep92->gc.ctl ^ old; if (change & EP92_GC_POWER_MASK) { - pr_debug("ep92 power changed to %d (%s)\n", - (ep92->gc.ctl >> EP92_GC_POWER_SHIFT) & - EP92_2CHOICE_MASK, - ep92_off_on_text[(ep92->gc.ctl - >> EP92_GC_POWER_SHIFT) & EP92_2CHOICE_MASK]); - send_uevent = true; + val = (ep92->gc.ctl >> EP92_GC_POWER_SHIFT) & + EP92_2CHOICE_MASK; + pr_debug("ep92 power changed to %d\n", val); + if (val) + ep92_send_uevent(ep92, "EP92EVT_POWER=ON"); + else + ep92_send_uevent(ep92, "EP92EVT_POWER=OFF"); } if (change & EP92_GC_AUDIO_PATH_MASK) { - pr_debug("ep92 audio_path changed to %d (%s)\n", - (ep92->gc.ctl >> EP92_GC_AUDIO_PATH_SHIFT) & - EP92_2CHOICE_MASK, - ep92_aud_path_text[(ep92->gc.ctl - >> EP92_GC_AUDIO_PATH_SHIFT) & EP92_2CHOICE_MASK]); - send_uevent = true; + val = (ep92->gc.ctl >> EP92_GC_AUDIO_PATH_SHIFT) & + EP92_2CHOICE_MASK; + pr_debug("ep92 audio_path changed to %d\n", val); + if (val) + ep92_send_uevent(ep92, "EP92EVT_AUDIO_PATH=TV"); + else + ep92_send_uevent(ep92, "EP92EVT_AUDIO_PATH=SPEAKER"); } if (change & EP92_GC_CEC_MUTE_MASK) { - pr_debug("ep92 cec_mute changed to %d (%s)\n", - (ep92->gc.ctl >> EP92_GC_CEC_MUTE_SHIFT) & - EP92_2CHOICE_MASK, - ep92_cec_mute_text[(ep92->gc.ctl - >> EP92_GC_CEC_MUTE_SHIFT) & EP92_2CHOICE_MASK]); - send_uevent = true; + val = (ep92->gc.ctl >> EP92_GC_CEC_MUTE_SHIFT) & + EP92_2CHOICE_MASK; + pr_debug("ep92 cec_mute changed to %d\n", val); + if (val) + ep92_send_uevent(ep92, "EP92EVT_CEC_MUTE=NORMAL"); + else + ep92_send_uevent(ep92, "EP92EVT_CEC_MUTE=MUTED"); } if (change & EP92_GC_ARC_EN_MASK) { - pr_debug("ep92 arc_en changed to %d (%s)\n", - ep92->gc.ctl & EP92_2CHOICE_MASK, - ep92_off_on_text[ep92->gc.ctl & EP92_2CHOICE_MASK]); - send_uevent = true; + val = ep92->gc.ctl & EP92_2CHOICE_MASK; + pr_debug("ep92 arc_en changed to %d\n", val); + if (val) + ep92_send_uevent(ep92, "EP92EVT_ARC_EN=ON"); + else + ep92_send_uevent(ep92, "EP92EVT_ARC_EN=OFF"); } old = ep92->gc.rx_sel; ep92->gc.rx_sel = snd_soc_read(codec, EP92_GENERAL_CONTROL_1); + if (ep92->gc.rx_sel == 0xff) { + pr_debug("ep92 EP92_GENERAL_CONTROL_1 read 0xff\n"); + ep92->gc.rx_sel = old; + } change = ep92->gc.rx_sel ^ old; if (change & EP92_GC_RX_SEL_MASK) { - pr_debug("ep92 rx_sel changed to %d (%s)\n", - ep92->gc.rx_sel & EP92_GC_RX_SEL_MASK, - ep92_rx_sel_text[ep92->gc.rx_sel & - EP92_GC_RX_SEL_MASK]); - send_uevent = true; + val = ep92->gc.rx_sel & EP92_GC_RX_SEL_MASK; + pr_debug("ep92 rx_sel changed to %d\n", val); + ep92_send_uevent(ep92, "EP92EVT_SRC_SEL=CHANGED"); } old = ep92->gc.cec_volume; ep92->gc.cec_volume = snd_soc_read(codec, EP92_GENERAL_CONTROL_3); + if (ep92->gc.cec_volume == 0xff) { + pr_debug("ep92 EP92_GENERAL_CONTROL_3 read 0xff\n"); + ep92->gc.cec_volume = old; + } change = ep92->gc.cec_volume ^ old; if (change & EP92_GC_CEC_VOLUME_MASK) { - pr_debug("ep92 cec_volume changed to %d\n", - ep92->gc.cec_volume & EP92_GC_CEC_VOLUME_MASK); - send_uevent = true; + val = ep92->gc.cec_volume & EP92_GC_CEC_VOLUME_MASK; + pr_debug("ep92 cec_volume changed to %d\n", val); + ep92_send_uevent(ep92, "EP92EVT_CEC_VOLUME=CHANGED"); } - if (send_uevent) - ep92_send_uevent_ctrl(ep92); + old = ep92->gc.link; + ep92->gc.link = snd_soc_read(codec, EP92_GENERAL_CONTROL_4); + if (ep92->gc.link == 0xff) { + pr_debug("ep92 EP92_GENERAL_CONTROL_4 read 0xff\n"); + ep92->gc.link = old; + } + + /* implement hysteresis to prevent events on glitches */ + if (ep92->gc.link & EP92_GC_LINK_ON0_MASK) { + if (ep92->hyst_link_on0 < EP92_HYST_CNT) { + ep92->hyst_link_on0++; + if ((ep92->hyst_link_on0 == EP92_HYST_CNT) && + (ep92->filt_link_on0 == 0)) { + ep92->filt_link_on0 = 1; + pr_debug("ep92 link_on0 changed to 1\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON0=CONNECTED"); + } + } + } else { + if (ep92->hyst_link_on0 > 0) { + ep92->hyst_link_on0--; + if ((ep92->hyst_link_on0 == 0) && + (ep92->filt_link_on0 == 1)) { + ep92->filt_link_on0 = 0; + pr_debug("ep92 link_on0 changed to 0\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON0=DISCONNECTED"); + } + } + } + + /* implement hysteresis to prevent events on glitches */ + if (ep92->gc.link & EP92_GC_LINK_ON1_MASK) { + if (ep92->hyst_link_on1 < EP92_HYST_CNT) { + ep92->hyst_link_on1++; + if ((ep92->hyst_link_on1 == EP92_HYST_CNT) && + (ep92->filt_link_on1 == 0)) { + ep92->filt_link_on1 = 1; + pr_debug("ep92 link_on1 changed to 1\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON1=CONNECTED"); + } + } + } else { + if (ep92->hyst_link_on1 > 0) { + ep92->hyst_link_on1--; + if ((ep92->hyst_link_on1 == 0) && + (ep92->filt_link_on1 == 1)) { + ep92->filt_link_on1 = 0; + pr_debug("ep92 link_on1 changed to 0\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON1=DISCONNECTED"); + } + } + } + + /* implement hysteresis to prevent events on glitches */ + if (ep92->gc.link & EP92_GC_LINK_ON2_MASK) { + if (ep92->hyst_link_on2 < EP92_HYST_CNT) { + ep92->hyst_link_on2++; + if ((ep92->hyst_link_on2 == EP92_HYST_CNT) && + (ep92->filt_link_on2 == 0)) { + ep92->filt_link_on2 = 1; + pr_debug("ep92 link_on2 changed to 1\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON2=CONNECTED"); + } + } + } else { + if (ep92->hyst_link_on2 > 0) { + ep92->hyst_link_on2--; + if ((ep92->hyst_link_on2 == 0) && + (ep92->filt_link_on2 == 1)) { + ep92->filt_link_on2 = 0; + pr_debug("ep92 link_on2 changed to 0\n"); + ep92_send_uevent(ep92, + "EP92EVT_LINK_ON2=DISCONNECTED"); + } + } + } } static void ep92_read_audio_info(struct snd_soc_codec *codec, @@ -1003,34 +542,36 @@ static void ep92_read_audio_info(struct snd_soc_codec *codec, old = ep92->ai.system_status_0; ep92->ai.system_status_0 = snd_soc_read(codec, EP92_AUDIO_INFO_SYSTEM_STATUS_0); + if (ep92->ai.system_status_0 == 0xff) { + pr_debug("ep92 EP92_AUDIO_INFO_SYSTEM_STATUS_0 read 0xff\n"); + ep92->ai.system_status_0 = old; + } change = ep92->ai.system_status_0 ^ old; if (change & EP92_AI_MCLK_ON_MASK) { - pr_debug("ep92 status changed to %d (%s)\n", + pr_debug("ep92 status changed to %d\n", (ep92->ai.system_status_0 >> EP92_AI_MCLK_ON_SHIFT) & - EP92_2CHOICE_MASK, - ep92_state_text[(ep92->ai.system_status_0 - >> EP92_AI_MCLK_ON_SHIFT) & EP92_2CHOICE_MASK]); + EP92_2CHOICE_MASK); send_uevent = true; } if (change & EP92_AI_AVMUTE_MASK) { - pr_debug("ep92 avmute changed to %d (%s)\n", + pr_debug("ep92 avmute changed to %d\n", (ep92->ai.system_status_0 >> EP92_AI_AVMUTE_SHIFT) & - EP92_2CHOICE_MASK, - ep92_avmute_text[(ep92->ai.system_status_0 - >> EP92_AI_AVMUTE_SHIFT) & EP92_2CHOICE_MASK]); + EP92_2CHOICE_MASK); send_uevent = true; } if (change & EP92_AI_LAYOUT_MASK) { - pr_debug("ep92 layout changed to %d (%s)\n", - (ep92->ai.system_status_0) & EP92_2CHOICE_MASK, - ep92_layout_text[(ep92->ai.system_status_0) & - EP92_2CHOICE_MASK]); + pr_debug("ep92 layout changed to %d\n", + (ep92->ai.system_status_0) & EP92_2CHOICE_MASK); send_uevent = true; } old = ep92->ai.audio_status; ep92->ai.audio_status = snd_soc_read(codec, EP92_AUDIO_INFO_AUDIO_STATUS); + if (ep92->ai.audio_status == 0xff) { + pr_debug("ep92 EP92_AUDIO_INFO_AUDIO_STATUS read 0xff\n"); + ep92->ai.audio_status = old; + } change = ep92->ai.audio_status ^ old; if (change & EP92_AI_RATE_MASK) { pr_debug("ep92 rate changed to %d\n", @@ -1041,8 +582,13 @@ static void ep92_read_audio_info(struct snd_soc_codec *codec, new_mode = ep92->old_mode; if (ep92->ai.audio_status & EP92_AI_STD_ADO_MASK) { + old = ep92->ai.cs[0]; ep92->ai.cs[0] = snd_soc_read(codec, EP92_AUDIO_INFO_CHANNEL_STATUS_0); + if (ep92->ai.cs[0] == 0xff) { + pr_debug("ep92 EP92_AUDIO_INFO_CHANNEL_STATUS_0 read 0xff\n"); + ep92->ai.cs[0] = old; + } if (ep92->ai.cs[0] & EP92_AI_NPCM_MASK) new_mode = 1; /* Compr */ else @@ -1051,14 +597,17 @@ static void ep92_read_audio_info(struct snd_soc_codec *codec, new_mode = 1; /* Compr */ if (ep92->old_mode != new_mode) { - pr_debug("ep92 mode changed to %d (%s)\n", new_mode, - ep92_mode_text[new_mode]); + pr_debug("ep92 mode changed to %d\n", new_mode); send_uevent = true; } ep92->old_mode = new_mode; old = ep92->ai.cc; ep92->ai.cc = snd_soc_read(codec, EP92_AUDIO_INFO_ADO_INFO_FRAME_1); + if (ep92->ai.cc == 0xff) { + pr_debug("ep92 EP92_AUDIO_INFO_ADO_INFO_FRAME_1 read 0xff\n"); + ep92->ai.cc = old; + } change = ep92->ai.cc ^ old; if (change & EP92_AI_CH_COUNT_MASK) { pr_debug("ep92 ch_count changed to %d (%d)\n", @@ -1070,6 +619,10 @@ static void ep92_read_audio_info(struct snd_soc_codec *codec, old = ep92->ai.ca; ep92->ai.ca = snd_soc_read(codec, EP92_AUDIO_INFO_ADO_INFO_FRAME_4); + if (ep92->ai.ca == 0xff) { + pr_debug("ep92 EP92_AUDIO_INFO_ADO_INFO_FRAME_4 read 0xff\n"); + ep92->ai.ca = old; + } change = ep92->ai.ca ^ old; if (change & EP92_AI_CH_ALLOC_MASK) { pr_debug("ep92 ch_alloc changed to 0x%02x\n", @@ -1078,7 +631,7 @@ static void ep92_read_audio_info(struct snd_soc_codec *codec, } if (send_uevent) - ep92_send_uevent_audio(ep92); + ep92_send_uevent(ep92, "EP92EVT_AUDIO=MEDIA_CONFIG_CHANGE"); } static void ep92_init(struct snd_soc_codec *codec, struct ep92_pdata *ep92) @@ -1117,10 +670,6 @@ static struct snd_soc_codec_driver soc_codec_drv_ep92 = { .probe = ep92_probe, .remove = ep92_remove, .get_regmap = ep92_get_regmap, - .component_driver = { - .controls = ep92_snd_controls, - .num_controls = ARRAY_SIZE(ep92_snd_controls), - }, }; static struct regmap_config ep92_regmap_config = { @@ -1205,11 +754,712 @@ static const struct of_device_id ep92_of_match[] = { }; MODULE_DEVICE_TABLE(of, ep92_of_match); +static ssize_t ep92_sysfs_rda_audio_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = (ep92->ai.system_status_0 & EP92_AI_MCLK_ON_MASK) >> + EP92_AI_MCLK_ON_SHIFT; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_format(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->old_mode; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_rate(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92_samp_freq_table[(ep92->ai.audio_status) & + EP92_AI_RATE_MASK]; + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_layout(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = (ep92->ai.system_status_0 & EP92_AI_LAYOUT_MASK) >> + EP92_AI_LAYOUT_SHIFT; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_ch_count(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->ai.cc & EP92_AI_CH_COUNT_MASK; + /* mapping is ch_count = reg_val + 1, with exception: 0 = unknown */ + if (val > 0) + val += 1; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_audio_ch_alloc(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->ai.ca & EP92_AI_CH_ALLOC_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_avmute(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + + val = (ep92->ai.system_status_0 >> EP92_AI_AVMUTE_SHIFT) & + EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_link_on0(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->filt_link_on0; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_link_on1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->filt_link_on1; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_link_on2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->filt_link_on2; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_out_plug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->filt_tx_plug; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_video_latency(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->gi.video_latency & EP92_GI_VIDEO_LATENCY_MASK; + if (val > 0) + val = (val - 1) * 2; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_rda_arc_disable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = (ep92->gc.ctl2 >> EP92_GC_ARC_DIS_SHIFT) & + EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_arc_disable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + pr_err("%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_read(ep92->codec, EP92_GENERAL_CONTROL_2); + reg &= ~EP92_GC_ARC_DIS_MASK; + reg |= ((val << EP92_GC_ARC_DIS_SHIFT) & EP92_GC_ARC_DIS_MASK); + snd_soc_write(ep92->codec, EP92_GENERAL_CONTROL_2, reg); + ep92->gc.ctl2 &= ~EP92_GC_ARC_DIS_MASK; + ep92->gc.ctl2 |= (val << EP92_GC_ARC_DIS_SHIFT) & EP92_GC_ARC_DIS_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_power(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = (ep92->gc.ctl >> EP92_GC_POWER_SHIFT) & EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_power(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + pr_err("%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_read(ep92->codec, EP92_GENERAL_CONTROL_0); + reg &= ~EP92_GC_POWER_MASK; + reg |= (val << EP92_GC_POWER_SHIFT) & EP92_GC_POWER_MASK; + snd_soc_write(ep92->codec, EP92_GENERAL_CONTROL_0, reg); + ep92->gc.ctl &= ~EP92_GC_POWER_MASK; + ep92->gc.ctl |= (val << EP92_GC_POWER_SHIFT) & EP92_GC_POWER_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_audio_path(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = (ep92->gc.ctl >> EP92_GC_AUDIO_PATH_SHIFT) & EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_audio_path(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + pr_err("%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_read(ep92->codec, EP92_GENERAL_CONTROL_0); + reg &= ~EP92_GC_AUDIO_PATH_MASK; + reg |= (val << EP92_GC_AUDIO_PATH_SHIFT) & EP92_GC_AUDIO_PATH_MASK; + snd_soc_write(ep92->codec, EP92_GENERAL_CONTROL_0, reg); + ep92->gc.ctl &= ~EP92_GC_AUDIO_PATH_MASK; + ep92->gc.ctl |= (val << EP92_GC_AUDIO_PATH_SHIFT) & + EP92_GC_AUDIO_PATH_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_src_sel(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = ep92->gc.rx_sel & EP92_GC_RX_SEL_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_src_sel(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 7)) { + pr_err("%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_read(ep92->codec, EP92_GENERAL_CONTROL_1); + reg &= ~EP92_GC_RX_SEL_MASK; + reg |= (val << EP92_GC_RX_SEL_SHIFT) & EP92_GC_RX_SEL_MASK; + snd_soc_write(ep92->codec, EP92_GENERAL_CONTROL_1, reg); + ep92->gc.rx_sel &= ~EP92_GC_RX_SEL_MASK; + ep92->gc.rx_sel |= (val << EP92_GC_RX_SEL_SHIFT) & EP92_GC_RX_SEL_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_arc_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = (ep92->gc.ctl >> EP92_GC_ARC_EN_SHIFT) & EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_arc_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + pr_err("%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_read(ep92->codec, EP92_GENERAL_CONTROL_0); + reg &= ~EP92_GC_AUDIO_PATH_MASK; + reg |= (val << EP92_GC_AUDIO_PATH_SHIFT) & EP92_GC_AUDIO_PATH_MASK; + snd_soc_write(ep92->codec, EP92_GENERAL_CONTROL_0, reg); + ep92->gc.ctl &= ~EP92_GC_AUDIO_PATH_MASK; + ep92->gc.ctl |= (val << EP92_GC_AUDIO_PATH_SHIFT) & + EP92_GC_AUDIO_PATH_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_cec_mute(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = (ep92->gc.ctl >> EP92_GC_CEC_MUTE_SHIFT) & EP92_2CHOICE_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_cec_mute(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > 1)) { + pr_err("%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = snd_soc_read(ep92->codec, EP92_GENERAL_CONTROL_0); + reg &= ~EP92_GC_CEC_MUTE_MASK; + reg |= (val << EP92_GC_CEC_MUTE_SHIFT) & EP92_GC_CEC_MUTE_MASK; + snd_soc_write(ep92->codec, EP92_GENERAL_CONTROL_0, reg); + ep92->gc.ctl &= ~EP92_GC_CEC_MUTE_MASK; + ep92->gc.ctl |= (val << EP92_GC_CEC_MUTE_SHIFT) & + EP92_GC_CEC_MUTE_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static ssize_t ep92_sysfs_rda_cec_volume(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + val = (ep92->gc.cec_volume >> EP92_GC_CEC_VOLUME_SHIFT) & + EP92_GC_CEC_VOLUME_MASK; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + pr_debug("%s: '%d'\n", __func__, val); + + return ret; +} + +static ssize_t ep92_sysfs_wta_cec_volume(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int reg, val, rc; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &val); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + goto end; + } + if ((val < 0) || (val > EP92_GC_CEC_VOLUME_MAX)) { + pr_err("%s: value out of range.\n", __func__); + rc = -EINVAL; + goto end; + } + + reg = val & EP92_GC_CEC_VOLUME_MASK; + snd_soc_write(ep92->codec, EP92_GENERAL_CONTROL_3, reg); + ep92->gc.cec_volume = val & EP92_GC_CEC_VOLUME_MASK; + + rc = strnlen(buf, EP92_SYSFS_ENTRY_MAX_LEN); +end: + return rc; +} + +static DEVICE_ATTR(audio_state, 0444, ep92_sysfs_rda_audio_state, NULL); +static DEVICE_ATTR(audio_format, 0444, ep92_sysfs_rda_audio_format, NULL); +static DEVICE_ATTR(audio_rate, 0444, ep92_sysfs_rda_audio_rate, NULL); +static DEVICE_ATTR(audio_layout, 0444, ep92_sysfs_rda_audio_layout, NULL); +static DEVICE_ATTR(audio_ch_count, 0444, ep92_sysfs_rda_audio_ch_count, NULL); +static DEVICE_ATTR(audio_ch_alloc, 0444, ep92_sysfs_rda_audio_ch_alloc, NULL); +static DEVICE_ATTR(audio_avmute, 0444, ep92_sysfs_rda_avmute, NULL); +static DEVICE_ATTR(link_on0, 0444, ep92_sysfs_rda_link_on0, NULL); +static DEVICE_ATTR(link_on1, 0444, ep92_sysfs_rda_link_on1, NULL); +static DEVICE_ATTR(link_on2, 0444, ep92_sysfs_rda_link_on2, NULL); +static DEVICE_ATTR(out_plug, 0444, ep92_sysfs_rda_out_plug, NULL); +static DEVICE_ATTR(video_latency, 0444, ep92_sysfs_rda_video_latency, NULL); +static DEVICE_ATTR(arc_disable, 0644, ep92_sysfs_rda_arc_disable, + ep92_sysfs_wta_arc_disable); +static DEVICE_ATTR(power_on, 0644, ep92_sysfs_rda_power, ep92_sysfs_wta_power); +static DEVICE_ATTR(audio_path, 0644, ep92_sysfs_rda_audio_path, + ep92_sysfs_wta_audio_path); +static DEVICE_ATTR(src_sel, 0644, ep92_sysfs_rda_src_sel, + ep92_sysfs_wta_src_sel); +static DEVICE_ATTR(arc_enable, 0644, ep92_sysfs_rda_arc_enable, + ep92_sysfs_wta_arc_enable); +static DEVICE_ATTR(cec_mute, 0644, ep92_sysfs_rda_cec_mute, + ep92_sysfs_wta_cec_mute); +static DEVICE_ATTR(cec_volume, 0644, ep92_sysfs_rda_cec_volume, + ep92_sysfs_wta_cec_volume); + +static struct attribute *ep92_fs_attrs[] = { + &dev_attr_audio_state.attr, + &dev_attr_audio_format.attr, + &dev_attr_audio_rate.attr, + &dev_attr_audio_layout.attr, + &dev_attr_audio_ch_count.attr, + &dev_attr_audio_ch_alloc.attr, + &dev_attr_audio_avmute.attr, + &dev_attr_link_on0.attr, + &dev_attr_link_on1.attr, + &dev_attr_link_on2.attr, + &dev_attr_out_plug.attr, + &dev_attr_video_latency.attr, + &dev_attr_arc_disable.attr, + &dev_attr_power_on.attr, + &dev_attr_audio_path.attr, + &dev_attr_src_sel.attr, + &dev_attr_arc_enable.attr, + &dev_attr_cec_mute.attr, + &dev_attr_cec_volume.attr, + NULL, +}; + +static struct attribute_group ep92_fs_attrs_group = { + .attrs = ep92_fs_attrs, +}; + +static int ep92_sysfs_create(struct i2c_client *client, + struct ep92_pdata *ep92) +{ + int rc; + + rc = sysfs_create_group(&client->dev.kobj, &ep92_fs_attrs_group); + + return rc; +} + +static void ep92_sysfs_remove(struct i2c_client *client, + struct ep92_pdata *ep92) +{ + sysfs_remove_group(&client->dev.kobj, &ep92_fs_attrs_group); +} + static int ep92_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ep92_pdata *ep92; int ret; +#if IS_ENABLED(CONFIG_DEBUG_FS) + char debugfs_dir_name[32]; +#endif ep92 = devm_kzalloc(&client->dev, sizeof(struct ep92_pdata), GFP_KERNEL); @@ -1220,8 +1470,8 @@ static int ep92_i2c_probe(struct i2c_client *client, if (IS_ERR(ep92->regmap)) { ret = PTR_ERR(ep92->regmap); dev_err(&client->dev, - "%s %d: Failed to allocate regmap for I2C device: %d\n", - __func__, __LINE__, ret); + "%s: Failed to allocate regmap for I2C device: %d\n", + __func__, ret); return ret; } @@ -1249,6 +1499,39 @@ static int ep92_i2c_probe(struct i2c_client *client, msecs_to_jiffies(EP92_POLL_INTERVAL_OFF_MSEC)); } +#if IS_ENABLED(CONFIG_DEBUG_FS) + /* debugfs interface */ + snprintf(debugfs_dir_name, sizeof(debugfs_dir_name), "%s-%s", + client->name, dev_name(&client->dev)); + ep92->debugfs_dir = debugfs_create_dir(debugfs_dir_name, NULL); + if (!ep92->debugfs_dir) { + dev_dbg(&client->dev, + "%s: Failed to create /sys/kernel/debug/%s for debugfs\n", + __func__, debugfs_dir_name); + return -ENOMEM; + } + ep92->debugfs_file_wo = debugfs_create_file( + "write_reg_val", S_IFREG | 0444, ep92->debugfs_dir, + (void *) ep92, + &debugfs_codec_ops); + if (!ep92->debugfs_file_wo) { + dev_dbg(&client->dev, + "%s: Failed to create /sys/kernel/debug/%s/write_reg_val\n", + __func__, debugfs_dir_name); + return -ENOMEM; + } + ep92->debugfs_file_ro = debugfs_create_file( + "show_reg_dump", S_IFREG | 0444, ep92->debugfs_dir, + (void *) ep92, + &debugfs_codec_ops); + if (!ep92->debugfs_file_ro) { + dev_dbg(&client->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->dev, &soc_codec_drv_ep92, ep92_dai, ARRAY_SIZE(ep92_dai)); @@ -1259,58 +1542,15 @@ static int ep92_i2c_probe(struct i2c_client *client, goto err_reg; } - /* Create a kset under /sys/kernel/ */ - ep92_uevent_kset = kset_create_and_add("ep92-hdmi", NULL, kernel_kobj); - if (!ep92_uevent_kset) { - pr_err("%s: error creating uevent kernel set", __func__); - ret = -EINVAL; - goto err_kset; - } - - /* uevent to signal control changes */ - ep92_uevent_ctrl = devm_kzalloc(&client->dev, - sizeof(*ep92_uevent_ctrl), GFP_KERNEL); - if (!ep92_uevent_ctrl) { - ret = -ENOMEM; - goto err_ue_ctrl; - } - - ep92_uevent_ctrl->ktype.release = ep92_release_uevent_data; - ret = ep92_init_uevent_data(ep92_uevent_ctrl, "ctrl-uevent"); + ret = ep92_sysfs_create(client, ep92); if (ret) { - dev_err(&client->dev, - "%s: Failed to init ctrl-uevent: %d\n", - __func__, ret); - goto err_ue_init_ctrl; + pr_err("%s: sysfs creation failed ret=%d\n", __func__, ret); + goto err_sysfs; } - /* uevent to signal audio format changes */ - ep92_uevent_audio = devm_kzalloc(&client->dev, - sizeof(*ep92_uevent_audio), GFP_KERNEL); - if (!ep92_uevent_audio) { - ret = -ENOMEM; - goto err_ue_audio; - } - - ep92_uevent_audio->ktype.release = ep92_release_uevent_data; - ret = ep92_init_uevent_data(ep92_uevent_audio, "audio-uevent"); - if (ret) { - dev_err(&client->dev, - "%s: Failed to init ctrl-uevent: %d\n", - __func__, ret); - goto err_ue_init_audio; - } return 0; -err_ue_init_audio: - devm_kfree(&client->dev, ep92_uevent_audio); -err_ue_audio: - ep92_destroy_uevent_data(ep92_uevent_ctrl); -err_ue_init_ctrl: - devm_kfree(&client->dev, ep92_uevent_ctrl); -err_ue_ctrl: - kset_unregister(ep92_uevent_kset); -err_kset: +err_sysfs: snd_soc_unregister_codec(&client->dev); err_reg: if (ep92->irq == 0) @@ -1324,21 +1564,17 @@ static int ep92_i2c_remove(struct i2c_client *client) struct ep92_pdata *ep92; ep92 = i2c_get_clientdata(client); - if ((ep92 != NULL) && (ep92->irq == 0)) - del_timer(&ep92->timer); + if (ep92) { + if (ep92->irq == 0) + del_timer(&ep92->timer); +#if IS_ENABLED(CONFIG_DEBUG_FS) + debugfs_remove_recursive(ep92->debugfs_dir); +#endif + } snd_soc_unregister_codec(&client->dev); - ep92_destroy_uevent_data(ep92_uevent_ctrl); - devm_kfree(&client->dev, ep92_uevent_ctrl); - - ep92_destroy_uevent_data(ep92_uevent_audio); - devm_kfree(&client->dev, ep92_uevent_audio); - - if (ep92_uevent_kset) { - kset_unregister(ep92_uevent_kset); - ep92_uevent_kset = NULL; - } + ep92_sysfs_remove(client, ep92); return 0; } diff --git a/asoc/codecs/ep92/ep92.h b/asoc/codecs/ep92/ep92.h index 237c9eac2a42..ad067ea1dc93 100644 --- a/asoc/codecs/ep92/ep92.h +++ b/asoc/codecs/ep92/ep92.h @@ -139,8 +139,13 @@ static struct reg_default ep92_reg_defaults[] = { * GC = General Control * AI = Audio Info */ -#define EP92_GI_ADO_CHF_MASK 0x01 -#define EP92_GI_CEC_ECF_MASK 0x02 +#define EP92_GI_ADO_CHF_MASK 0x01 +#define EP92_GI_CEC_ECF_MASK 0x02 +#define EP92_GI_TX_HOT_PLUG_SHIFT 7 +#define EP92_GI_TX_HOT_PLUG_MASK 0x80 +#define EP92_GI_VIDEO_LATENCY_SHIFT 0 +#define EP92_GI_VIDEO_LATENCY_MASK 0xff + #define EP92_GC_POWER_SHIFT 7 #define EP92_GC_POWER_MASK 0x80 #define EP92_GC_AUDIO_PATH_SHIFT 5 @@ -149,10 +154,19 @@ static struct reg_default ep92_reg_defaults[] = { #define EP92_GC_CEC_MUTE_MASK 0x02 #define EP92_GC_ARC_EN_SHIFT 0 #define EP92_GC_ARC_EN_MASK 0x01 +#define EP92_GC_ARC_DIS_SHIFT 6 +#define EP92_GC_ARC_DIS_MASK 0x40 #define EP92_GC_RX_SEL_SHIFT 0 #define EP92_GC_RX_SEL_MASK 0x07 #define EP92_GC_CEC_VOLUME_SHIFT 0 #define EP92_GC_CEC_VOLUME_MASK 0xff +#define EP92_GC_LINK_ON0_SHIFT 0 +#define EP92_GC_LINK_ON0_MASK 0x01 +#define EP92_GC_LINK_ON1_SHIFT 1 +#define EP92_GC_LINK_ON1_MASK 0x02 +#define EP92_GC_LINK_ON2_SHIFT 2 +#define EP92_GC_LINK_ON2_MASK 0x04 + #define EP92_AI_MCLK_ON_SHIFT 6 #define EP92_AI_MCLK_ON_MASK 0x40 #define EP92_AI_AVMUTE_SHIFT 5