1150 lines
28 KiB
C
1150 lines
28 KiB
C
/*
|
|
* ALSA SoC ES7202 pdm adc driver
|
|
*
|
|
* Author: David Yang, <yangxiaohua@everest-semi.com>
|
|
* Copyright: (C) 2020 Everest Semiconductor Co Ltd.,
|
|
*
|
|
* Based on sound/soc/codecs/es7210.c by David Yang
|
|
*
|
|
* 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.
|
|
*
|
|
* Notes:
|
|
* ES7202 is 2-ch ADC with PDM interface
|
|
*
|
|
*/
|
|
#include <linux/clk.h>
|
|
#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/regulator/consumer.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <sound/core.h>
|
|
#include <sound/pcm.h>
|
|
#include <sound/pcm_params.h>
|
|
#include <sound/tlv.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/soc-dapm.h>
|
|
#include <sound/initval.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/regmap.h>
|
|
#include "es7202.h"
|
|
|
|
//static struct snd_soc_codec *es7202_codec;
|
|
struct i2c_client *i2c_ctl[ADC_DEV_MAXNUM];
|
|
struct snd_soc_component *tron_component1[ADC_DEV_MAXNUM];
|
|
static int es7202_adc_num = 0;
|
|
|
|
/* codec private data */
|
|
struct es7202_priv {
|
|
struct regmap *regmap;
|
|
struct i2c_client *i2c;
|
|
|
|
unsigned int pwr_vdd_voltage;
|
|
struct regulator *vdd;
|
|
int reset_gpio;
|
|
bool reset_active_level;
|
|
};
|
|
|
|
static const struct reg_default es7202_reg_defaults[] = {
|
|
{0x00, 0x10}, {0x01, 0x00}, {0x02, 0x04}, {0x03, 0x00},
|
|
{0x04, 0x01}, {0x05, 0x18}, {0x06, 0x00}, {0x07, 0x30},
|
|
{0x08, 0x02}, {0x10, 0xff}, {0x11, 0x0c}, {0x12, 0x55},
|
|
{0x13, 0x55}, {0x14, 0x8c}, {0x15, 0x33}, {0x16, 0x33},
|
|
{0x17, 0x33}, {0x18, 0x44}, {0x19, 0x00}, {0x1a, 0x00},
|
|
{0x1b, 0x00}, {0x1c, 0xf8}, {0x1d, 0x18}, {0x1e, 0x18},
|
|
};
|
|
|
|
static int es7202_read(u8 reg, u8 * rt_value, struct i2c_client *client)
|
|
{
|
|
int ret;
|
|
u8 read_cmd[3] = { 0 };
|
|
u8 cmd_len = 0;
|
|
|
|
read_cmd[0] = reg;
|
|
cmd_len = 1;
|
|
|
|
if (!client || !client->adapter)
|
|
return -1;
|
|
|
|
ret = i2c_master_send(client, read_cmd, cmd_len);
|
|
if (ret != cmd_len) {
|
|
printk("es7202_read error1\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = i2c_master_recv(client, rt_value, 1);
|
|
if (ret != 1) {
|
|
printk("es7202_read error2, ret = %d.\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_write(u8 reg, unsigned char value, struct i2c_client *client)
|
|
{
|
|
int ret = 0;
|
|
u8 write_cmd[2] = { 0 };
|
|
|
|
if (!client || !client->adapter)
|
|
return -1;
|
|
|
|
write_cmd[0] = reg;
|
|
write_cmd[1] = value;
|
|
|
|
ret = i2c_master_send(client, write_cmd, 2);
|
|
if (ret != 2) {
|
|
printk("es7202_write error->[REG-0x%02x,val-0x%02x]\n",
|
|
reg, value);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_update_bits(u8 reg, u8 mask, u8 value,
|
|
struct i2c_client *client)
|
|
{
|
|
u8 val_old = 0, val_new = 0;
|
|
|
|
es7202_read(reg, &val_old, client);
|
|
val_new = (val_old & ~mask) | (value & mask);
|
|
if (val_new != val_old) {
|
|
es7202_write(reg, val_new, client);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#if 0
|
|
static int es7202_multi_chips_write(u8 reg, unsigned char value)
|
|
{
|
|
u8 i;
|
|
|
|
for (i = 0; i < ADC_DEV_MAXNUM; i++) {
|
|
es7202_write(reg, value, i2c_ctl[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
static int es7202_multi_chips_update_bits(u8 reg, u8 mask, u8 value)
|
|
{
|
|
u8 i;
|
|
|
|
for (i = 0; i < ADC_DEV_MAXNUM; i++) {
|
|
es7202_update_bits(reg, mask, value, i2c_ctl[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 300, 0);
|
|
|
|
#if ES7202_CHANNELS_MAX > 0
|
|
static int es7202_micboost1_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1d, 0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f,
|
|
i2c_ctl[0]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost1_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val = 0;
|
|
es7202_read(0x1d, &val, i2c_ctl[0]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost2_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1e,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[0]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost2_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val = 0;
|
|
es7202_read(0x1e, &val, i2c_ctl[0]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 2
|
|
static int es7202_micboost3_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1d,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[1]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost3_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val = 0;
|
|
es7202_read(0x1d, &val, i2c_ctl[1]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost4_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1e,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[1]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost4_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val = 0;
|
|
es7202_read(0x1e, &val, i2c_ctl[1]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 4
|
|
static int es7202_micboost5_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1d,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[2]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost5_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1d, &val, i2c_ctl[2]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost6_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1e,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[2]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost6_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1e, &val, i2c_ctl[2]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 6
|
|
static int es7202_micboost7_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1d,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[3]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost7_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1d, &val, i2c_ctl[3]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost8_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1e,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[3]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost8_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1e, &val, i2c_ctl[3]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 8
|
|
static int es7202_micboost9_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1d,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[4]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost9_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1d, &val, i2c_ctl[4]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost10_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1e,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[4]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost10_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1e, &val, i2c_ctl[4]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 10
|
|
static int es7202_micboost11_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1d,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[5]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost11_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1d, &val, i2c_ctl[5]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost12_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1e,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[5]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost12_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1e, &val, i2c_ctl[5]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 12
|
|
static int es7202_micboost13_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1d,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[6]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost13_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1d, &val, i2c_ctl[6]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost14_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1e,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[6]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost14_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1e, &val, i2c_ctl[6]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 14
|
|
static int es7202_micboost15_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1d,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[7]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost15_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1d, &val, i2c_ctl[7]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost16_setting_set(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
es7202_update_bits(0x1e,
|
|
0x0F,
|
|
ucontrol->value.integer.value[0] & 0x0f, i2c_ctl[7]);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_micboost16_setting_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
u8 val;
|
|
es7202_read(0x1e, &val, i2c_ctl[7]);
|
|
ucontrol->value.integer.value[0] = val & 0x0f;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static const struct snd_kcontrol_new es7202_snd_controls[] = {
|
|
#if ES7202_CHANNELS_MAX > 0
|
|
SOC_SINGLE_EXT_TLV("PGA1_setting", 0x1D, 0, 0x0C, 0,
|
|
es7202_micboost1_setting_get,
|
|
es7202_micboost1_setting_set,
|
|
mic_boost_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA2_setting", 0x1E, 0, 0x0C, 0,
|
|
es7202_micboost2_setting_get,
|
|
es7202_micboost2_setting_set,
|
|
mic_boost_tlv),
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 2
|
|
SOC_SINGLE_EXT_TLV("PGA3_setting", 0x1D, 0, 0x0C, 0,
|
|
es7202_micboost3_setting_get,
|
|
es7202_micboost3_setting_set,
|
|
mic_boost_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA4_setting", 0x1E, 0, 0x0C, 0,
|
|
es7202_micboost4_setting_get,
|
|
es7202_micboost4_setting_set,
|
|
mic_boost_tlv),
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 4
|
|
SOC_SINGLE_EXT_TLV("PGA5_setting", 0x1D, 0, 0x0C, 0,
|
|
es7202_micboost5_setting_get,
|
|
es7202_micboost5_setting_set,
|
|
mic_boost_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA6_setting", 0x1E, 0, 0x0C, 0,
|
|
es7202_micboost6_setting_get,
|
|
es7202_micboost6_setting_set,
|
|
mic_boost_tlv),
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 6
|
|
SOC_SINGLE_EXT_TLV("PGA7_setting", 0x1D, 0, 0x0C, 0,
|
|
es7202_micboost7_setting_get,
|
|
es7202_micboost7_setting_set,
|
|
mic_boost_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA8_setting", 0x1E, 0, 0x0C, 0,
|
|
es7202_micboost8_setting_get,
|
|
es7202_micboost8_setting_set,
|
|
mic_boost_tlv),
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 8
|
|
SOC_SINGLE_EXT_TLV("PGA9_setting", 0x1D, 0, 0x0C, 0,
|
|
es7202_micboost9_setting_get,
|
|
es7202_micboost9_setting_set,
|
|
mic_boost_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA10_setting", 0x1E, 0, 0x0C, 0,
|
|
es7202_micboost10_setting_get,
|
|
es7202_micboost10_setting_set,
|
|
mic_boost_tlv),
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 10
|
|
SOC_SINGLE_EXT_TLV("PGA11_setting", 0x1D, 0, 0x0C, 0,
|
|
es7202_micboost11_setting_get,
|
|
es7202_micboost11_setting_set,
|
|
mic_boost_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA12_setting", 0x1E, 0, 0x0C, 0,
|
|
es7202_micboost12_setting_get,
|
|
es7202_micboost12_setting_set,
|
|
mic_boost_tlv),
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 12
|
|
SOC_SINGLE_EXT_TLV("PGA13_setting", 0x1D, 0, 0x0C, 0,
|
|
es7202_micboost13_setting_get,
|
|
es7202_micboost13_setting_set,
|
|
mic_boost_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA14_setting", 0x1E, 0, 0x0C, 0,
|
|
es7202_micboost14_setting_get,
|
|
es7202_micboost14_setting_set,
|
|
mic_boost_tlv),
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 14
|
|
SOC_SINGLE_EXT_TLV("PGA15_setting", 0x1D, 0, 0x0C, 0,
|
|
es7202_micboost15_setting_get,
|
|
es7202_micboost15_setting_set,
|
|
mic_boost_tlv),
|
|
SOC_SINGLE_EXT_TLV("PGA16_setting", 0x1E, 0, 0x0C, 0,
|
|
es7202_micboost16_setting_get,
|
|
es7202_micboost16_setting_set,
|
|
mic_boost_tlv),
|
|
#endif
|
|
};
|
|
|
|
static int es7202_mute(struct snd_soc_dai *dai, int mute, int stream)
|
|
{
|
|
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
return 0;
|
|
|
|
if (mute) {
|
|
es7202_multi_chips_update_bits(ES7202_PDM_INF_CTL_REG07, 0x03,0x03);
|
|
} else {
|
|
es7202_multi_chips_update_bits(ES7202_PDM_INF_CTL_REG07, 0x03,0x00);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define es7202_RATES SNDRV_PCM_RATE_8000_96000
|
|
|
|
static struct snd_soc_dai_ops es7202_ops = {
|
|
.mute_stream = es7202_mute,
|
|
};
|
|
#if ES7202_CHANNELS_MAX > 0
|
|
static struct snd_soc_dai_driver es7202_dai0 = {
|
|
.name = "es7202 pdm 0",
|
|
.capture = {
|
|
.stream_name = "Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 8,
|
|
.rates = es7202_RATES,
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
},
|
|
.ops = &es7202_ops,
|
|
.symmetric_rate = 1,
|
|
};
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 2
|
|
static struct snd_soc_dai_driver es7202_dai1 = {
|
|
.name = "es7202 pdm 1",
|
|
.capture = {
|
|
.stream_name = "Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 8,
|
|
.rates = es7202_RATES,
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
},
|
|
.ops = &es7202_ops,
|
|
.symmetric_rate = 1,
|
|
};
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 4
|
|
static struct snd_soc_dai_driver es7202_dai2 = {
|
|
.name = "es7202 pdm 2",
|
|
.capture = {
|
|
.stream_name = "Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 8,
|
|
.rates = es7202_RATES,
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
},
|
|
.ops = &es7202_ops,
|
|
.symmetric_rate = 1,
|
|
};
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 6
|
|
static struct snd_soc_dai_driver es7202_dai3 = {
|
|
.name = "es7202 pdm 3",
|
|
.capture = {
|
|
.stream_name = "Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 8,
|
|
.rates = es7202_RATES,
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
},
|
|
.ops = &es7202_ops,
|
|
.symmetric_rate = 1,
|
|
};
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 8
|
|
static struct snd_soc_dai_driver es7202_dai4 = {
|
|
.name = "es7202 pdm 4",
|
|
.capture = {
|
|
.stream_name = "Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 10,
|
|
.rates = es7202_RATES,
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
},
|
|
.ops = &es7202_ops,
|
|
.symmetric_rate = 1,
|
|
};
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 10
|
|
static struct snd_soc_dai_driver es7202_dai5 = {
|
|
.name = "es7202 pdm 5",
|
|
.capture = {
|
|
.stream_name = "Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 12,
|
|
.rates = es7202_RATES,
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
},
|
|
.ops = &es7202_ops,
|
|
.symmetric_rate = 1,
|
|
};
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 12
|
|
static struct snd_soc_dai_driver es7202_dai6 = {
|
|
.name = "es7202 pdm 6",
|
|
.capture = {
|
|
.stream_name = "Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 14,
|
|
.rates = es7202_RATES,
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
},
|
|
.ops = &es7202_ops,
|
|
.symmetric_rate = 1,
|
|
};
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 14
|
|
static struct snd_soc_dai_driver es7202_dai7 = {
|
|
.name = "es7202 pdm 7",
|
|
.capture = {
|
|
.stream_name = "Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 16,
|
|
.rates = es7202_RATES,
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
},
|
|
.ops = &es7202_ops,
|
|
.symmetric_rate = 1,
|
|
};
|
|
#endif
|
|
|
|
static struct snd_soc_dai_driver *es7202_dai[] = {
|
|
#if ES7202_CHANNELS_MAX > 0
|
|
&es7202_dai0,
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 2
|
|
&es7202_dai1,
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 4
|
|
&es7202_dai2,
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 6
|
|
&es7202_dai3,
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 8
|
|
&es7202_dai4,
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 10
|
|
&es7202_dai5,
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 12
|
|
&es7202_dai6,
|
|
#endif
|
|
#if ES7202_CHANNELS_MAX > 14
|
|
&es7202_dai7,
|
|
#endif
|
|
};
|
|
|
|
static int es7202_suspend(struct snd_soc_component *component)
|
|
{
|
|
es7202_multi_chips_update_bits(ES7202_PDM_INF_CTL_REG07, 0x03,0x03);
|
|
msleep(50);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_resume(struct snd_soc_component *component)
|
|
{
|
|
msleep(50);
|
|
es7202_multi_chips_update_bits(ES7202_PDM_INF_CTL_REG07, 0x03,0x00);
|
|
return 0;
|
|
}
|
|
|
|
static int es7202_probe(struct snd_soc_component *component)
|
|
{
|
|
struct es7202_priv *es7202 = snd_soc_component_get_drvdata(component);
|
|
int cnt;
|
|
int ret = 0;
|
|
printk("enter into %s()\n", __func__);
|
|
tron_component1[es7202_adc_num++] = component;
|
|
|
|
for (cnt = 0; cnt < ADC_DEV_MAXNUM; cnt++) {
|
|
es7202_write(ES7202_SOFT_MODE_REG01, 0x01, i2c_ctl[cnt]);
|
|
switch(es7202->pwr_vdd_voltage) {
|
|
case VDD_3V3:
|
|
es7202_write(ES7202_ANALOG_MISC1_REG1B, 0x50, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_PGA1_REG1D, 0x1b, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_PGA2_REG1E, 0x1b, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_ANALOG_EN_REG10, 0x7F, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_BIAS_VMID_REG11, 0x2F, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_ANALOG_EN_REG10, 0x0F, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_ANALOG_EN_REG10, 0x00, i2c_ctl[cnt]);
|
|
break;
|
|
default:
|
|
case VDD_1V8:
|
|
es7202_write(ES7202_ANALOG_MISC1_REG1B, 0x40, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_PGA1_REG1D, 0x1b, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_PGA2_REG1E, 0x1b, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_ANALOG_EN_REG10, 0x7F, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_BIAS_VMID_REG11, 0x2F, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_ANALOG_EN_REG10, 0x3F, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_ANALOG_EN_REG10, 0x00, i2c_ctl[cnt]);
|
|
break;
|
|
}
|
|
es7202_write(ES7202_MOD1_BIAS_REG14, 0x58, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_CLK_DIV_REG02, 0x01, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_T2_VMID_REG05, 0x01, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_MISC_CTL_REG08, 0x02, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_RESET_REG00, 0x01, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_CLK_EN_REG03, 0x03, i2c_ctl[cnt]);
|
|
es7202_write(ES7202_BIAS_VMID_REG11, 0x2E, i2c_ctl[cnt]);
|
|
|
|
es7202_multi_chips_update_bits(ES7202_PDM_INF_CTL_REG07, 0x03, 0x00);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void es7202_remove(struct snd_soc_component *component)
|
|
{
|
|
es7202_multi_chips_update_bits(ES7202_PDM_INF_CTL_REG07, 0x03,0x03);
|
|
msleep(50);
|
|
}
|
|
|
|
const struct regmap_config es7202_regmap_config = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
.max_register = 0xff,
|
|
.cache_type = REGCACHE_RBTREE,
|
|
.reg_defaults = es7202_reg_defaults,
|
|
.num_reg_defaults = ARRAY_SIZE(es7202_reg_defaults),
|
|
};
|
|
|
|
static struct snd_soc_component_driver soc_codec_dev_es7202 = {
|
|
.probe = es7202_probe,
|
|
.remove = es7202_remove,
|
|
.suspend = es7202_suspend,
|
|
.resume = es7202_resume,
|
|
|
|
|
|
.controls = es7202_snd_controls,
|
|
.num_controls = ARRAY_SIZE(es7202_snd_controls),
|
|
.idle_bias_on = 1,
|
|
.use_pmdown_time = 1,
|
|
.endianness = 1,
|
|
};
|
|
|
|
static ssize_t es7202_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
int val=0, flag=0;
|
|
u8 i=0, reg, num, value_w, value_r;
|
|
|
|
struct es7202_priv *es7202 = dev_get_drvdata(dev);
|
|
val = simple_strtol(buf, NULL, 16);
|
|
flag = (val >> 16) & 0xFF;
|
|
|
|
if (flag) {
|
|
reg = (val >> 8) & 0xFF;
|
|
value_w = val & 0xFF;
|
|
printk("\nWrite: start REG:0x%02x,val:0x%02x,count:0x%02x\n", reg, value_w, flag);
|
|
while(flag--) {
|
|
es7202_write(reg, value_w, es7202->i2c);
|
|
printk("Write 0x%02x to REG:0x%02x\n", value_w, reg);
|
|
reg++;
|
|
}
|
|
} else {
|
|
reg = (val >> 8) & 0xFF;
|
|
num = val & 0xff;
|
|
printk("\nRead: start REG:0x%02x,count:0x%02x\n", reg, num);
|
|
do {
|
|
value_r = 0;
|
|
es7202_read(reg, &value_r, es7202->i2c);
|
|
printk("REG[0x%02x]: 0x%02x; ", reg, value_r);
|
|
reg++;
|
|
i++;
|
|
if ((i==num) || (i%4==0)) printk("\n");
|
|
} while (i<num);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t es7202_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
printk("echo flag|reg|val > es7202\n");
|
|
printk("eg read star addres=0x06,count 0x10:echo 0610 >es7202\n");
|
|
printk("eg write star addres=0x90,value=0x3c,count=4:echo 4903c >es7202\n");
|
|
return 0;
|
|
}
|
|
|
|
static DEVICE_ATTR(es7202, 0644, es7202_show, es7202_store);
|
|
|
|
static struct attribute *es7202_debug_attrs[] = {
|
|
&dev_attr_es7202.attr,
|
|
NULL,
|
|
};
|
|
|
|
static struct attribute_group es7202_debug_attr_group = {
|
|
.name = "es7202_debug",
|
|
.attrs = es7202_debug_attrs,
|
|
};
|
|
|
|
static int es7202_i2c_probe(struct i2c_client *i2c,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
struct es7202_priv *es7202;
|
|
int uV;
|
|
int ret = -1;
|
|
|
|
dev_info(&i2c->dev, "probe\n");
|
|
es7202 = devm_kzalloc(&i2c->dev, sizeof(*es7202), GFP_KERNEL);
|
|
if (!es7202)
|
|
return -ENOMEM;
|
|
es7202->i2c = i2c;
|
|
es7202->vdd = devm_regulator_get_optional(&i2c->dev, "power");
|
|
if (IS_ERR(es7202->vdd)) {
|
|
if (PTR_ERR(es7202->vdd) == -EPROBE_DEFER)
|
|
return -EPROBE_DEFER;
|
|
dev_warn(&i2c->dev, "power-supply get fail, use 3v3 as default\n");
|
|
es7202->pwr_vdd_voltage = VDD_3V3;
|
|
} else {
|
|
uV = regulator_get_voltage(es7202->vdd);
|
|
dev_info(&i2c->dev, "probe power-supply %duV\n", uV);
|
|
if (uV <= MAX_VOLTAGE_1_8)
|
|
es7202->pwr_vdd_voltage = VDD_1V8;
|
|
else
|
|
es7202->pwr_vdd_voltage = VDD_3V3;
|
|
}
|
|
dev_set_drvdata(&i2c->dev, es7202);
|
|
if (id->driver_data < ADC_DEV_MAXNUM) {
|
|
i2c_ctl[id->driver_data] = i2c;
|
|
dev_info(&i2c->dev, "probe reigister es7202 dai(%s) component\n",
|
|
es7202_dai[id->driver_data]->name);
|
|
ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_es7202,
|
|
es7202_dai[id->driver_data], 1);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
ret = sysfs_create_group(&i2c->dev.kobj, &es7202_debug_attr_group);
|
|
if (ret) {
|
|
dev_err(&i2c->dev, "failed to create attr group\n");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void es7202_i2c_remove(struct i2c_client *client)
|
|
{
|
|
sysfs_remove_group(&client->dev.kobj, &es7202_debug_attr_group);
|
|
}
|
|
|
|
static void es7202_i2c_shutdown(struct i2c_client *client)
|
|
{
|
|
es7202_multi_chips_update_bits(ES7202_PDM_INF_CTL_REG07, 0x03,0x03);
|
|
msleep(50);
|
|
}
|
|
|
|
#if !ES7202_MATCH_DTS_EN
|
|
static int es7202_i2c_detect(struct i2c_client *client,
|
|
struct i2c_board_info *info)
|
|
{
|
|
struct i2c_adapter *adapter = client->adapter;
|
|
|
|
if (adapter->nr == ES7202_I2C_BUS_NUM) {
|
|
if (client->addr == 0x30) {
|
|
strlcpy(info->type, "ES7202_PDM_ADC_1", I2C_NAME_SIZE);
|
|
return 0;
|
|
} else if (client->addr == 0x31) {
|
|
strlcpy(info->type, "ES7202_PDM_ADC_2", I2C_NAME_SIZE);
|
|
return 0;
|
|
} else if (client->addr == 0x32) {
|
|
strlcpy(info->type, "ES7202_PDM_ADC_3", I2C_NAME_SIZE);
|
|
return 0;
|
|
} else if (client->addr == 0x33) {
|
|
strlcpy(info->type, "ES7202_PDM_ADC_4", I2C_NAME_SIZE);
|
|
return 0;
|
|
}else if (client->addr == 0x34) {
|
|
strlcpy(info->type, "ES7202_PDM_ADC_5", I2C_NAME_SIZE);
|
|
return 0;
|
|
}else if (client->addr == 0x35) {
|
|
strlcpy(info->type, "ES7202_PDM_ADC_6", I2C_NAME_SIZE);
|
|
return 0;
|
|
}else if (client->addr == 0x36) {
|
|
strlcpy(info->type, "ES7202_PDM_ADC_7", I2C_NAME_SIZE);
|
|
return 0;
|
|
}else if (client->addr == 0x37) {
|
|
strlcpy(info->type, "ES7202_PDM_ADC_8", I2C_NAME_SIZE);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -ENODEV;
|
|
}
|
|
|
|
static const unsigned short es7202_i2c_addr[] = {
|
|
#if ES7202_CHANNELS_MAX > 0
|
|
0x30,
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 2
|
|
0x31,
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 4
|
|
0x32,
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 6
|
|
0x33,
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 8
|
|
0x34,
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 10
|
|
0x35,
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 12
|
|
0x36,
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 14
|
|
0x37,
|
|
#endif
|
|
I2C_CLIENT_END,
|
|
};
|
|
#endif
|
|
|
|
#if ES7202_MATCH_DTS_EN
|
|
/*
|
|
* device tree source or i2c_board_info both use to
|
|
* transfer hardware information to linux kernel,
|
|
* use one of them wil be OK
|
|
*/
|
|
#if 0
|
|
static struct i2c_board_info es7202_i2c_board_info[] = {
|
|
#if ES7202_CHANNELS_MAX > 0
|
|
{I2C_BOARD_INFO("ES7202_PDM_ADC_1", 0x30),},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 2
|
|
{I2C_BOARD_INFO("ES7202_PDM_ADC_2", 0x31),},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 4
|
|
{I2C_BOARD_INFO("ES7202_PDM_ADC_3", 0x32),},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 6
|
|
{I2C_BOARD_INFO("ES7202_PDM_ADC_4", 0x33),},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 8
|
|
{I2C_BOARD_INFO("ES7202_PDM_ADC_5", 0x34),},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 10
|
|
{I2C_BOARD_INFO("ES7202_PDM_ADC_6", 0x35),},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 12
|
|
{I2C_BOARD_INFO("ES7202_PDM_ADC_7", 0x36),},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 14
|
|
{I2C_BOARD_INFO("ES7202_PDM_ADC_8", 0x37),},
|
|
#endif
|
|
};
|
|
#endif
|
|
static const struct of_device_id es7202_dt_ids[] = {
|
|
#if ES7202_CHANNELS_MAX > 0
|
|
{.compatible = "ES7202_PDM_ADC_1",},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 2
|
|
{.compatible = "ES7202_PDM_ADC_2",},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 4
|
|
{.compatible = "ES7202_PDM_ADC_3",},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 6
|
|
{.compatible = "ES7202_PDM_ADC_4",},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 8
|
|
{.compatible = "ES7202_PDM_ADC_5",},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 10
|
|
{.compatible = "ES7202_PDM_ADC_6",},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 12
|
|
{.compatible = "ES7202_PDM_ADC_7",},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 14
|
|
{.compatible = "ES7202_PDM_ADC_8",},
|
|
#endif
|
|
{}
|
|
};
|
|
#endif
|
|
|
|
static const struct i2c_device_id es7202_i2c_id[] = {
|
|
#if ES7202_CHANNELS_MAX > 0
|
|
{"ES7202_PDM_ADC_1", 0},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 2
|
|
{"ES7202_PDM_ADC_2", 1},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 4
|
|
{"ES7202_PDM_ADC_3", 2},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 6
|
|
{"ES7202_PDM_ADC_4", 3},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 8
|
|
{"ES7202_PDM_ADC_5", 4},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 10
|
|
{"ES7202_PDM_ADC_6", 5},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 12
|
|
{"ES7202_PDM_ADC_7", 6},
|
|
#endif
|
|
|
|
#if ES7202_CHANNELS_MAX > 14
|
|
{"ES7202_PDM_ADC_8", 7},
|
|
#endif
|
|
{}
|
|
};
|
|
|
|
static struct i2c_driver es7202_i2c_driver = {
|
|
.driver = {
|
|
.name = "es7202",
|
|
#if ES7202_MATCH_DTS_EN
|
|
.of_match_table = es7202_dt_ids,
|
|
#endif
|
|
},
|
|
.probe = es7202_i2c_probe,
|
|
.remove = es7202_i2c_remove,
|
|
.shutdown = es7202_i2c_shutdown,
|
|
.class = I2C_CLASS_HWMON,
|
|
.id_table = es7202_i2c_id,
|
|
#if !ES7202_MATCH_DTS_EN
|
|
.address_list = es7202_i2c_addr,
|
|
.detect = es7202_i2c_detect,
|
|
#endif
|
|
};
|
|
|
|
static int __init es7202_modinit(void)
|
|
{
|
|
int ret;
|
|
//#if ES7202_MATCH_DTS_EN
|
|
#if 0
|
|
int i;
|
|
struct i2c_adapter *adapter;
|
|
struct i2c_client *client;
|
|
#endif
|
|
|
|
//#if ES7202_MATCH_DTS_EN
|
|
#if 0
|
|
/*
|
|
* Notes:
|
|
* if the device has been declared in DTS tree,
|
|
* here don't need to create new i2c device with i2c_board_info.
|
|
*/
|
|
adapter = i2c_get_adapter(ES7202_I2C_BUS_NUM);
|
|
if (!adapter) {
|
|
printk("i2c_get_adapter() fail!\n");
|
|
return -ENODEV;
|
|
}
|
|
printk("%s() begin0000", __func__);
|
|
|
|
for (i = 0; i < ADC_DEV_MAXNUM; i++) {
|
|
client = i2c_new_device(adapter, &es7202_i2c_board_info[i]);
|
|
printk("%s() i2c_new_device\n", __func__);
|
|
if (!client)
|
|
return -ENODEV;
|
|
}
|
|
i2c_put_adapter(adapter);
|
|
#endif
|
|
ret = i2c_add_driver(&es7202_i2c_driver);
|
|
if (ret != 0)
|
|
printk("Failed to register es7202 i2c driver : %d \n", ret);
|
|
return ret;
|
|
}
|
|
|
|
late_initcall(es7202_modinit);
|
|
//module_init(es7202_modinit);
|
|
static void __exit es7202_exit(void)
|
|
{
|
|
i2c_del_driver(&es7202_i2c_driver);
|
|
}
|
|
|
|
module_exit(es7202_exit);
|
|
|
|
MODULE_DESCRIPTION("ASoC es7202 pdm adc driver");
|
|
MODULE_AUTHOR(" David Yang, <yangxiaohua@everest-semi.com>>");
|
|
MODULE_LICENSE("GPL v2");
|