CONFIG_SND_RK29_SOC_I2S_8CH=y
# CONFIG_SND_RK29_SOC_WM8988 is not set
CONFIG_SND_RK29_SOC_WM8900=y
-# CONFIG_SND_RK29_SOC_alc5621 is not set
-# CONFIG_SND_RK29_SOC_alc5631 is not set
+# CONFIG_SND_RK29_SOC_RT5621 is not set
+# CONFIG_SND_RK29_SOC_RT5631 is not set
# CONFIG_SND_RK29_SOC_RT5625 is not set
# CONFIG_SND_RK29_SOC_WM8994 is not set
# CONFIG_SND_RK29_SOC_CS42L52 is not set
CONFIG_SND_I2S_DMA_EVENT_STATIC=y
# CONFIG_SND_RK29_SOC_WM8988 is not set
# CONFIG_SND_RK29_SOC_WM8900 is not set
-# CONFIG_SND_RK29_SOC_alc5621 is not set
+# CONFIG_SND_RK29_SOC_RT5621 is not set
CONFIG_SND_RK29_SOC_RT5631=y
# CONFIG_SND_RK29_SOC_RT5625 is not set
# CONFIG_SND_RK29_SOC_WM8994 is not set
.flags = 0,
},
#endif
-#if defined (CONFIG_SND_SOC_alc5621)
+#if defined (CONFIG_SND_SOC_RT5621)
{
- .type = "ALC5621",
+ .type = "rt5621",
.addr = 0x1a,
.flags = 0,
},
.flags = 0,
},
#endif
-#if defined (CONFIG_SND_SOC_alc5621)
+#if defined (CONFIG_SND_SOC_RT5621)
{
- .type = "ALC5621",
+ .type = "rt5621",
.addr = 0x1a,
.flags = 0,
},
static struct i2c_driver wm8994_i2c_driver = {
.driver = {
- .name = "wm8994",
+ .name = "WM8994",
.owner = THIS_MODULE,
.pm = &wm8994_pm_ops,
},
#include <linux/hdmi.h>
-#if defined CONFIG_SND_SOC_WM8900 || defined CONFIG_SND_SOC_RT5631
+#if defined CONFIG_SND_SOC_WM8900 || defined CONFIG_SND_SOC_RT5631 || defined CONFIG_SND_SOC_RT5621
/* sound/soc/codecs/wm8900.c */
extern void codec_set_spk(bool on);
#else
#ifndef __MFD_WM8994_CORE_H__
#define __MFD_WM8994_CORE_H__
-<<<<<<< HEAD
#include <linux/interrupt.h>
enum wm8994_type {
WM8958 = 1,
};
-=======
->>>>>>> parent of 15f7fab... temp revert rk change
struct regulator_dev;
struct regulator_bulk_data;
#define WM8994_NUM_GPIO_REGS 11
-#define WM8994_NUM_LDO_REGS 2
+#define WM8994_NUM_LDO_REGS 2
+#define WM8994_NUM_IRQ_REGS 2
+
+#define WM8994_IRQ_TEMP_SHUT 0
+#define WM8994_IRQ_MIC1_DET 1
+#define WM8994_IRQ_MIC1_SHRT 2
+#define WM8994_IRQ_MIC2_DET 3
+#define WM8994_IRQ_MIC2_SHRT 4
+#define WM8994_IRQ_FLL1_LOCK 5
+#define WM8994_IRQ_FLL2_LOCK 6
+#define WM8994_IRQ_SRC1_LOCK 7
+#define WM8994_IRQ_SRC2_LOCK 8
+#define WM8994_IRQ_AIF1DRC1_SIG_DET 9
+#define WM8994_IRQ_AIF1DRC2_SIG_DET 10
+#define WM8994_IRQ_AIF2DRC_SIG_DET 11
+#define WM8994_IRQ_FIFOS_ERR 12
+#define WM8994_IRQ_WSEQ_DONE 13
+#define WM8994_IRQ_DCS_DONE 14
+#define WM8994_IRQ_TEMP_WARN 15
+
+/* GPIOs in the chip are numbered from 1-11 */
+#define WM8994_IRQ_GPIO(x) (x + WM8994_IRQ_TEMP_WARN)
struct wm8994 {
struct mutex io_lock;
+ struct mutex irq_lock;
enum wm8994_type type;
void *control_data;
int gpio_base;
+ int irq_base;
+
+ int irq;
+ u16 irq_masks_cur[WM8994_NUM_IRQ_REGS];
+ u16 irq_masks_cache[WM8994_NUM_IRQ_REGS];
/* Used over suspend/resume */
bool suspended;
int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg,
int count, const u16 *buf);
+
+/* Helper to save on boilerplate */
+static inline int wm8994_request_irq(struct wm8994 *wm8994, int irq,
+ irq_handler_t handler, const char *name,
+ void *data)
+{
+ if (!wm8994->irq_base)
+ return -EINVAL;
+ return request_threaded_irq(wm8994->irq_base + irq, NULL, handler,
+ IRQF_TRIGGER_RISING, name,
+ data);
+}
+static inline void wm8994_free_irq(struct wm8994 *wm8994, int irq, void *data)
+{
+ if (!wm8994->irq_base)
+ return;
+ free_irq(wm8994->irq_base + irq, data);
+}
+
+int wm8994_irq_init(struct wm8994 *wm8994);
+void wm8994_irq_exit(struct wm8994 *wm8994);
+
#endif
struct regulator_init_data *init_data;
};
-#define WM8994_CONFIGURE_GPIO 0x8000
+#define WM8994_CONFIGURE_GPIO 0x10000
#define WM8994_DRC_REGS 5
-#define WM8994_EQ_REGS 19
+#define WM8994_EQ_REGS 20
+#define WM8958_MBC_CUTOFF_REGS 20
+#define WM8958_MBC_COEFF_REGS 48
+#define WM8958_MBC_COMBINED_REGS 56
+#define WM8958_VSS_HPF_REGS 2
+#define WM8958_VSS_REGS 148
+#define WM8958_ENH_EQ_REGS 32
/**
* DRC configurations are specified with a label and a set of register
u16 regs[WM8994_EQ_REGS];
};
-#define PCM_BB 1
-#define NO_PCM_BB 0
+/**
+ * Multiband compressor configurations are specified with a label and
+ * two sets of values to write. Configurations are expected to be
+ * generated using the multiband compressor configuration panel in
+ * WISCE - see http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_mbc_cfg {
+ const char *name;
+ u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
+ u16 coeff_regs[WM8958_MBC_COEFF_REGS];
+
+ /* Coefficient layout when using MBC+VSS firmware */
+ u16 combined_regs[WM8958_MBC_COMBINED_REGS];
+};
+
+/**
+ * VSS HPF configurations are specified with a label and two values to
+ * write. Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_hpf_cfg {
+ const char *name;
+ u16 regs[WM8958_VSS_HPF_REGS];
+};
+
+/**
+ * VSS configurations are specified with a label and array of values
+ * to write. Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_cfg {
+ const char *name;
+ u16 regs[WM8958_VSS_REGS];
+};
+
+/**
+ * Enhanced EQ configurations are specified with a label and array of
+ * values to write. Configurations are expected to be generated using
+ * the multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_enh_eq_cfg {
+ const char *name;
+ u16 regs[WM8958_ENH_EQ_REGS];
+};
struct wm8994_pdata {
int gpio_base;
struct wm8994_ldo_pdata ldo[WM8994_NUM_LDO];
+ int irq_base; /** Base IRQ number for WM8994, required for IRQs */
int num_drc_cfgs;
struct wm8994_drc_cfg *drc_cfgs;
int num_retune_mobile_cfgs;
struct wm8994_retune_mobile_cfg *retune_mobile_cfgs;
+ int num_mbc_cfgs;
+ struct wm8958_mbc_cfg *mbc_cfgs;
+
+ int num_vss_cfgs;
+ struct wm8958_vss_cfg *vss_cfgs;
+
+ int num_vss_hpf_cfgs;
+ struct wm8958_vss_hpf_cfg *vss_hpf_cfgs;
+
+ int num_enh_eq_cfgs;
+ struct wm8958_enh_eq_cfg *enh_eq_cfgs;
+
/* LINEOUT can be differential or single ended */
unsigned int lineout1_diff:1;
unsigned int lineout2_diff:1;
unsigned int lineout1fb:1;
unsigned int lineout2fb:1;
- /* Microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */
+ /* IRQ for microphone detection if brought out directly as a
+ * signal.
+ */
+ int micdet_irq;
+
+ /* WM8994 microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */
unsigned int micbias1_lvl:1;
unsigned int micbias2_lvl:1;
- /* Jack detect threashold levels, see datasheet for values */
+ /* WM8994 jack detect threashold levels, see datasheet for values */
unsigned int jd_scthr:2;
unsigned int jd_thr:2;
- //for phonepad
- unsigned int no_earpiece:1; // =1 don't have a earpiece, =0 has a earpiece
- unsigned int sp_hp_same_channel:1;
-
- //BB input can be differential or single ended
- unsigned int BB_input_diff:1; // =0 single ended =1 differential
- unsigned int BB_class:1;//PCM_BB= 1 NO_PCM_BB=0
-
- //If an external amplifier speakers wm8994 enable>0 disable=0
- unsigned int PA_control_pin;
-
- //wm8994 LDO1_ENA and LDO2_ENA
- unsigned int Power_EN_Pin;
- char PowerEN_iomux_name[50];
- int PowerEN_iomux_mode;
-
- //volume
- int speaker_incall_vol; //max = 6, min = -21
- int speaker_incall_mic_vol; //max = 30, min = -22
- int speaker_normal_vol; //max = 6, min = -57
- int earpiece_incall_vol; //max = 6, min = -21
- int headset_incall_vol; //max = 6, min = -12
- int headset_incall_mic_vol; //max = 30, min = -22
- int headset_normal_vol; //max = 6, min = -57
- int BT_incall_vol; //max = 30, min = -16
- int BT_incall_mic_vol; //max = 6, min = -57
- int recorder_vol; //max = 60 , min = -16
-
+ /* WM8958 microphone bias configuration */
+ int micbias[2];
};
#endif
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8900 if I2C
- select SND_SOC_alc5621 if I2C
+ select SND_SOC_RT5621 if I2C
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5625 if I2C
select SND_SOC_WM8903 if I2C
config SND_SOC_WM8900
tristate
-config SND_SOC_alc5621
+config SND_SOC_RT5621
tristate
config SND_SOC_RT5631
snd-soc-wm8776-objs := wm8776.o
snd-soc-wm8804-objs := wm8804.o
snd-soc-wm8900-objs := wm8900.o
-snd-soc-alc5621-objs := alc5621.o
+snd-soc-rt5621-objs := rt5621.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5625-objs := rt5625.o
snd-soc-cs42l52-objs := cs42l52.o
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o
obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
-obj-$(CONFIG_SND_SOC_alc5621) += snd-soc-alc5621.o
+obj-$(CONFIG_SND_SOC_RT5621) += snd-soc-rt5621.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5625) += snd-soc-rt5625.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
--- /dev/null
+/*
+ * rt5621.c -- RT5621 ALSA SoC audio codec driver
+ *
+ * Copyright 2011 Realtek Semiconductor Corp.
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5621.h"
+
+#if REALTEK_HWDEP
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#endif
+
+#if 0
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define RT5621_VERSION "0.01 alsa 1.0.24"
+
+static int caps_charge = 500;
+module_param(caps_charge, int, 0);
+MODULE_PARM_DESC(caps_charge, "RT5621 cap charge time (msecs)");
+
+struct snd_soc_codec *rt5621_codec;
+
+static void rt5621_work(struct work_struct *work);
+
+static struct workqueue_struct *rt5621_workq;
+static DECLARE_DELAYED_WORK(delayed_work, rt5621_work);
+
+#define ENABLE_EQ_HREQ 1
+
+struct rt5621_priv {
+ unsigned int sysclk;
+};
+
+enum {
+ NORMAL,
+ CLUB,
+ DANCE,
+ LIVE,
+ POP,
+ ROCK,
+ OPPO,
+ TREBLE,
+ BASS,
+ HFREQ,
+ EQTEST,
+ SPK_FR
+};
+
+typedef struct _HW_EQ_PRESET
+{
+ u16 HwEqType;
+ u16 EqValue[14];
+ u16 HwEQCtrl;
+
+}HW_EQ_PRESET;
+
+HW_EQ_PRESET HwEq_Preset[]={
+ /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x 0x9 0xa 0x 0xc 0x62*/
+ {NORMAL,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x0000},
+ {CLUB ,{0x1C10,0x0000,0xC1CC,0x1E5D,0x0699,0xCD48,0x188D,0x0699,0xC3B6,0x1CD0,0x0699,0x0436,0x0000},0x800E},
+ {DANCE ,{0x1F2C,0x095B,0xC071,0x1F95,0x0616,0xC96E,0x1B11,0xFC91,0xDCF2,0x1194,0xFAF2,0x0436,0x0000},0x800F},
+ {LIVE ,{0x1EB5,0xFCB6,0xC24A,0x1DF8,0x0E7C,0xC883,0x1C10,0x0699,0xDA41,0x1561,0x0295,0x0436,0x0000},0x800F},
+ {POP ,{0x1E98,0xFCB6,0xC340,0x1D60,0x095B,0xC6AC,0x1BBC,0x0556,0x0689,0x0F33,0x0000,0xEDD1,0xF805},0x801F},
+ {ROCK ,{0x1EB5,0xFCB6,0xC071,0x1F95,0x0424,0xC30A,0x1D27,0xF900,0x0C5D,0x0FC7,0x0E23,0x0436,0x0000},0x800F},
+ {OPPO ,{0x0000,0x0000,0xCA4A,0x17F8,0x0FEC,0xCA4A,0x17F8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x800F},
+ {TREBLE,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x188D,0x1699},0x8010},
+ {BASS ,{0x1A43,0x0C00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x8001},
+ {EQTEST,{0x1F8C,0x1830,0xC118,0x1EEF,0xFD77,0xD8CB,0x1BBC,0x0556,0x0689,0x0F33,0x0000,0xF17F,0x0FEC},0x8003},
+};
+
+static const u16 rt5621_reg[RT5621_VENDOR_ID2 + 1] = {
+ [RT5621_RESET] = 0x59b4,
+ [RT5621_SPK_OUT_VOL] = 0x8080,
+ [RT5621_HP_OUT_VOL] = 0x8080,
+ [RT5621_MONO_AUX_OUT_VOL] = 0x8080,
+ [RT5621_AUXIN_VOL] = 0xe808,
+ [RT5621_LINE_IN_VOL] = 0xe808,
+ [RT5621_STEREO_DAC_VOL] = 0xe808,
+ [RT5621_MIC_VOL] = 0x0808,
+ [RT5621_MIC_ROUTING_CTRL] = 0xe0e0,
+ [RT5621_ADC_REC_GAIN] = 0xf58b,
+ [RT5621_ADC_REC_MIXER] = 0x7f7f,
+ [RT5621_SOFT_VOL_CTRL_TIME] = 0x000a,
+ [RT5621_OUTPUT_MIXER_CTRL] = 0xc000,
+ [RT5621_AUDIO_INTERFACE] = 0x8000,
+ [RT5621_STEREO_AD_DA_CLK_CTRL] = 0x166d,
+ [RT5621_ADD_CTRL_REG] = 0x5300,
+ [RT5621_GPIO_PIN_CONFIG] = 0x1c0e,
+ [RT5621_GPIO_PIN_POLARITY] = 0x1c0e,
+ [RT5621_GPIO_PIN_STATUS] = 0x0002,
+ [RT5621_OVER_TEMP_CURR_STATUS] = 0x003c,
+ [RT5621_PSEDUEO_SPATIAL_CTRL] = 0x0497,
+ [RT5621_AVC_CTRL] = 0x000b,
+ [RT5621_VENDOR_ID1] = 0x10ec,
+ [RT5621_VENDOR_ID2] = 0x2003,
+};
+
+#define rt5621_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value)
+
+#define rt5621_write_index_reg(c, addr, data) \
+{ \
+ snd_soc_write(c, 0x6a, addr); \
+ snd_soc_write(c, 0x6c, data); \
+}
+
+static int rt5621_reset(struct snd_soc_codec *codec)
+{
+ return snd_soc_write(codec, RT5621_RESET, 0);
+}
+
+static int rt5621_volatile_register(
+ struct snd_soc_codec *codec, unsigned int reg)
+{
+ switch (reg) {
+ case RT5621_RESET:
+ case RT5621_HID_CTRL_DATA:
+ case RT5621_GPIO_PIN_STATUS:
+ case RT5621_OVER_TEMP_CURR_STATUS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int rt5621_readable_register(
+ struct snd_soc_codec *codec, unsigned int reg)
+{
+ switch (reg) {
+ case RT5621_RESET:
+ case RT5621_SPK_OUT_VOL:
+ case RT5621_HP_OUT_VOL:
+ case RT5621_MONO_AUX_OUT_VOL:
+ case RT5621_AUXIN_VOL:
+ case RT5621_LINE_IN_VOL:
+ case RT5621_STEREO_DAC_VOL:
+ case RT5621_MIC_VOL:
+ case RT5621_MIC_ROUTING_CTRL:
+ case RT5621_ADC_REC_GAIN:
+ case RT5621_ADC_REC_MIXER:
+ case RT5621_SOFT_VOL_CTRL_TIME:
+ case RT5621_OUTPUT_MIXER_CTRL:
+ case RT5621_MIC_CTRL:
+ case RT5621_AUDIO_INTERFACE:
+ case RT5621_STEREO_AD_DA_CLK_CTRL:
+ case RT5621_COMPANDING_CTRL:
+ case RT5621_PWR_MANAG_ADD1:
+ case RT5621_PWR_MANAG_ADD2:
+ case RT5621_PWR_MANAG_ADD3:
+ case RT5621_ADD_CTRL_REG:
+ case RT5621_GLOBAL_CLK_CTRL_REG:
+ case RT5621_PLL_CTRL:
+ case RT5621_GPIO_OUTPUT_PIN_CTRL:
+ case RT5621_GPIO_PIN_CONFIG:
+ case RT5621_GPIO_PIN_POLARITY:
+ case RT5621_GPIO_PIN_STICKY:
+ case RT5621_GPIO_PIN_WAKEUP:
+ case RT5621_GPIO_PIN_STATUS:
+ case RT5621_GPIO_PIN_SHARING:
+ case RT5621_OVER_TEMP_CURR_STATUS:
+ case RT5621_JACK_DET_CTRL:
+ case RT5621_MISC_CTRL:
+ case RT5621_PSEDUEO_SPATIAL_CTRL:
+ case RT5621_EQ_CTRL:
+ case RT5621_EQ_MODE_ENABLE:
+ case RT5621_AVC_CTRL:
+ case RT5621_HID_CTRL_INDEX:
+ case RT5621_HID_CTRL_DATA:
+ case RT5621_VENDOR_ID1:
+ case RT5621_VENDOR_ID2:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
+//static const char *rt5621_spkl_pga[] = {"Vmid","HPL mixer","SPK mixer","Mono Mixer"};
+static const char *rt5621_spkn_source_sel[] = {"RN", "RP", "LN"};
+static const char *rt5621_spk_pga[] = {"Vmid","HP mixer","SPK mixer","Mono Mixer"};
+static const char *rt5621_hpl_pga[] = {"Vmid","HPL mixer"};
+static const char *rt5621_hpr_pga[] = {"Vmid","HPR mixer"};
+static const char *rt5621_mono_pga[] = {"Vmid","HP mixer","SPK mixer","Mono Mixer"};
+static const char *rt5621_amp_type_sel[] = {"Class AB","Class D"};
+static const char *rt5621_mic_boost_sel[] = {"Bypass","20db","30db","40db"};
+
+static const struct soc_enum rt5621_enum[] = {
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 14, 3, rt5621_spkn_source_sel), /* spkn source from hp mixer */
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 10, 4, rt5621_spk_pga), /* spk input sel 1 */
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 9, 2, rt5621_hpl_pga), /* hp left input sel 2 */
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 8, 2, rt5621_hpr_pga), /* hp right input sel 3 */
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 6, 4, rt5621_mono_pga), /* mono input sel 4 */
+SOC_ENUM_SINGLE(RT5621_MIC_CTRL, 10,4, rt5621_mic_boost_sel), /*Mic1 boost sel 5 */
+SOC_ENUM_SINGLE(RT5621_MIC_CTRL, 8,4,rt5621_mic_boost_sel), /*Mic2 boost sel 6 */
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL,13,2,rt5621_amp_type_sel), /*Speaker AMP sel 7 */
+};
+
+static int rt5621_amp_sel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned short val;
+ unsigned short mask, bitmask;
+
+ for (bitmask = 1; bitmask < e->max; bitmask <<= 1);
+
+ if (ucontrol->value.enumerated.item[0] > e->max - 1)
+ return -EINVAL;
+ val = ucontrol->value.enumerated.item[0] << e->shift_l;
+ mask = (bitmask - 1) << e->shift_l;
+ if (e->shift_l != e->shift_r) {
+ if (ucontrol->value.enumerated.item[1] > e->max - 1)
+ return -EINVAL;
+ val |= ucontrol->value.enumerated.item[1] << e->shift_r;
+ mask |= (bitmask - 1) << e->shift_r;
+ }
+
+ snd_soc_update_bits(codec, e->reg, mask, val);
+ val &= (0x1 << 13);
+
+ if (val == 0)
+ {
+ snd_soc_update_bits(codec, 0x3c, 0x0000, 0x4000); /*power off classd*/
+ snd_soc_update_bits(codec, 0x3c, 0x8000, 0x8000); /*power on classab*/
+ } else {
+ snd_soc_update_bits(codec, 0x3c, 0x0000, 0x8000); /*power off classab*/
+ snd_soc_update_bits(codec, 0x3c, 0x4000, 0x4000); /*power on classd*/
+ }
+
+ return 0;
+}
+
+//*****************************************************************************
+//
+//function:Change audio codec power status
+//
+//*****************************************************************************
+static int rt5621_ChangeCodecPowerStatus(struct snd_soc_codec *codec,int power_state)
+{
+ unsigned short int PowerDownState=0;
+
+ switch(power_state) {
+ case POWER_STATE_D0: //FULL ON-----power on all power
+
+ snd_soc_write(codec,RT5621_PWR_MANAG_ADD1,~PowerDownState);
+ snd_soc_write(codec,RT5621_PWR_MANAG_ADD2,~PowerDownState);
+ snd_soc_write(codec,RT5621_PWR_MANAG_ADD3,~PowerDownState);
+ break;
+ case POWER_STATE_D1: //LOW ON-----
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD2 ,PWR_VREF |
+ PWR_DAC_REF_CIR | PWR_L_DAC_CLK | PWR_R_DAC_CLK |
+ PWR_L_HP_MIXER | PWR_R_HP_MIXER | PWR_L_ADC_CLK_GAIN |
+ PWR_R_ADC_CLK_GAIN | PWR_L_ADC_REC_MIXER | PWR_R_ADC_REC_MIXER |
+ PWR_CLASS_AB, PWR_VREF | PWR_DAC_REF_CIR | PWR_L_DAC_CLK |
+ PWR_R_DAC_CLK | PWR_L_HP_MIXER | PWR_R_HP_MIXER |
+ PWR_L_ADC_CLK_GAIN | PWR_R_ADC_CLK_GAIN |
+ PWR_L_ADC_REC_MIXER | PWR_R_ADC_REC_MIXER | PWR_CLASS_AB);
+
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD3 ,PWR_MAIN_BIAS |
+ PWR_HP_R_OUT_VOL | PWR_HP_L_OUT_VOL | PWR_SPK_OUT |
+ PWR_MIC1_FUN_CTRL | PWR_MIC1_BOOST_MIXER, PWR_MAIN_BIAS |
+ PWR_HP_R_OUT_VOL | PWR_HP_L_OUT_VOL | PWR_SPK_OUT |
+ PWR_MIC1_FUN_CTRL | PWR_MIC1_BOOST_MIXER);
+
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD1 ,PWR_MAIN_I2S_EN |
+ PWR_HP_OUT_ENH_AMP | PWR_HP_OUT_AMP | PWR_MIC1_BIAS_EN,
+ PWR_MAIN_I2S_EN | PWR_HP_OUT_ENH_AMP | PWR_HP_OUT_AMP |
+ PWR_MIC1_BIAS_EN);
+ break;
+
+ case POWER_STATE_D1_PLAYBACK: //Low on of Playback
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD2, PWR_VREF | PWR_DAC_REF_CIR |
+ PWR_L_DAC_CLK | PWR_R_DAC_CLK | PWR_L_HP_MIXER | PWR_R_HP_MIXER |
+ PWR_CLASS_AB | PWR_CLASS_D, PWR_VREF | PWR_DAC_REF_CIR |
+ PWR_L_DAC_CLK | PWR_R_DAC_CLK | PWR_L_HP_MIXER | PWR_R_HP_MIXER |
+ PWR_CLASS_AB | PWR_CLASS_D);
+
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD3, PWR_MAIN_BIAS |
+ PWR_HP_R_OUT_VOL | PWR_HP_L_OUT_VOL | PWR_SPK_OUT,
+ PWR_MAIN_BIAS | PWR_HP_R_OUT_VOL | PWR_HP_L_OUT_VOL | PWR_SPK_OUT);
+
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD1, PWR_MAIN_I2S_EN |
+ PWR_HP_OUT_ENH_AMP | PWR_HP_OUT_AMP, PWR_MAIN_I2S_EN |
+ PWR_HP_OUT_ENH_AMP | PWR_HP_OUT_AMP);
+ break;
+
+ case POWER_STATE_D1_RECORD: //Low on of Record
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD1, PWR_MAIN_I2S_EN |
+ PWR_MIC1_BIAS_EN, PWR_MAIN_I2S_EN | PWR_MIC1_BIAS_EN);
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD2, PWR_VREF |
+ PWR_L_ADC_CLK_GAIN | PWR_R_ADC_CLK_GAIN | PWR_L_ADC_REC_MIXER |
+ PWR_R_ADC_REC_MIXER, PWR_VREF | PWR_L_ADC_CLK_GAIN |
+ PWR_R_ADC_CLK_GAIN | PWR_L_ADC_REC_MIXER | PWR_R_ADC_REC_MIXER);
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD3, PWR_MAIN_BIAS |
+ PWR_MIC2_BOOST_MIXER | PWR_MIC1_BOOST_MIXER, PWR_MAIN_BIAS |
+ PWR_MIC2_BOOST_MIXER | PWR_MIC1_BOOST_MIXER);
+ break;
+
+ case POWER_STATE_D2: //STANDBY----
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD1, 0, PWR_MAIN_I2S_EN |
+ PWR_HP_OUT_ENH_AMP | PWR_HP_OUT_AMP | PWR_MIC1_BIAS_EN);
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD3, 0, PWR_HP_R_OUT_VOL |
+ PWR_HP_L_OUT_VOL | PWR_SPK_OUT | PWR_MIC1_FUN_CTRL |
+ PWR_MIC1_BOOST_MIXER);
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD2, 0, PWR_DAC_REF_CIR |
+ PWR_L_DAC_CLK | PWR_R_DAC_CLK | PWR_L_HP_MIXER | PWR_R_HP_MIXER|
+ PWR_L_ADC_CLK_GAIN | PWR_R_ADC_CLK_GAIN | PWR_L_ADC_REC_MIXER |
+ PWR_R_ADC_REC_MIXER | PWR_CLASS_AB | PWR_CLASS_D);
+ break;
+
+ case POWER_STATE_D2_PLAYBACK: //STANDBY of playback
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD3, 0, /*PWR_HP_R_OUT_VOL |
+ PWR_HP_L_OUT_VOL |*/ PWR_SPK_OUT);
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD1, 0, PWR_HP_OUT_ENH_AMP |
+ PWR_HP_OUT_AMP);
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD2, 0, PWR_DAC_REF_CIR |
+ PWR_L_DAC_CLK | PWR_R_DAC_CLK | PWR_L_HP_MIXER | PWR_R_HP_MIXER |
+ PWR_CLASS_AB | PWR_CLASS_D);
+ break;
+
+ case POWER_STATE_D2_RECORD: //STANDBY of record
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD1, 0, PWR_MIC1_BIAS_EN);
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD2, 0, PWR_L_ADC_CLK_GAIN |
+ PWR_R_ADC_CLK_GAIN | PWR_L_ADC_REC_MIXER | PWR_R_ADC_REC_MIXER);
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD3, 0, PWR_MIC2_BOOST_MIXER |
+ PWR_MIC1_BOOST_MIXER);
+ break;
+
+ case POWER_STATE_D3: //SLEEP
+ case POWER_STATE_D4: //OFF----power off all power
+ rt5621_write_mask(codec, RT5621_PWR_MANAG_ADD1, 0, PWR_HP_OUT_ENH_AMP |
+ PWR_HP_OUT_AMP);
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD3, 0);
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD1, 0);
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD2, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+//*****************************************************************************
+//
+//function AudioOutEnable:Mute/Unmute audio out channel
+//WavOutPath:output channel
+//Mute :Mute/Unmute output channel
+//
+//*****************************************************************************
+static int rt5621_AudioOutEnable(struct snd_soc_codec *codec,
+ unsigned short int WavOutPath, int Mute)
+{
+ int RetVal=0;
+
+ if(Mute) {
+ switch(WavOutPath) {
+ case RT_WAVOUT_ALL_ON:
+ RetVal = rt5621_write_mask(codec, RT5621_SPK_OUT_VOL, RT_L_MUTE | RT_R_MUTE,
+ RT_L_MUTE | RT_R_MUTE); //Mute Speaker right/left channel
+ RetVal = rt5621_write_mask(codec, RT5621_HP_OUT_VOL, RT_L_MUTE | RT_R_MUTE,
+ RT_L_MUTE | RT_R_MUTE); //Mute headphone right/left channel
+ RetVal = rt5621_write_mask(codec, RT5621_MONO_AUX_OUT_VOL, RT_L_MUTE |
+ RT_R_MUTE, RT_L_MUTE | RT_R_MUTE); //Mute Aux/Mono right/left channel
+ RetVal = rt5621_write_mask(codec, RT5621_STEREO_DAC_VOL, RT_M_HP_MIXER |
+ RT_M_SPK_MIXER | RT_M_MONO_MIXER, RT_M_HP_MIXER |
+ RT_M_SPK_MIXER | RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer
+ break;
+
+ case RT_WAVOUT_HP:
+ RetVal = rt5621_write_mask(codec, RT5621_HP_OUT_VOL, RT_L_MUTE | RT_R_MUTE,
+ RT_L_MUTE | RT_R_MUTE); //Mute headphone right/left channel
+ break;
+
+ case RT_WAVOUT_SPK:
+ RetVal = rt5621_write_mask(codec, RT5621_SPK_OUT_VOL, RT_L_MUTE | RT_R_MUTE,
+ RT_L_MUTE | RT_R_MUTE); //Mute Speaker right/left channel
+ break;
+
+ case RT_WAVOUT_AUXOUT:
+ RetVal = rt5621_write_mask(codec, RT5621_MONO_AUX_OUT_VOL, RT_L_MUTE |
+ RT_R_MUTE, RT_L_MUTE | RT_R_MUTE); //Mute AuxOut right/left channel
+ break;
+
+ case RT_WAVOUT_MONO:
+
+ RetVal = rt5621_write_mask(codec, RT5621_MONO_AUX_OUT_VOL, RT_L_MUTE,
+ RT_L_MUTE); //Mute MonoOut channel
+ break;
+
+ case RT_WAVOUT_DAC:
+ RetVal = rt5621_write_mask(codec, RT5621_STEREO_DAC_VOL, RT_M_HP_MIXER |
+ RT_M_SPK_MIXER | RT_M_MONO_MIXER, RT_M_HP_MIXER | RT_M_SPK_MIXER |
+ RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer
+ break;
+
+ default:
+ return 0;
+ }
+ } else {
+ switch(WavOutPath) {
+ case RT_WAVOUT_ALL_ON:
+ RetVal = rt5621_write_mask(codec, RT5621_SPK_OUT_VOL, 0, RT_L_MUTE |
+ RT_R_MUTE); //Mute Speaker right/left channel
+ RetVal = rt5621_write_mask(codec, RT5621_HP_OUT_VOL, 0, RT_L_MUTE |
+ RT_R_MUTE); //Mute headphone right/left channel
+ RetVal = rt5621_write_mask(codec, RT5621_MONO_AUX_OUT_VOL, 0, RT_L_MUTE |
+ RT_R_MUTE); //Mute Aux/Mono right/left channel
+ RetVal = rt5621_write_mask(codec, RT5621_STEREO_DAC_VOL, 0, RT_M_HP_MIXER |
+ RT_M_SPK_MIXER | RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer
+ break;
+ case RT_WAVOUT_HP:
+ RetVal = rt5621_write_mask(codec, RT5621_HP_OUT_VOL, 0, RT_L_MUTE |
+ RT_R_MUTE); //UnMute headphone right/left channel
+ break;
+
+ case RT_WAVOUT_SPK:
+ RetVal = rt5621_write_mask(codec, RT5621_SPK_OUT_VOL, 0, RT_L_MUTE |
+ RT_R_MUTE); //unMute Speaker right/left channel
+ break;
+ case RT_WAVOUT_AUXOUT:
+ RetVal = rt5621_write_mask(codec, RT5621_MONO_AUX_OUT_VOL, 0, RT_L_MUTE |
+ RT_R_MUTE); //unMute AuxOut right/left channel
+ break;
+
+ case RT_WAVOUT_MONO:
+ RetVal = rt5621_write_mask(codec, RT5621_MONO_AUX_OUT_VOL, 0,
+ RT_L_MUTE); //unMute MonoOut channel
+ break;
+
+ case RT_WAVOUT_DAC:
+ RetVal = rt5621_write_mask(codec, RT5621_STEREO_DAC_VOL, 0, RT_M_HP_MIXER |
+ RT_M_SPK_MIXER | RT_M_MONO_MIXER); //unMute DAC to HP,Speaker,Mono Mixer
+ break;
+ default:
+ return 0;
+ }
+
+ }
+
+ return RetVal;
+}
+
+
+//*****************************************************************************
+//
+//function:Enable/Disable ADC input source control
+//
+//*****************************************************************************
+static int Enable_ADC_Input_Source(struct snd_soc_codec *codec,unsigned short int ADC_Input_Sour,int Enable)
+{
+ int bRetVal=0;
+
+ if(Enable) {
+ //Enable ADC source
+ bRetVal=rt5621_write_mask(codec,RT5621_ADC_REC_MIXER,0,ADC_Input_Sour);
+ } else {
+ //Disable ADC source
+ bRetVal=rt5621_write_mask(codec,RT5621_ADC_REC_MIXER,ADC_Input_Sour,ADC_Input_Sour);
+ }
+
+ return bRetVal;
+}
+
+static void rt5621_update_eqmode(struct snd_soc_codec *codec, int mode)
+{
+ u16 HwEqIndex=0;
+
+ if (mode == NORMAL) {
+ /*clear EQ parameter*/
+ for (HwEqIndex=0; HwEqIndex<=0x0C; HwEqIndex++) {
+
+ rt5621_write_index_reg(codec, HwEqIndex, HwEq_Preset[mode].EqValue[HwEqIndex])
+ }
+
+ snd_soc_write(codec, 0x62, 0x0); /*disable EQ block*/
+ } else {
+ snd_soc_write(codec, 0x62, HwEq_Preset[mode].HwEQCtrl);
+
+ /*Fill EQ parameter*/
+ for (HwEqIndex=0; HwEqIndex<=0x0C; HwEqIndex++) {
+
+ rt5621_write_index_reg(codec, HwEqIndex, HwEq_Preset[mode].EqValue[HwEqIndex])
+ }
+ //update EQ parameter
+ snd_soc_write(codec, 0x66, 0x1f);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(1));
+ snd_soc_write(codec, 0x66, 0x0);
+ }
+}
+
+static const struct snd_kcontrol_new rt5621_snd_controls[] = {
+SOC_DOUBLE("Speaker Playback Volume", RT5621_SPK_OUT_VOL, 8, 0, 31, 1),
+SOC_DOUBLE("Speaker Playback Switch", RT5621_SPK_OUT_VOL, 15, 7, 1, 1),
+SOC_DOUBLE("Headphone Playback Volume", RT5621_HP_OUT_VOL, 8, 0, 31, 1),
+SOC_DOUBLE("Headphone Playback Switch", RT5621_HP_OUT_VOL,15, 7, 1, 1),
+SOC_DOUBLE("AUX Playback Volume", RT5621_MONO_AUX_OUT_VOL, 8, 0, 31, 1),
+SOC_DOUBLE("AUX Playback Switch", RT5621_MONO_AUX_OUT_VOL, 15, 7, 1, 1),
+SOC_DOUBLE("PCM Playback Volume", RT5621_STEREO_DAC_VOL, 8, 0, 31, 1),
+SOC_DOUBLE("Line In Volume", RT5621_LINE_IN_VOL, 8, 0, 31, 1),
+SOC_SINGLE("Mic 1 Volume", RT5621_MIC_VOL, 8, 31, 1),
+SOC_SINGLE("Mic 2 Volume", RT5621_MIC_VOL, 0, 31, 1),
+SOC_ENUM("Mic 1 Boost", rt5621_enum[5]),
+SOC_ENUM("Mic 2 Boost", rt5621_enum[6]),
+SOC_ENUM_EXT("Speaker Amp Type", rt5621_enum[7], snd_soc_get_enum_double, rt5621_amp_sel_put),
+SOC_DOUBLE("AUX In Volume", RT5621_AUXIN_VOL, 8, 0, 31, 1),
+SOC_DOUBLE("Capture Volume", RT5621_ADC_REC_GAIN, 7, 0, 31, 0),
+};
+
+void hp_depop_mode2(struct snd_soc_codec *codec)
+{
+ snd_soc_update_bits(codec, 0x3e, 0x8000, 0x8000);
+ snd_soc_update_bits(codec, 0x04, 0x8080, 0x8080);
+ snd_soc_update_bits(codec, 0x3a, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, 0x3c, 0x2000, 0x2000);
+ snd_soc_update_bits(codec, 0x3e, 0x0600, 0x0600);
+ snd_soc_update_bits(codec, 0x5e, 0x0200, 0x0200);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(300));
+}
+
+void aux_depop_mode2(struct snd_soc_codec *codec)
+{
+ snd_soc_update_bits(codec, 0x3e, 0x8000, 0x8000);
+ snd_soc_update_bits(codec, 0x06, 0x8080, 0x8080);
+ snd_soc_update_bits(codec, 0x3a, 0x0100, 0x0100);
+ snd_soc_update_bits(codec, 0x3c, 0x2000, 0x2000);
+ snd_soc_update_bits(codec, 0x3e, 0x6000, 0x6000);
+ snd_soc_update_bits(codec, 0x5e, 0x0020, 0x0200);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(300));
+ snd_soc_update_bits(codec, 0x3a, 0x0002, 0x0002);
+ snd_soc_update_bits(codec, 0x3a, 0x0001, 0x0001);
+}
+
+static int rt5621_pcm_hw_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *codec_dai)
+{
+
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int stream = substream->stream;
+
+ switch (stream)
+ {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+
+ rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D1_PLAYBACK); //power on dac to hp and speaker out
+
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_SPK,0); //unmute speaker out
+
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_HP,0); //unmute hp
+
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_AUXOUT,0); //unmute auxout out
+
+ break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+
+ rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D1_RECORD); //power on input to adc
+
+ Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,1); //enable record source from mic1
+
+ break;
+ }
+
+ return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+ u32 pll_in;
+ u32 pll_out;
+ u16 regvalue;
+};
+
+static const struct _pll_div codec_pll_div[] = {
+
+ { 2048000, 8192000, 0x0ea0},
+ { 3686400, 8192000, 0x4e27},
+ { 12000000, 8192000, 0x456b},
+ { 13000000, 8192000, 0x495f},
+ { 13100000, 8192000, 0x0320},
+ { 2048000, 11289600, 0xf637},
+ { 3686400, 11289600, 0x2f22},
+ { 12000000, 11289600, 0x3e2f},
+ { 13000000, 11289600, 0x4d5b},
+ { 13100000, 11289600, 0x363b},
+ { 2048000, 16384000, 0x1ea0},
+ { 3686400, 16384000, 0x9e27},
+ { 12000000, 16384000, 0x452b},
+ { 13000000, 16384000, 0x542f},
+ { 13100000, 16384000, 0x03a0},
+ { 2048000, 16934400, 0xe625},
+ { 3686400, 16934400, 0x9126},
+ { 12000000, 16934400, 0x4d2c},
+ { 13000000, 16934400, 0x742f},
+ { 13100000, 16934400, 0x3c27},
+ { 2048000, 22579200, 0x2aa0},
+ { 3686400, 22579200, 0x2f20},
+ { 12000000, 22579200, 0x7e2f},
+ { 13000000, 22579200, 0x742f},
+ { 13100000, 22579200, 0x3c27},
+ { 2048000, 24576000, 0x2ea0},
+ { 3686400, 24576000, 0xee27},
+ { 12000000, 24576000, 0x2915},
+ { 13000000, 24576000, 0x772e},
+ { 13100000, 24576000, 0x0d20},
+};
+
+static const struct _pll_div codec_bclk_pll_div[] = {
+
+ { 1536000, 24576000, 0x3ea0},
+ { 3072000, 24576000, 0x1ea0},
+ { 512000, 24576000, 0x8e90},
+ { 256000, 24576000, 0xbe80},
+ { 2822400, 11289600, 0x1ee0},
+ { 3072000, 12288000, 0x1ee0},
+};
+
+
+static int rt5621_set_dai_pll(struct snd_soc_dai *dai,
+ int pll_id,int source, unsigned int freq_in, unsigned int freq_out)
+{
+ int i;
+ int ret = -EINVAL;
+ struct snd_soc_codec *codec = dai->codec;
+
+ if (pll_id < RT5621_PLL_FR_MCLK || pll_id > RT5621_PLL_FR_BCLK)
+ return -EINVAL;
+
+ //rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2, 0x0000,0x1000); //disable PLL power
+
+ if (!freq_in || !freq_out) {
+
+ return 0;
+ }
+
+ if (RT5621_PLL_FR_MCLK == pll_id) {
+ for (i = 0; i < ARRAY_SIZE(codec_pll_div); i++) {
+
+ if (codec_pll_div[i].pll_in == freq_in && codec_pll_div[i].pll_out == freq_out)
+ {
+ snd_soc_update_bits(codec, RT5621_GLOBAL_CLK_CTRL_REG, 0x0000, 0x4000);
+ snd_soc_write(codec,RT5621_PLL_CTRL,codec_pll_div[i].regvalue);//set PLL parameter
+ snd_soc_update_bits(codec,RT5621_PWR_MANAG_ADD2, 0x1000,0x1000); //enable PLL power
+ ret = 0;
+ }
+ }
+ }
+ else if (RT5621_PLL_FR_BCLK == pll_id)
+ {
+ for (i = 0; i < ARRAY_SIZE(codec_bclk_pll_div); i++)
+ {
+ if ((freq_in == codec_bclk_pll_div[i].pll_in) && (freq_out == codec_bclk_pll_div[i].pll_out))
+ {
+ snd_soc_update_bits(codec, RT5621_GLOBAL_CLK_CTRL_REG, 0x4000, 0x4000);
+ snd_soc_write(codec,RT5621_PLL_CTRL,codec_bclk_pll_div[i].regvalue);//set PLL parameter
+ snd_soc_update_bits(codec,RT5621_PWR_MANAG_ADD2, 0x1000,0x1000); //enable PLL power
+ ret = 0;
+ }
+ }
+ }
+
+ snd_soc_update_bits(codec,RT5621_GLOBAL_CLK_CTRL_REG,0x8000,0x8000);//Codec sys-clock from PLL
+ return ret;
+}
+
+
+struct _coeff_div {
+ u32 mclk;
+ u32 rate;
+ u16 fs;
+ u16 regvalue;
+};
+
+/* codec hifi mclk (after PLL) clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+ /* 8k */
+ { 8192000, 8000, 256*4, 0x2a2d},
+ {12288000, 8000, 384*4, 0x2c2f},
+
+ /* 11.025k */
+ {11289600, 11025, 256*4, 0x2a2d},
+ {16934400, 11025, 384*4, 0x2c2f},
+
+ /* 16k */
+ {12288000, 16000, 384*2, 0x1c2f},
+ {16384000, 16000, 256*4, 0x2a2d},
+ {24576000, 16000, 384*4, 0x2c2f},
+
+ /* 22.05k */
+ {11289600, 22050, 256*2, 0x1a2d},
+ {16934400, 22050, 384*2, 0x1c2f},
+
+ /* 32k */
+ {12288000, 32000, 384 , 0x0c2f},
+ {16384000, 32000, 256*2, 0x1a2d},
+ {24576000, 32000, 384*2, 0x1c2f},
+
+ /* 44.1k */
+ {11289600, 44100, 256*1, 0x0a2d},
+ {22579200, 44100, 256*2, 0x1a2d},
+ {45158400, 44100, 256*4, 0x2a2d},
+
+ /* 48k */
+ {12288000, 48000, 256*1, 0x0a2d},
+ {24576000, 48000, 256*2, 0x1a2d},
+ {49152000, 48000, 256*4, 0x2a2d},
+
+ //MCLK is 24.576Mhz(for 8k,16k,32k)
+ {24576000, 8000, 384*8, 0x3c6b},
+ {24576000, 16000, 384*4, 0x2c6b},
+ {24576000, 32000, 384*2, 0x1c6b},
+
+ //MCLK is 22.5792mHz(for 11k,22k)
+ {22579200, 11025, 256*8, 0x3a2d},
+ {22579200, 22050, 256*4, 0x2a2d},
+};
+
+
+
+static int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ DBG("get_coeff mclk=%d,rate=%d\n",mclk,rate);
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+ return i;
+ }
+ return -EINVAL;
+}
+
+
+/*
+ * Clock after PLL and dividers
+ */
+ /*in this driver, you have to set sysclk to be 24576000,
+ * but you don't need to give a clk to be 24576000, our
+ * internal pll will generate this clock! so it won't make
+ * you any difficult.
+ */
+static int rt5621_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5621_priv *rt5621 = snd_soc_codec_get_drvdata(codec);
+
+ if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+ rt5621->sysclk = freq;
+ return 0;
+ }
+
+ printk("unsupported sysclk freq %u for audio i2s\n", freq);
+
+ return -EINVAL;
+}
+
+
+static int rt5621_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 iface = 0;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface = 0x0000;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ iface = 0x8000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface |= 0x0000;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ iface |= 0x0001;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= 0x0002;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= 0x0003;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= 0x4003;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ iface |= 0x0000;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x0100;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec,RT5621_AUDIO_INTERFACE,iface);
+ return 0;
+}
+
+
+static int rt5621_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct rt5621_priv *rt5621 = snd_soc_codec_get_drvdata(codec);
+ u16 iface = snd_soc_read(codec,RT5621_AUDIO_INTERFACE)&0xfff3;
+ int coeff = get_coeff(rt5621->sysclk, params_rate(params));
+
+ DBG("rt5621_pcm_hw_params\n");
+ if (coeff < 0)
+ coeff = get_coeff(24576000, params_rate(params)); /*if not set sysclk, default to be 24.576MHz*/
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ iface |= 0x0000;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0004;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0008;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ iface |= 0x000c;
+ break;
+ }
+
+ /* set iface & srate */
+ snd_soc_write(codec, RT5621_AUDIO_INTERFACE, iface);
+
+ if (coeff >= 0)
+ snd_soc_write(codec, RT5621_STEREO_AD_DA_CLK_CTRL, coeff_div[coeff].regvalue);
+ else
+ {
+ printk(KERN_ERR "cant find matched sysclk and rate config\n");
+ return -EINVAL;
+
+ }
+ return 0;
+}
+
+static int rt5621_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ snd_soc_update_bits(codec, RT5621_SPK_OUT_VOL, RT_L_MUTE | RT_R_MUTE, 0);
+ snd_soc_update_bits(codec, RT5621_HP_OUT_VOL, RT_L_MUTE | RT_R_MUTE, 0);
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_update_bits(codec, RT5621_SPK_OUT_VOL, RT_L_MUTE | RT_R_MUTE, RT_L_MUTE | RT_R_MUTE);
+ snd_soc_update_bits(codec, RT5621_HP_OUT_VOL, RT_L_MUTE | RT_R_MUTE, RT_L_MUTE | RT_R_MUTE);
+ if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD3, 0x8000);//enable Main bias
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD2, 0x2000);//enable Vref
+ codec->cache_only = false;
+ snd_soc_cache_sync(codec);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, RT5621_SPK_OUT_VOL, RT_L_MUTE | RT_R_MUTE, RT_L_MUTE | RT_R_MUTE);
+ snd_soc_update_bits(codec, RT5621_HP_OUT_VOL, RT_L_MUTE | RT_R_MUTE, RT_L_MUTE | RT_R_MUTE);
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD3, 0x0000);
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD2, 0x0000);
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD1, 0x0000);
+ break;
+
+ default:
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+
+
+struct rt5621_init_reg{
+
+ u8 reg_index;
+ u16 reg_value;
+};
+
+static struct rt5621_init_reg init_data[] = {
+ {RT5621_AUDIO_INTERFACE, 0x8000}, //set I2S codec to slave mode
+ {RT5621_STEREO_DAC_VOL, 0x0505}, //default stereo DAC volume to 0db
+ {RT5621_OUTPUT_MIXER_CTRL, 0x2b40}, //default output mixer control
+ {RT5621_ADC_REC_MIXER, 0x3f3f}, //set record source is Mic1 by default
+ {RT5621_MIC_CTRL, 0x0a00}, //set Mic1,Mic2 boost 20db
+ {RT5621_SPK_OUT_VOL, 0x8080}, //default speaker volume to 0db
+ {RT5621_HP_OUT_VOL, 0x8080}, //default HP volume to -12db
+ {RT5621_ADD_CTRL_REG, 0x4b00}, //Class AB/D speaker ratio is 1.25VDD
+ {RT5621_STEREO_AD_DA_CLK_CTRL, 0x066d}, //set Dac filter to 256fs
+ {RT5621_ADC_REC_GAIN, 0xfa95}, //set ADC boost to 15db
+ {RT5621_HID_CTRL_INDEX, 0x46}, //Class D setting
+ {RT5621_MIC_VOL, 0x1f08},
+ {RT5621_HID_CTRL_DATA, 0xFFFF}, //power on Class D Internal register
+ {RT5621_JACK_DET_CTRL, 0x4810}, //power on Class D Internal register
+};
+#define RT5621_INIT_REG_NUM ARRAY_SIZE(init_data)
+
+static int rt5621_reg_init(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for (i = 0; i < RT5621_INIT_REG_NUM; i++)
+ snd_soc_write(codec, init_data[i].reg_index, init_data[i].reg_value);
+
+ return 0;
+}
+
+void codec_set_spk(bool on)
+{
+ struct snd_soc_codec *codec = rt5621_codec;
+
+ DBG("%s: %d\n", __func__, on);
+
+ if(!codec)
+ return;
+
+ if(on){
+ DBG("snd_soc_dapm_enable_pin\n");
+ snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
+ snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
+ }
+ else{
+
+ DBG("snd_soc_dapm_disable_pin\n");
+ snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack");
+ snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
+ }
+
+ snd_soc_dapm_sync(&codec->dapm);
+
+ return;
+}
+
+static void rt5621_work(struct work_struct *work)
+{
+ struct snd_soc_codec *codec = rt5621_codec;
+
+ rt5621_set_bias_level(codec, codec->dapm.bias_level);
+}
+
+static int rt5621_probe(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+ codec->cache_bypass = 1;
+
+ rt5621_reset(codec);
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD3, 0x8000);//enable Main bias
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD2, 0x2000);//enable Vref
+ hp_depop_mode2(codec);
+ rt5621_reg_init(codec);
+
+#if ENABLE_EQ_HREQ
+
+ rt5621_write_index_reg(codec, 0x11,0x1);
+ rt5621_write_index_reg(codec, 0x12,0x1);
+ rt5621_update_eqmode(codec, HFREQ);
+
+#endif
+ rt5621_workq = create_freezable_workqueue("rt5621");
+ if (rt5621_workq == NULL) {
+ printk("wm8900_probe::create_freezeable_workqueue ERROR !");
+ kfree(codec);
+ return -ENOMEM;
+ }
+
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+ codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+
+ queue_delayed_work(rt5621_workq, &delayed_work,
+ msecs_to_jiffies(caps_charge));
+
+ codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+
+ rt5621_codec = codec;
+
+ return 0;
+}
+
+static int rt5621_remove(struct snd_soc_codec *codec)
+{
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ cancel_delayed_work_sync(&delayed_work);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5621_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int rt5621_resume(struct snd_soc_codec *codec)
+{
+
+ rt5621_reset(codec);
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD3, 0x8000);//enable Main bias
+ snd_soc_write(codec, RT5621_PWR_MANAG_ADD2, 0x2000);//enable Vref
+
+ hp_depop_mode2(codec);
+
+ rt5621_reg_init(codec);
+
+#if ENABLE_EQ_HREQ
+
+ rt5621_write_index_reg(codec, 0x11,0x1);
+ rt5621_write_index_reg(codec, 0x12,0x1);
+ rt5621_update_eqmode(codec, HFREQ);
+#endif
+
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+ codec->dapm.bias_level = SND_SOC_BIAS_ON;
+ queue_delayed_work(rt5621_workq, &delayed_work,
+ msecs_to_jiffies(caps_charge));
+ }
+ return 0;
+}
+#else
+#define rt5621_suspend NULL
+#define rt5621_resume NULL
+#endif
+
+static void rt5621_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *codec_dai)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int stream = substream->stream;
+
+ switch (stream)
+ {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_SPK,1); //mute speaker out
+
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_HP,1); //mute hp out
+
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_AUXOUT,1); //mute auxout
+
+ rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D2_PLAYBACK); //power off dac to hp and speaker out and auxout
+
+
+
+ break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+
+ Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,0); //disable record source from mic1
+
+ rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D2_RECORD);
+
+
+ break;
+ }
+}
+
+//#define RT5621_HIFI_RATES SNDRV_PCM_RATE_8000_48000
+#define RT5621_HIFI_RATES (SNDRV_PCM_RATE_44100) // zyy 20110704, playback and record use same sample rate
+
+#define RT5621_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai_ops rt5621_hifi_ops = {
+ .hw_params = rt5621_pcm_hw_params,
+ .set_fmt = rt5621_set_dai_fmt,
+ .set_sysclk = rt5621_set_dai_sysclk,
+ .set_pll = rt5621_set_dai_pll,
+ .prepare = rt5621_pcm_hw_prepare,
+ .shutdown = rt5621_shutdown,
+};
+
+struct snd_soc_dai_driver rt5621_dai = {
+ .name = "RT5621 HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5621_HIFI_RATES,
+ .formats = RT5621_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5621_HIFI_RATES,
+ .formats = RT5621_FORMATS,
+ },
+ .ops = &rt5621_hifi_ops,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5621 = {
+ .probe = rt5621_probe,
+ .remove = rt5621_remove,
+ .suspend = rt5621_suspend,
+ .resume = rt5621_resume,
+ .set_bias_level = rt5621_set_bias_level,
+ .reg_cache_size = RT5621_VENDOR_ID2 + 1,
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = rt5621_reg,
+ .volatile_register = rt5621_volatile_register,
+ .readable_register = rt5621_readable_register,
+ .reg_cache_step = 1,
+ .controls = rt5621_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5621_snd_controls),
+};
+
+static const struct i2c_device_id rt5621_i2c_id[] = {
+ { "rt5621", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5621_i2c_id);
+
+static int rt5621_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5621_priv *rt5621;
+ int ret;
+
+ rt5621 = kzalloc(sizeof(struct rt5621_priv), GFP_KERNEL);
+ if (NULL == rt5621)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt5621);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_rt5621, &rt5621_dai, 1);
+ if (ret < 0)
+ kfree(rt5621);
+
+ return ret;
+}
+
+static __devexit int rt5621_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+ kfree(i2c_get_clientdata(i2c));
+ return 0;
+}
+
+struct i2c_driver rt5621_i2c_driver = {
+ .driver = {
+ .name = "RT5621",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5621_i2c_probe,
+ .remove = __devexit_p(rt5621_i2c_remove),
+ .id_table = rt5621_i2c_id,
+};
+
+static int __init rt5621_modinit(void)
+{
+ return i2c_add_driver(&rt5621_i2c_driver);
+}
+module_init(rt5621_modinit);
+
+static void __exit rt5621_modexit(void)
+{
+ i2c_del_driver(&rt5621_i2c_driver);
+}
+module_exit(rt5621_modexit);
+
+MODULE_DESCRIPTION("ASoC RT5621 driver");
+MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * rt5621.h -- RT5621 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5621_H__
+#define __RT5621_H__
+
+#define RT5621_RESET 0X00 //RESET CODEC TO DEFAULT
+#define RT5621_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME
+#define RT5621_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME
+#define RT5621_MONO_AUX_OUT_VOL 0X06 //MONO OUTPUT/AUXOUT VOLUME
+#define RT5621_AUXIN_VOL 0X08 //AUXIN VOLUME
+#define RT5621_LINE_IN_VOL 0X0A //LINE IN VOLUME
+#define RT5621_STEREO_DAC_VOL 0X0C //STEREO DAC VOLUME
+#define RT5621_MIC_VOL 0X0E //MICROPHONE VOLUME
+#define RT5621_MIC_ROUTING_CTRL 0X10 //MIC ROUTING CONTROL
+#define RT5621_ADC_REC_GAIN 0X12 //ADC RECORD GAIN
+#define RT5621_ADC_REC_MIXER 0X14 //ADC RECORD MIXER CONTROL
+#define RT5621_SOFT_VOL_CTRL_TIME 0X16 //SOFT VOLUME CONTROL TIME
+#define RT5621_OUTPUT_MIXER_CTRL 0X1C //OUTPUT MIXER CONTROL
+#define RT5621_MIC_CTRL 0X22 //MICROPHONE CONTROL
+#define RT5621_AUDIO_INTERFACE 0X34 //AUDIO INTERFACE
+#define RT5621_STEREO_AD_DA_CLK_CTRL 0X36 //STEREO AD/DA CLOCK CONTROL
+#define RT5621_COMPANDING_CTRL 0X38 //COMPANDING CONTROL
+#define RT5621_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1
+#define RT5621_PWR_MANAG_ADD2 0X3C //POWER MANAGMENT ADDITION 2
+#define RT5621_PWR_MANAG_ADD3 0X3E //POWER MANAGMENT ADDITION 3
+#define RT5621_ADD_CTRL_REG 0X40 //ADDITIONAL CONTROL REGISTER
+#define RT5621_GLOBAL_CLK_CTRL_REG 0X42 //GLOBAL CLOCK CONTROL REGISTER
+#define RT5621_PLL_CTRL 0X44 //PLL CONTROL
+#define RT5621_GPIO_OUTPUT_PIN_CTRL 0X4A //GPIO OUTPUT PIN CONTROL
+#define RT5621_GPIO_PIN_CONFIG 0X4C //GPIO PIN CONFIGURATION
+#define RT5621_GPIO_PIN_POLARITY 0X4E //GPIO PIN POLARITY/TYPE
+#define RT5621_GPIO_PIN_STICKY 0X50 //GPIO PIN STICKY
+#define RT5621_GPIO_PIN_WAKEUP 0X52 //GPIO PIN WAKE UP
+#define RT5621_GPIO_PIN_STATUS 0X54 //GPIO PIN STATUS
+#define RT5621_GPIO_PIN_SHARING 0X56 //GPIO PIN SHARING
+#define RT5621_OVER_TEMP_CURR_STATUS 0X58 //OVER TEMPERATURE AND CURRENT STATUS
+#define RT5621_JACK_DET_CTRL 0X5A //JACK DETECT CONTROL REGISTER
+#define RT5621_MISC_CTRL 0X5E //MISC CONTROL
+#define RT5621_PSEDUEO_SPATIAL_CTRL 0X60 //PSEDUEO STEREO & SPATIAL EFFECT BLOCK CONTROL
+#define RT5621_EQ_CTRL 0X62 //EQ CONTROL
+#define RT5621_EQ_MODE_ENABLE 0X66 //EQ MODE CHANGE ENABLE
+#define RT5621_AVC_CTRL 0X68 //AVC CONTROL
+#define RT5621_HID_CTRL_INDEX 0X6A //HIDDEN CONTROL INDEX PORT
+#define RT5621_HID_CTRL_DATA 0X6C //HIDDEN CONTROL DATA PORT
+#define RT5621_VENDOR_ID1 0x7C //VENDOR ID1
+#define RT5621_VENDOR_ID2 0x7E //VENDOR ID2
+
+
+//global definition
+#define RT_L_MUTE (0x1<<15) //MUTE LEFT CONTROL BIT
+#define RT_L_ZC (0x1<<14) //LEFT ZERO CROSS CONTROL BIT
+#define RT_L_SM (0x1<<13) //LEFT SOFTMUTE CONTROL BIT
+#define RT_R_MUTE (0x1<<7) //MUTE RIGHT CONTROL BIT
+#define RT_R_ZC (0x1<<6) //RIGHT ZERO CROSS CONTROL BIT
+#define RT_R_SM (0x1<<5) //RIGHT SOFTMUTE CONTROL BIT
+#define RT_M_HP_MIXER (0x1<<15) //Mute source to HP Mixer
+#define RT_M_SPK_MIXER (0x1<<14) //Mute source to Speaker Mixer
+#define RT_M_MONO_MIXER (0x1<<13) //Mute source to Mono Mixer
+#define SPK_CLASS_AB 0
+#define SPK_CLASS_D 1
+
+//Mic Routing Control(0x10)
+#define M_MIC1_TO_HP_MIXER (0x1<<15) //Mute MIC1 to HP mixer
+#define M_MIC1_TO_SPK_MIXER (0x1<<14) //Mute MiC1 to SPK mixer
+#define M_MIC1_TO_MONO_MIXER (0x1<<13) //Mute MIC1 to MONO mixer
+#define MIC1_DIFF_INPUT_CTRL (0x1<<12) //MIC1 different input control
+#define M_MIC2_TO_HP_MIXER (0x1<<7) //Mute MIC2 to HP mixer
+#define M_MIC2_TO_SPK_MIXER (0x1<<6) //Mute MiC2 to SPK mixer
+#define M_MIC2_TO_MONO_MIXER (0x1<<5) //Mute MIC2 to MONO mixer
+#define MIC2_DIFF_INPUT_CTRL (0x1<<4) //MIC2 different input control
+
+//ADC Record Gain(0x12)
+#define M_ADC_L_TO_HP_MIXER (0x1<<15) //Mute left of ADC to HP Mixer
+#define M_ADC_R_TO_HP_MIXER (0x1<<14) //Mute right of ADC to HP Mixer
+#define M_ADC_L_TO_MONO_MIXER (0x1<<13) //Mute left of ADC to MONO Mixer
+#define M_ADC_R_TO_MONO_MIXER (0x1<<12) //Mute right of ADC to MONO Mixer
+#define ADC_L_GAIN_MASK (0x1f<<7) //ADC Record Gain Left channel Mask
+#define ADC_L_ZC_DET (0x1<<6) //ADC Zero-Cross Detector Control
+#define ADC_R_ZC_DET (0x1<<5) //ADC Zero-Cross Detector Control
+#define ADC_R_GAIN_MASK (0x1f<<0) //ADC Record Gain Right channel Mask
+
+//ADC Input Mixer Control(0x14)
+#define M_MIC1_TO_ADC_L_MIXER (0x1<<14) //Mute mic1 to left channel of ADC mixer
+#define M_MIC2_TO_ADC_L_MIXER (0x1<<13) //Mute mic2 to left channel of ADC mixer
+#define M_LINEIN_L_TO_ADC_L_MIXER (0x1<<12) //Mute line In left channel to left channel of ADC mixer
+#define M_AUXIN_L_TO_ADC_L_MIXER (0x1<<11) //Mute aux In left channel to left channel of ADC mixer
+#define M_HPMIXER_L_TO_ADC_L_MIXER (0x1<<10) //Mute HP mixer left channel to left channel of ADC mixer
+#define M_SPKMIXER_L_TO_ADC_L_MIXER (0x1<<9) //Mute SPK mixer left channel to left channel of ADC mixer
+#define M_MONOMIXER_L_TO_ADC_L_MIXER (0x1<<8) //Mute MONO mixer left channel to left channel of ADC mixer
+#define M_MIC1_TO_ADC_R_MIXER (0x1<<6) //Mute mic1 to right channel of ADC mixer
+#define M_MIC2_TO_ADC_R_MIXER (0x1<<5) //Mute mic2 to right channel of ADC mixer
+#define M_LINEIN_R_TO_ADC_R_MIXER (0x1<<4) //Mute lineIn right channel to right channel of ADC mixer
+#define M_AUXIN_R_TO_ADC_R_MIXER (0x1<<3) //Mute aux In right channel to right channel of ADC mixer
+#define M_HPMIXER_R_TO_ADC_R_MIXER (0x1<<2) //Mute HP mixer right channel to right channel of ADC mixer
+#define M_SPKMIXER_R_TO_ADC_R_MIXER (0x1<<1) //Mute SPK mixer right channel to right channel of ADC mixer
+#define M_MONOMIXER_R_TO_ADC_R_MIXER (0x1<<0) //Mute MONO mixer right channel to right channel of ADC mixer
+
+//Output Mixer Control(0x1C)
+#define SPKOUT_N_SOUR_MASK (0x3<<14)
+#define SPKOUT_N_SOUR_LN (0x2<<14)
+#define SPKOUT_N_SOUR_RP (0x1<<14)
+#define SPKOUT_N_SOUR_RN (0x0<<14)
+#define SPK_OUTPUT_CLASS_AB (0x0<<13)
+#define SPK_OUTPUT_CLASS_D (0x1<<13)
+#define SPK_CLASS_AB_S_AMP (0x0<<12)
+#define SPK_CALSS_AB_W_AMP (0x1<<12)
+#define SPKOUT_INPUT_SEL_MASK (0x3<<10)
+#define SPKOUT_INPUT_SEL_MONOMIXER (0x3<<10)
+#define SPKOUT_INPUT_SEL_SPKMIXER (0x2<<10)
+#define SPKOUT_INPUT_SEL_HPMIXER (0x1<<10)
+#define SPKOUT_INPUT_SEL_VMID (0x0<<10)
+#define HPL_INPUT_SEL_HPLMIXER (0x1<<9)
+#define HPR_INPUT_SEL_HPRMIXER (0x1<<8)
+#define MONO_AUX_INPUT_SEL_MASK (0x3<<6)
+#define MONO_AUX_INPUT_SEL_MONO (0x3<<6)
+#define MONO_AUX_INPUT_SEL_SPK (0x2<<6)
+#define MONO_AUX_INPUT_SEL_HP (0x1<<6)
+#define MONO_AUX_INPUT_SEL_VMID (0x0<<6)
+
+//Micphone Control define(0x22)
+#define MIC1 1
+#define MIC2 2
+#define MIC_BIAS_90_PRECNET_AVDD 1
+#define MIC_BIAS_75_PRECNET_AVDD 2
+
+#define MIC1_BOOST_CTRL_MASK (0x3<<10)
+#define MIC1_BOOST_CTRL_BYPASS (0x0<<10)
+#define MIC1_BOOST_CTRL_20DB (0x1<<10)
+#define MIC1_BOOST_CTRL_30DB (0x2<<10)
+#define MIC1_BOOST_CTRL_40DB (0x3<<10)
+
+#define MIC2_BOOST_CTRL_MASK (0x3<<8)
+#define MIC2_BOOST_CTRL_BYPASS (0x0<<8)
+#define MIC2_BOOST_CTRL_20DB (0x1<<8)
+#define MIC2_BOOST_CTRL_30DB (0x2<<8)
+#define MIC2_BOOST_CTRL_40DB (0x3<<8)
+
+#define MICBIAS_VOLT_CTRL_MASK (0x1<<5)
+#define MICBIAS_VOLT_CTRL_90P (0x0<<5)
+#define MICBIAS_VOLT_CTRL_75P (0x1<<5)
+
+#define MICBIAS_SHORT_CURR_DET_MASK (0x3)
+#define MICBIAS_SHORT_CURR_DET_600UA (0x0)
+#define MICBIAS_SHORT_CURR_DET_1200UA (0x1)
+#define MICBIAS_SHORT_CURR_DET_1800UA (0x2)
+
+//Audio Interface(0x34)
+#define SDP_MASTER_MODE (0x0<<15) //Main I2S interface select Master mode
+#define SDP_SLAVE_MODE (0x1<<15) //Main I2S interface select Slave mode
+#define I2S_PCM_MODE (0x1<<14) //PCM 0:mode A ,1:mode B
+#define MAIN_I2S_BCLK_POL_CTRL (0x1<<7) //0:Normal 1:Invert
+#define ADC_DATA_L_R_SWAP (0x1<<5) //0:ADC data appear at left phase of LRCK
+ //1:ADC data appear at right phase of LRCK
+#define DAC_DATA_L_R_SWAP (0x1<<4) //0:DAC data appear at left phase of LRCK
+ //1:DAC data appear at right phase of LRCK
+//Data Length Slection
+#define I2S_DL_MASK (0x3<<2) //main i2s Data Length mask
+#define I2S_DL_16 (0x0<<2) //16 bits
+#define I2S_DL_20 (0x1<<2) //20 bits
+#define I2S_DL_24 (0x2<<2) //24 bits
+#define I2S_DL_32 (0x3<<2) //32 bits
+
+//PCM Data Format Selection
+#define I2S_DF_MASK (0x3) //main i2s Data Format mask
+#define I2S_DF_I2S (0x0) //I2S FORMAT
+#define I2S_DF_RIGHT (0x1) //RIGHT JUSTIFIED format
+#define I2S_DF_LEFT (0x2) //LEFT JUSTIFIED format
+#define I2S_DF_PCM (0x3) //PCM format
+
+//Stereo AD/DA Clock Control(0x36h)
+#define I2S_PRE_DIV_MASK (0x7<<12)
+#define I2S_PRE_DIV_1 (0x0<<12) //DIV 1
+#define I2S_PRE_DIV_2 (0x1<<12) //DIV 2
+#define I2S_PRE_DIV_4 (0x2<<12) //DIV 4
+#define I2S_PRE_DIV_8 (0x3<<12) //DIV 8
+#define I2S_PRE_DIV_16 (0x4<<12) //DIV 16
+#define I2S_PRE_DIV_32 (0x5<<12) //DIV 32
+
+#define I2S_SCLK_DIV_MASK (0x7<<9)
+#define I2S_SCLK_DIV_1 (0x0<<9) //DIV 1
+#define I2S_SCLK_DIV_2 (0x1<<9) //DIV 2
+#define I2S_SCLK_DIV_3 (0x2<<9) //DIV 3
+#define I2S_SCLK_DIV_4 (0x3<<9) //DIV 4
+#define I2S_SCLK_DIV_6 (0x4<<9) //DIV 6
+#define I2S_SCLK_DIV_8 (0x5<<9) //DIV 8
+#define I2S_SCLK_DIV_12 (0x6<<9) //DIV 12
+#define I2S_SCLK_DIV_16 (0x7<<9) //DIV 16
+
+#define I2S_WCLK_DIV_PRE_MASK (0xF<<5)
+#define I2S_WCLK_PRE_DIV_1 (0x0<<5) //DIV 1
+#define I2S_WCLK_PRE_DIV_2 (0x1<<5) //DIV 2
+#define I2S_WCLK_PRE_DIV_3 (0x2<<5) //DIV 3
+#define I2S_WCLK_PRE_DIV_4 (0x3<<5) //DIV 4
+#define I2S_WCLK_PRE_DIV_5 (0x4<<5) //DIV 5
+#define I2S_WCLK_PRE_DIV_6 (0x5<<5) //DIV 6
+#define I2S_WCLK_PRE_DIV_7 (0x6<<5) //DIV 7
+#define I2S_WCLK_PRE_DIV_8 (0x7<<5) //DIV 8
+//........................
+
+#define I2S_WCLK_DIV_MASK (0x7<<2)
+#define I2S_WCLK_DIV_2 (0x0<<2) //DIV 2
+#define I2S_WCLK_DIV_4 (0x1<<2) //DIV 4
+#define I2S_WCLK_DIV_8 (0x2<<2) //DIV 8
+#define I2S_WCLK_DIV_16 (0x3<<2) //DIV 16
+#define I2S_WCLK_DIV_32 (0x4<<2) //DIV 32
+
+#define ADDA_FILTER_CLK_SEL_256FS (0<<1) //256FS
+#define ADDA_FILTER_CLK_SEL_384FS (1<<1) //384FS
+
+#define ADDA_OSR_SEL_64FS (0) //64FS
+#define ADDA_OSR_SEL_128FS (1) //128FS
+
+//Power managment addition 1 (0x3A),0:Disable,1:Enable
+#define PWR_MAIN_I2S_EN (0x1<<15)
+#define PWR_ZC_DET_PD_EN (0x1<<14)
+#define PWR_MIC1_BIAS_EN (0x1<<11)
+#define PWR_SHORT_CURR_DET_EN (0x1<<10)
+#define PWR_SOFTGEN_EN (0x1<<8)
+#define PWR_DEPOP_BUF_HP (0x1<<6)
+#define PWR_HP_OUT_AMP (0x1<<5)
+#define PWR_HP_OUT_ENH_AMP (0x1<<4)
+#define PWR_DEPOP_BUF_AUX (0x1<<2)
+#define PWR_AUX_OUT_AMP (0x1<<1)
+#define PWR_AUX_OUT_ENH_AMP (0x1)
+
+
+//Power managment addition 2(0x3C),0:Disable,1:Enable
+#define PWR_CLASS_AB (0x1<<15)
+#define PWR_CLASS_D (0x1<<14)
+#define PWR_VREF (0x1<<13)
+#define PWR_PLL (0x1<<12)
+#define PWR_DAC_REF_CIR (0x1<<10)
+#define PWR_L_DAC_CLK (0x1<<9)
+#define PWR_R_DAC_CLK (0x1<<8)
+#define PWR_L_ADC_CLK_GAIN (0x1<<7)
+#define PWR_R_ADC_CLK_GAIN (0x1<<6)
+#define PWR_L_HP_MIXER (0x1<<5)
+#define PWR_R_HP_MIXER (0x1<<4)
+#define PWR_SPK_MIXER (0x1<<3)
+#define PWR_MONO_MIXER (0x1<<2)
+#define PWR_L_ADC_REC_MIXER (0x1<<1)
+#define PWR_R_ADC_REC_MIXER (0x1)
+
+//Power managment addition 3(0x3E),0:Disable,1:Enable
+#define PWR_MAIN_BIAS (0x1<<15)
+#define PWR_AUXOUT_L_VOL_AMP (0x1<<14)
+#define PWR_AUXOUT_R_VOL_AMP (0x1<<13)
+#define PWR_SPK_OUT (0x1<<12)
+#define PWR_HP_L_OUT_VOL (0x1<<10)
+#define PWR_HP_R_OUT_VOL (0x1<<9)
+#define PWR_LINEIN_L_VOL (0x1<<7)
+#define PWR_LINEIN_R_VOL (0x1<<6)
+#define PWR_AUXIN_L_VOL (0x1<<5)
+#define PWR_AUXIN_R_VOL (0x1<<4)
+#define PWR_MIC1_FUN_CTRL (0x1<<3)
+#define PWR_MIC2_FUN_CTRL (0x1<<2)
+#define PWR_MIC1_BOOST_MIXER (0x1<<1)
+#define PWR_MIC2_BOOST_MIXER (0x1)
+
+
+//Additional Control Register(0x40)
+#define AUXOUT_SEL_DIFF (0x1<<15) //Differential Mode
+#define AUXOUT_SEL_SE (0x1<<15) //Single-End Mode
+
+#define SPK_AB_AMP_CTRL_MASK (0x7<<12)
+#define SPK_AB_AMP_CTRL_RATIO_225 (0x0<<12) //2.25 Vdd
+#define SPK_AB_AMP_CTRL_RATIO_200 (0x1<<12) //2.00 Vdd
+#define SPK_AB_AMP_CTRL_RATIO_175 (0x2<<12) //1.75 Vdd
+#define SPK_AB_AMP_CTRL_RATIO_150 (0x3<<12) //1.50 Vdd
+#define SPK_AB_AMP_CTRL_RATIO_125 (0x4<<12) //1.25 Vdd
+#define SPK_AB_AMP_CTRL_RATIO_100 (0x5<<12) //1.00 Vdd
+
+#define SPK_D_AMP_CTRL_MASK (0x3<<10)
+#define SPK_D_AMP_CTRL_RATIO_175 (0x0<<10) //1.75 Vdd
+#define SPK_D_AMP_CTRL_RATIO_150 (0x1<<10) //1.50 Vdd
+#define SPK_D_AMP_CTRL_RATIO_125 (0x2<<10) //1.25 Vdd
+#define SPK_D_AMP_CTRL_RATIO_100 (0x3<<10) //1.00 Vdd
+
+#define STEREO_DAC_HI_PASS_FILTER_EN (0x1<<9) //Stereo DAC high pass filter enable
+#define STEREO_ADC_HI_PASS_FILTER_EN (0x1<<8) //Stereo ADC high pass filter enable
+
+#define DIG_VOL_BOOST_MASK (0x3<<4) //Digital volume Boost mask
+#define DIG_VOL_BOOST_0DB (0x0<<4) //Digital volume Boost 0DB
+#define DIG_VOL_BOOST_6DB (0x1<<4) //Digital volume Boost 6DB
+#define DIG_VOL_BOOST_12DB (0x2<<4) //Digital volume Boost 12DB
+#define DIG_VOL_BOOST_18DB (0x3<<4) //Digital volume Boost 18DB
+
+
+//Global Clock Control Register(0x42)
+#define SYSCLK_SOUR_SEL_MASK (0x1<<15)
+#define SYSCLK_SOUR_SEL_MCLK (0x0<<15) //system Clock source from MCLK
+#define SYSCLK_SOUR_SEL_PLL (0x1<<15) //system Clock source from PLL
+#define PLLCLK_SOUR_SEL_MCLK (0x0<<14) //PLL clock source from MCLK
+#define PLLCLK_SOUR_SEL_BITCLK (0x1<<14) //PLL clock source from BITCLK
+
+#define PLLCLK_DIV_RATIO_MASK (0x3<<1)
+#define PLLCLK_DIV_RATIO_DIV1 (0x0<<1) //DIV 1
+#define PLLCLK_DIV_RATIO_DIV2 (0x1<<1) //DIV 2
+#define PLLCLK_DIV_RATIO_DIV4 (0x2<<1) //DIV 4
+#define PLLCLK_DIV_RATIO_DIV8 (0x3<<1) //DIV 8
+
+#define PLLCLK_PRE_DIV1 (0x0) //DIV 1
+#define PLLCLK_PRE_DIV2 (0x1) //DIV 2
+
+//PLL Control(0x44)
+
+#define PLL_CTRL_M_VAL(m) ((m)&0xf)
+#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4)
+#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8)
+
+//GPIO Pin Configuration(0x4C)
+#define GPIO_PIN_MASK (0x1<<1)
+#define GPIO_PIN_SET_INPUT (0x1<<1)
+#define GPIO_PIN_SET_OUTPUT (0x0<<1)
+
+//Pin Sharing(0x56)
+#define LINEIN_L_PIN_SHARING (0x1<<15)
+#define LINEIN_L_PIN_AS_LINEIN_L (0x0<<15)
+#define LINEIN_L_PIN_AS_JD1 (0x1<<15)
+
+#define LINEIN_R_PIN_SHARING (0x1<<14)
+#define LINEIN_R_PIN_AS_LINEIN_R (0x0<<14)
+#define LINEIN_R_PIN_AS_JD2 (0x1<<14)
+
+#define GPIO_PIN_SHARING (0x3)
+#define GPIO_PIN_AS_GPIO (0x0)
+#define GPIO_PIN_AS_IRQOUT (0x1)
+#define GPIO_PIN_AS_PLLOUT (0x3)
+
+//Jack Detect Control Register(0x5A)
+#define JACK_DETECT_MASK (0x3<<14)
+#define JACK_DETECT_USE_JD2 (0x3<<14)
+#define JACK_DETECT_USE_JD1 (0x2<<14)
+#define JACK_DETECT_USE_GPIO (0x1<<14)
+#define JACK_DETECT_OFF (0x0<<14)
+
+#define SPK_EN_IN_HI (0x1<<11)
+#define AUX_R_EN_IN_HI (0x1<<10)
+#define AUX_L_EN_IN_HI (0x1<<9)
+#define HP_EN_IN_HI (0x1<<8)
+#define SPK_EN_IN_LO (0x1<<7)
+#define AUX_R_EN_IN_LO (0x1<<6)
+#define AUX_L_EN_IN_LO (0x1<<5)
+#define HP_EN_IN_LO (0x1<<4)
+
+////MISC CONTROL(0x5E)
+#define DISABLE_FAST_VREG (0x1<<15)
+#define SPK_CLASS_AB_OC_PD (0x1<<13)
+#define SPK_CLASS_AB_OC_DET (0x1<<12)
+#define HP_DEPOP_MODE3_EN (0x1<<10)
+#define HP_DEPOP_MODE2_EN (0x1<<9)
+#define HP_DEPOP_MODE1_EN (0x1<<8)
+#define AUXOUT_DEPOP_MODE3_EN (0x1<<6)
+#define AUXOUT_DEPOP_MODE2_EN (0x1<<5)
+#define AUXOUT_DEPOP_MODE1_EN (0x1<<4)
+#define M_DAC_L_INPUT (0x1<<3)
+#define M_DAC_R_INPUT (0x1<<2)
+#define IRQOUT_INV_CTRL (0x1<<0)
+
+//Psedueo Stereo & Spatial Effect Block Control(0x60)
+#define SPATIAL_CTRL_EN (0x1<<15)
+#define ALL_PASS_FILTER_EN (0x1<<14)
+#define PSEUDO_STEREO_EN (0x1<<13)
+#define STEREO_EXPENSION_EN (0x1<<12)
+
+#define GAIN_3D_PARA_L_MASK (0x7<<9)
+#define GAIN_3D_PARA_L_1_00 (0x0<<9)
+#define GAIN_3D_PARA_L_1_25 (0x1<<9)
+#define GAIN_3D_PARA_L_1_50 (0x2<<9)
+#define GAIN_3D_PARA_L_1_75 (0x3<<9)
+#define GAIN_3D_PARA_L_2_00 (0x4<<9)
+
+#define GAIN_3D_PARA_R_MASK (0x7<<6)
+#define GAIN_3D_PARA_R_1_00 (0x0<<6)
+#define GAIN_3D_PARA_R_1_25 (0x1<<6)
+#define GAIN_3D_PARA_R_1_50 (0x2<<6)
+#define GAIN_3D_PARA_R_1_75 (0x3<<6)
+#define GAIN_3D_PARA_R_2_00 (0x4<<6)
+
+#define RATIO_3D_L_MASK (0x3<<4)
+#define RATIO_3D_L_0_0 (0x0<<4)
+#define RATIO_3D_L_0_66 (0x1<<4)
+#define RATIO_3D_L_1_0 (0x2<<4)
+
+#define RATIO_3D_R_MASK (0x3<<2)
+#define RATIO_3D_R_0_0 (0x0<<2)
+#define RATIO_3D_R_0_66 (0x1<<2)
+#define RATIO_3D_R_1_0 (0x2<<2)
+
+#define APF_MASK (0x3)
+#define APF_FOR_48K (0x3)
+#define APF_FOR_44_1K (0x2)
+#define APF_FOR_32K (0x1)
+
+//EQ CONTROL(0x62)
+
+#define EN_HW_EQ_BLK (0x1<<15) //HW EQ block control
+#define EN_HW_EQ_HPF_MODE (0x1<<14) //High Frequency shelving filter mode
+#define EN_HW_EQ_SOUR (0x1<<11) //0:DAC PATH,1:ADC PATH
+#define EN_HW_EQ_HPF (0x1<<4) //EQ High Pass Filter Control
+#define EN_HW_EQ_BP3 (0x1<<3) //EQ Band-3 Control
+#define EN_HW_EQ_BP2 (0x1<<2) //EQ Band-2 Control
+#define EN_HW_EQ_BP1 (0x1<<1) //EQ Band-1 Control
+#define EN_HW_EQ_LPF (0x1<<0) //EQ Low Pass Filter Control
+
+//EQ Mode Change Enable(0x66)
+#define EQ_HPF_CHANGE_EN (0x1<<4) //EQ High Pass Filter Mode Change Enable
+#define EQ_BP3_CHANGE_EN (0x1<<3) //EQ Band-3 Pass Filter Mode Change Enable
+#define EQ_BP2_CHANGE_EN (0x1<<2) //EQ Band-2 Pass Filter Mode Change Enable
+#define EQ_BP1_CHANGE_EN (0x1<<1) //EQ Band-1 Pass Filter Mode Change Enable
+#define EQ_LPF_CHANGE_EN (0x1<<0) //EQ Low Pass Filter Mode Change Enable
+
+
+//AVC Control(0x68)
+#define AVC_ENABLE (0x1<<15)
+#define AVC_TARTGET_SEL_MASK (0x1<<14)
+#define AVC_TARTGET_SEL_R (0x1<<14)
+#define AVC_TARTGET_SEL_L (0x0<<14)
+
+
+#define RT5621_PLL_FR_MCLK 0
+#define RT5621_PLL_FR_BCLK 1
+
+
+#define REALTEK_HWDEP 0
+
+//WaveOut channel for realtek codec
+enum
+{
+ RT_WAVOUT_SPK =(0x1<<0),
+ RT_WAVOUT_SPK_R =(0x1<<1),
+ RT_WAVOUT_SPK_L =(0x1<<2),
+ RT_WAVOUT_HP =(0x1<<3),
+ RT_WAVOUT_HP_R =(0x1<<4),
+ RT_WAVOUT_HP_L =(0x1<<5),
+ RT_WAVOUT_MONO =(0x1<<6),
+ RT_WAVOUT_AUXOUT =(0x1<<7),
+ RT_WAVOUT_AUXOUT_R =(0x1<<8),
+ RT_WAVOUT_AUXOUT_L =(0x1<<9),
+ RT_WAVOUT_LINEOUT =(0x1<<10),
+ RT_WAVOUT_LINEOUT_R =(0x1<<11),
+ RT_WAVOUT_LINEOUT_L =(0x1<<12),
+ RT_WAVOUT_DAC =(0x1<<13),
+ RT_WAVOUT_ALL_ON =(0x1<<14),
+};
+
+//WaveIn channel for realtek codec
+enum
+{
+ RT_WAVIN_R_MONO_MIXER =(0x1<<0),
+ RT_WAVIN_R_SPK_MIXER =(0x1<<1),
+ RT_WAVIN_R_HP_MIXER =(0x1<<2),
+ RT_WAVIN_R_PHONE =(0x1<<3),
+ RT_WAVIN_R_AUXIN =(0x1<<3),
+ RT_WAVIN_R_LINE_IN =(0x1<<4),
+ RT_WAVIN_R_MIC2 =(0x1<<5),
+ RT_WAVIN_R_MIC1 =(0x1<<6),
+
+ RT_WAVIN_L_MONO_MIXER =(0x1<<8),
+ RT_WAVIN_L_SPK_MIXER =(0x1<<9),
+ RT_WAVIN_L_HP_MIXER =(0x1<<10),
+ RT_WAVIN_L_PHONE =(0x1<<11),
+ RT_WAVIN_L_AUXIN =(0x1<<11),
+ RT_WAVIN_L_LINE_IN =(0x1<<12),
+ RT_WAVIN_L_MIC2 =(0x1<<13),
+ RT_WAVIN_L_MIC1 =(0x1<<14),
+};
+
+enum
+{
+ POWER_STATE_D0=0,
+ POWER_STATE_D1,
+ POWER_STATE_D1_PLAYBACK,
+ POWER_STATE_D1_RECORD,
+ POWER_STATE_D2,
+ POWER_STATE_D2_PLAYBACK,
+ POWER_STATE_D2_RECORD,
+ POWER_STATE_D3,
+ POWER_STATE_D4
+
+};
+
+#if REALTEK_HWDEP
+
+struct rt56xx_reg_state
+{
+ unsigned int reg_index;
+ unsigned int reg_value;
+};
+
+struct rt56xx_cmd
+{
+ size_t number;
+ struct rt56xx_reg_state __user *buf;
+};
+
+enum
+{
+ RT_READ_CODEC_REG_IOCTL = _IOR('R', 0x01, struct rt56xx_cmd),
+ RT_READ_ALL_CODEC_REG_IOCTL = _IOR('R', 0x02, struct rt56xx_cmd),
+ RT_WRITE_CODEC_REG_IOCTL = _IOW('R', 0x03, struct rt56xx_cmd),
+};
+
+#endif
+
+#endif /* __RT5621_H__ */
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
+#define DEBUG
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
static struct platform_driver wm8994_codec_driver = {
.driver = {
- .name = "wm8994-codec",
+ .name = "WM8994",
.owner = THIS_MODULE,
},
.probe = wm8994_probe,
help
Say Y if you want to add support for SoC audio on rockchip
with the WM8900.
-config SND_RK29_SOC_alc5621
- tristate "SoC I2S Audio support for rockchip - alc5621"
+config SND_RK29_SOC_RT5621
+ tristate "SoC I2S Audio support for rockchip - rt5621"
depends on SND_RK29_SOC && I2C_RK29
select SND_RK29_SOC_I2S
- select SND_SOC_alc5621
+ select SND_SOC_RT5621
help
Say Y if you want to add support for SoC audio on rockchip
- with the alc5621.
+ with the rt5621.
config SND_RK29_SOC_RT5631
tristate "SoC I2S Audio support for rockchip - RT5631"
depends on SND_RK29_SOC && I2C_RK29
Say Y if you want to add support for SoC audio on rockchip
with the RK1000.
-if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_alc5621 || SND_RK29_SOC_RT5631 || SND_RK29_SOC_RT5625 || SND_RK29_SOC_CS42L52
+if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_RT5621 || SND_RK29_SOC_RT5631 || SND_RK29_SOC_RT5625 || SND_RK29_SOC_CS42L52
choice
prompt "Set i2s type"
config SND_RK29_CODEC_SOC_MASTER
# ROCKCHIP Machine Support
snd-soc-wm8900-objs := rk29_wm8900.o
-snd-soc-alc5621-objs := rk29_alc5621.o
+snd-soc-rt5621-objs := rk29_rt5621.o
snd-soc-rt5631-objs := rk29_rt5631.o
snd-soc-rt5625-objs := rk29_rt5625.o
snd-soc-cs42l52-objs := rk29_cs42l52.o
obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o
obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_RK29_SOC_WM8900) += snd-soc-wm8900.o
-obj-$(CONFIG_SND_RK29_SOC_alc5621) += snd-soc-alc5621.o
+obj-$(CONFIG_SND_RK29_SOC_RT5621) += snd-soc-rt5621.o
obj-$(CONFIG_SND_RK29_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_RK29_SOC_RT5625) += snd-soc-rt5625.o
obj-$(CONFIG_SND_RK29_SOC_RK1000) += snd-soc-rk1000.o
--- /dev/null
+/*
+ * rk29_rt5621.c -- SoC audio for rockchip
+ *
+ * Driver for rockchip rt5621 audio
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/rk29_iomap.h>
+#include "../codecs/rt5621.h"
+#include "rk29_pcm.h"
+#include "rk29_i2s.h"
+
+#if 0
+#define DBG(x...) printk(KERN_INFO x)
+#else
+#define DBG(x...)
+#endif
+
+static int rk29_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 0;
+ unsigned int lrclk = 0;
+ int ret;
+
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+ /*by Vincent Hsiung for EQ Vol Change*/
+ #define HW_PARAMS_FLAG_EQVOL_ON 0x21
+ #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
+ if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
+ {
+ ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+ } else {
+ /* set codec DAI configuration */
+#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+#endif
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM );
+#endif
+ if (ret < 0)
+ return ret;
+ /* set cpu DAI configuration */
+#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+#endif
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+#endif
+ if (ret < 0)
+ return ret;
+ }
+
+ switch(params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ pll_out = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ pll_out = 11289600;
+ break;
+ default:
+ DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+ return -EINVAL;
+ break;
+ }
+ DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+
+#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+#if 0 //use pll from blck
+ /*Set the pll of rt5621,the Pll source from BITCLK on CPU is master mode*/
+ //bitclk is 64fs
+ ret=snd_soc_dai_set_pll(codec_dai,RT5621_PLL_FR_BCLK,params_rate(params)*64,pll_out);
+ if (ret < 0) {
+ DBG("rk29_hw_params_rt5621:failed to set the pll for codec side\n");
+ return ret;
+ }
+#endif
+ /*Set the system clk for codec*/
+ ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ DBG("rk29_hw_params_rt5621:failed to set the sysclk for codec side\n");
+ return ret;
+ }
+#endif
+
+
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+
+ if((24576000%params_rate(params))==0) //for 8k,16k,32k,48k
+ {
+ snd_soc_dai_set_pll(codec_dai,RT5621_PLL_FR_MCLK,pll_out, 24576000);
+ snd_soc_dai_set_sysclk(codec_dai,0, 24576000, SND_SOC_CLOCK_IN);
+ }
+ else if((22579200%params_rate(params))==0) //for 11k,22k,44k
+ {
+ snd_soc_dai_set_pll(codec_dai,RT5621_PLL_FR_MCLK,pll_out, 22579200);
+ snd_soc_dai_set_sysclk(codec_dai,0, 22579200, SND_SOC_CLOCK_IN);
+ }
+
+#endif
+
+
+#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
+ snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
+ snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
+#endif
+
+ DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5621_dapm_widgets[] = {
+
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+
+};
+
+static const struct snd_soc_dapm_route audio_map[]={
+
+ /* Mic Jack --> MIC_IN*/
+ {"Mic Bias1", NULL, "Mic Jack"},
+ {"MIC1", NULL, "Mic Bias1"},
+ /* HP_OUT --> Headphone Jack */
+ {"Headphone Jack", NULL, "HPOL"},
+ {"Headphone Jack", NULL, "HPOR"},
+ /* LINE_OUT --> Ext Speaker */
+ {"Ext Spk", NULL, "SPOL"},
+ {"Ext Spk", NULL, "SPOR"},
+
+} ;
+
+/*
+ * Logic for a rt5621 as connected on a rockchip board.
+ */
+static int rk29_wm8988_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return 0;
+}
+
+static struct snd_soc_ops rk29_ops = {
+ .hw_params = rk29_hw_params,
+};
+
+static struct snd_soc_dai_link rk29_dai = {
+ .name = "RT5621",
+ .stream_name = "RT5621 PCM",
+ .codec_name = "RT5621.0-001a",
+ .platform_name = "rockchip-audio",
+ .cpu_dai_name = "rk29_i2s.0",
+ .codec_dai_name = "RT5621 HiFi",
+ .init = rk29_wm8988_init,
+ .ops = &rk29_ops,
+};
+
+static struct snd_soc_card snd_soc_card_rk29 = {
+ .name = "RK29_RT5621",
+ .dai_link = &rk29_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *rk29_snd_device;
+
+static int __init audio_card_init(void)
+{
+ int ret =0;
+
+ //rk29_speaker = rk29_speaker_init(RK29_PIN6_PB6, GPIO_HIGH, 2, (200*1000*1000));
+
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+ rk29_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!rk29_snd_device) {
+ DBG("platform device allocation failed\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+ platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
+ ret = platform_device_add(rk29_snd_device);
+ if (ret) {
+ DBG("platform device add failed\n");
+ platform_device_put(rk29_snd_device);
+ return ret;
+ }
+ return ret;
+}
+
+static void __exit audio_card_exit(void)
+{
+ platform_device_unregister(rk29_snd_device);
+}
+
+module_init(audio_card_init);
+module_exit(audio_card_exit);
+/* Module information */
+MODULE_AUTHOR("rockchip");
+MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
+MODULE_LICENSE("GPL");
#include "rk29_i2s.h"
#include <linux/clk.h>
-#if 0
+#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
-static int rk29_hw_params(struct snd_pcm_substream *substream,
+#define HW_PARAMS_FLAG_EQVOL_ON 0x21
+#define HW_PARAMS_FLAG_EQVOL_OFF 0x22
+
+static int rk29_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
unsigned int pll_out = 0;
int div_bclk,div_mclk;
int ret;
struct clk *general_pll;
-
- DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+ if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
+ {
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+ if (codec_dai->driver->ops->hw_params)
+ ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent
+
+ return 0;
+ }
+
/* set codec DAI configuration */
#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
- DBG("Set codec_dai slave\n");
+ DBG("Set codec_dai slave\n");
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
#endif
#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
- DBG("Set codec_dai master\n");
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ DBG("Set codec_dai master\n");
#endif
- if (ret < 0)
- return ret;
+ if (ret < 0)
+ return ret;
/* set cpu DAI configuration */
#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
- DBG("Set cpu_dai slave\n");
+ DBG("Set cpu_dai slave\n");
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
#endif
#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- DBG("Set cpu_dai master\n");
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ DBG("Set cpu_dai master\n");
#endif
if (ret < 0)
return ret;
- switch(params_rate(params)) {
- case 8000:
- case 16000:
- case 24000:
- case 32000:
- case 48000:
- pll_out = 12288000;
- break;
- case 11025:
- case 22050:
- case 44100:
- pll_out = 11289600;
- break;
- default:
- DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
- return -EINVAL;
- break;
- }
- DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+ switch(params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ pll_out = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ pll_out = 11289600;
+ break;
+ default:
+ DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+ return -EINVAL;
+ break;
+ }
+
+ DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+
#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
-#endif
-
+#endif
+
#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
general_pll=clk_get(NULL, "general_pll");
- if(clk_get_rate(general_pll)>260000000)
- {
+
+ if(clk_get_rate(general_pll)>260000000) {
div_bclk=(pll_out/4)/params_rate(params)-1;
div_mclk=3;
}
div_bclk=(pll_out)/params_rate(params)-1;
div_mclk=0;
}
- DBG("func is%s,gpll=%ld,pll_out=%ld,div_mclk=%ld\n",
- __FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
+ DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",
+ __FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
+ if(div_mclk == 3)
+ snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, pll_out, 0);
+ else
+ snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, pll_out, 0);
+#endif
+
+ return 0;
+}
+
+static int rk29_aif2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 0;
+ int div_bclk,div_mclk;
+ int ret;
+ struct clk *general_pll;
+
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+ /* set codec DAI configuration */
+#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ DBG("Set codec_dai slave\n");
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+#endif
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ DBG("Set codec_dai master\n");
+#endif
+ if (ret < 0)
+ return ret;
+
+ switch(params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ pll_out = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ pll_out = 11289600;
+ break;
+ default:
+ DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+ return -EINVAL;
+ break;
+ }
+
+ DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+ snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
+#endif
+
+#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ general_pll=clk_get(NULL, "general_pll");
+
+ if(clk_get_rate(general_pll)>260000000) {
+ div_bclk=(pll_out/4)/params_rate(params)-1;
+ div_mclk=3;
+ }
+ else if(clk_get_rate(general_pll)>130000000)
+ {
+ div_bclk=(pll_out/2)/params_rate(params)-1;
+ div_mclk=1;
+ }
+ else
+ {
+ pll_out=pll_out/4;
+ div_bclk=(pll_out)/params_rate(params)-1;
+ div_mclk=0;
+ }
+ DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",
+ __FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
+ snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
+
if(div_mclk == 3)
snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, pll_out, 0);
else
snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, pll_out, 0);
- DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
#endif
- return 0;
+ return 0;
+}
+
+static int rk29_aif3_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ unsigned int pll_out = 0;
+ int div_bclk,div_mclk;
+ int ret;
+ struct clk *general_pll;
+
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+ DBG("Set codec_dai master\n");
+
+ if (ret < 0)
+ return ret;
+
+ switch(params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ pll_out = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ pll_out = 11289600;
+ break;
+ default:
+ DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+ return -EINVAL;
+ break;
+ }
+
+ DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+
+ snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
+
+ general_pll=clk_get(NULL, "general_pll");
+
+ if(clk_get_rate(general_pll)>260000000) {
+ div_bclk=(pll_out/4)/params_rate(params)-1;
+ div_mclk=3;
+ }
+ else if(clk_get_rate(general_pll)>130000000)
+ {
+ div_bclk=(pll_out/2)/params_rate(params)-1;
+ div_mclk=1;
+ }
+ else
+ {
+ pll_out=pll_out/4;
+ div_bclk=(pll_out)/params_rate(params)-1;
+ div_mclk=0;
+ }
+
+ if(div_mclk == 3)
+ snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, pll_out, 0);
+ else
+ snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, pll_out, 0);
+
+ return 0;
}
+
/*
static const struct snd_soc_dapm_widget rk2818_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Audio Out", NULL),
/*
* Logic for a wm8994 as connected on a rockchip board.
*/
-static int rk29_wm8994_init(struct snd_soc_codec *codec)
+static int rk29_wm8994_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *codec_dai = &codec->dai[0];
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
- DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
- ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0,
12000000, SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "Failed to set WM8994 SYSCLK: %d\n", ret);
return ret;
}
- /* Add specific widgets */
-// snd_soc_dapm_new_controls(codec, rk2818_dapm_widgets,
-// ARRAY_SIZE(rk2818_dapm_widgets));
- /* Set up specific audio path audio_mapnects */
-// snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-// snd_soc_dapm_sync(codec);
+ /* Add specific widgets */
+// snd_soc_dapm_new_controls(dapm, rk2818_dapm_widgets,
+// ARRAY_SIZE(rk2818_dapm_widgets));
+ /* Set up specific audio path audio_mapnects */
+// snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+// snd_soc_dapm_sync(codec);
return 0;
}
-static struct snd_soc_ops rk29_ops = {
- .hw_params = rk29_hw_params,
+static struct snd_soc_ops rk29_aif1_ops = {
+ .hw_params = rk29_aif1_hw_params,
};
-static struct snd_soc_dai_link rk29_dai = {
- .name = "WM8994",
- .stream_name = "WM8994 PCM",
-#ifdef CONFIG_MACH_RK29_PHONEPADSDK
- .cpu_dai = &rk29_i2s_dai[1],
-#else
- .cpu_dai = &rk29_i2s_dai[0],
-#endif
- .codec_dai = &wm8994_dai,
- .init = rk29_wm8994_init,
- .ops = &rk29_ops,
+static struct snd_soc_ops rk29_aif2_ops = {
+ .hw_params = rk29_aif2_hw_params,
};
-static struct snd_soc_card snd_soc_card_rk29 = {
- .name = "RK29_WM8994",
- .platform = &rk29_soc_platform,
- .dai_link = &rk29_dai,
- .num_links = 1,
+static struct snd_soc_ops rk29_aif3_ops = {
+ .hw_params = rk29_aif3_hw_params,
};
+static struct snd_soc_dai_link rk29_dai[] = {
+ {
+ .name = "WM8994",
+ .stream_name = "WM8994 I2S1",
+ .codec_name = "WM8994.0-001a",
+ .platform_name = "rockchip-audio",
+ .cpu_dai_name = "rk29_i2s.0",
+ .codec_dai_name = "wm8994-aif1",
+ .init = rk29_wm8994_init,
+ .ops = &rk29_aif1_ops,
+ },
+ {
+ .name = "WM8994",
+ .stream_name = "WM8994 I2S2",
+ .codec_name = "WM8994.1-001a",
+ .platform_name = "rockchip-audio",
+ .cpu_dai_name = "rk29_i2s.0",
+ .codec_dai_name = "wm8994-aif2",
+ .init = rk29_wm8994_init,
+ .ops = &rk29_aif2_ops,
+ },
+ {
+ .name = "WM8994",
+ .stream_name = "WM8994 I2S3",
+ .codec_name = "WM8994.2-001a",
+ .platform_name = "rockchip-audio",
+ .cpu_dai_name = "rk29_i2s.0",
+ .codec_dai_name = "wm8994-aif3",
+ .init = rk29_wm8994_init,
+ .ops = &rk29_aif3_ops,
+ },
+};
-static struct snd_soc_device rk29_snd_devdata = {
- .card = &snd_soc_card_rk29,
- .codec_dev = &soc_codec_dev_wm8994,
+static struct snd_soc_card snd_soc_card_rk29 = {
+ .name = "RK29_WM8994",
+ .dai_link = rk29_dai,
+ .num_links = 3,
};
static struct platform_device *rk29_snd_device;
static int __init audio_card_init(void)
{
- int ret =0;
- DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+ int ret =0;
+
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
rk29_snd_device = platform_device_alloc("soc-audio", -1);
if (!rk29_snd_device) {
DBG("platform device allocation failed\n");
ret = -ENOMEM;
return ret;
}
- platform_set_drvdata(rk29_snd_device, &rk29_snd_devdata);
- rk29_snd_devdata.dev = &rk29_snd_device->dev;
+
+ platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
ret = platform_device_add(rk29_snd_device);
if (ret) {
- DBG("platform device add failed\n");
- platform_device_put(rk29_snd_device);
+ DBG("platform device add failed\n");
+
+ platform_device_put(rk29_snd_device);
+ return ret;
}
- return ret;
+
+ return ret;
}
static void __exit audio_card_exit(void)