Exyons4412音频驱动读写流程

Exyons4412音频驱动----初始化之寄存器读写流程(一)

550人阅读 评论(0) 收藏 举报
本文章已收录于:
分类:


内核加载驱动:

  1. module_init(snd_soc_init);  
module_init(snd_soc_init);

 加载完成之后进入:snd_soc_init() 初始化函数

  1. static int __init snd_soc_init(void)  
  2. {  
  3. #ifdef CONFIG_DEBUG_FS  
  4.     snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);  
  5.     if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {  
  6.         printk(KERN_WARNING  
  7.                "ASoC: Failed to create debugfs directory\n");  
  8.         snd_soc_debugfs_root = NULL;  
  9.     }  
  10.   
  11.     if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,  
  12.                  &codec_list_fops))  
  13.         pr_warn("ASoC: Failed to create CODEC list debugfs file\n");  
  14.   
  15.     if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,  
  16.                  &dai_list_fops))  
  17.         pr_warn("ASoC: Failed to create DAI list debugfs file\n");  
  18.   
  19.     if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,  
  20.                  &platform_list_fops))  
  21.         pr_warn("ASoC: Failed to create platform list debugfs file\n");  
  22. #endif  
  23.   
  24.     snd_soc_util_init();  
  25.   
  26.     return platform_driver_register(&soc_driver);  
  27. }  
static int __init snd_soc_init(void)
{
#ifdef CONFIG_DEBUG_FS
	snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
	if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
		printk(KERN_WARNING
		       "ASoC: Failed to create debugfs directory\n");
		snd_soc_debugfs_root = NULL;
	}

	if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
				 &codec_list_fops))
		pr_warn("ASoC: Failed to create CODEC list debugfs file\n");

	if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
				 &dai_list_fops))
		pr_warn("ASoC: Failed to create DAI list debugfs file\n");

	if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
				 &platform_list_fops))
		pr_warn("ASoC: Failed to create platform list debugfs file\n");
#endif

	snd_soc_util_init();

	return platform_driver_register(&soc_driver);
}


soc_driver原型如下:

  1. /* ASoC platform driver */  
  2. static struct platform_driver soc_driver = {  
  3.     .driver     = {  
  4.         .name       = "soc-audio",  
  5.         .owner      = THIS_MODULE,  
  6.         .pm     = &snd_soc_pm_ops,  
  7.     },  
  8.     .probe      = soc_probe,  
  9.     .remove     = soc_remove,  
  10. };  
/* ASoC platform driver */
static struct platform_driver soc_driver = {
	.driver		= {
		.name		= "soc-audio",
		.owner		= THIS_MODULE,
		.pm		= &snd_soc_pm_ops,
	},
	.probe		= soc_probe,
	.remove		= soc_remove,
};

在执行platform_driver_register(&soc_driver); 这条语句之后 进入 soc_probe


该函数原型如下:


  1. /* probes a new socdev */  
  2. static int soc_probe(struct platform_device *pdev)  
  3. {  
  4.     struct snd_soc_card *card = platform_get_drvdata(pdev);  
  5.     int ret = 0;  
  6.   
  7.     /*  
  8.      * no card, so machine driver should be registering card  
  9.      * we should not be here in that case so ret error  
  10.      */  
  11.     if (!card)  
  12.         return -EINVAL;  
  13.   
  14.     /* Bodge while we unpick instantiation */  
  15.     card->dev = &pdev->dev;  
  16.   
  17.     ret = snd_soc_register_card(card);  
  18.     if (ret != 0) {  
  19.         dev_err(&pdev->dev, "Failed to register card\n");  
  20.         return ret;  
  21.     }  
  22.   
  23.     return 0;  
  24. }  
/* probes a new socdev */
static int soc_probe(struct platform_device *pdev)
{
	struct snd_soc_card *card = platform_get_drvdata(pdev);
	int ret = 0;

	/*
	 * no card, so machine driver should be registering card
	 * we should not be here in that case so ret error
	 */
	if (!card)
		return -EINVAL;

	/* Bodge while we unpick instantiation */
	card->dev = &pdev->dev;

	ret = snd_soc_register_card(card);
	if (ret != 0) {
		dev_err(&pdev->dev, "Failed to register card\n");
		return ret;
	}

	return 0;
}


调用该函数之后执行:ret = snd_soc_register_card(card)->snd_soc_instantiate_cards();->snd_soc_instantiate_card(card);

->ret = snd_soc_init_codec_cache(codec, compress_type);->ret = snd_soc_cache_init(codec);


执行到ret = snd_soc_cache_init(codec);函数之后会做一些处理 , 该函数原型如下


  1. int snd_soc_cache_init(struct snd_soc_codec *codec)  
  2. {  
  3.     int i;  
  4.   
  5.     for (i = 0; i < ARRAY_SIZE(cache_types); ++i)  
  6.         if (cache_types[i].id == codec->compress_type)  
  7.             break;  
  8.   
  9.     /* Fall back to flat compression */  
  10.     if (i == ARRAY_SIZE(cache_types)) {  
  11.         dev_warn(codec->dev, "Could not match compress type: %d\n",  
  12.              codec->compress_type);  
  13.         i = 0;  
  14.     }  
  15.   
  16.     mutex_init(&codec->cache_rw_mutex);  
  17.     codec->cache_ops = &cache_types[i];  
  18.   
  19.     if (codec->cache_ops->init) {  
  20.         if (codec->cache_ops->name)  
  21.             dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",  
  22.                 codec->cache_ops->name, codec->name);  
  23.         return codec->cache_ops->init(codec);  
  24.     }  
  25.     return -ENOSYS;  
  26. }  
int snd_soc_cache_init(struct snd_soc_codec *codec)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
		if (cache_types[i].id == codec->compress_type)
			break;

	/* Fall back to flat compression */
	if (i == ARRAY_SIZE(cache_types)) {
		dev_warn(codec->dev, "Could not match compress type: %d\n",
			 codec->compress_type);
		i = 0;
	}

	mutex_init(&codec->cache_rw_mutex);
	codec->cache_ops = &cache_types[i];

	if (codec->cache_ops->init) {
		if (codec->cache_ops->name)
			dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
				codec->cache_ops->name, codec->name);
		return codec->cache_ops->init(codec);
	}
	return -ENOSYS;
}

codec->cache_ops = &cache_types[i];  这句就是赋初始值   cache_types的定义如下

  1. static const struct snd_soc_cache_ops cache_types[] = {  
  2.     /* Flat *must* be the first entry for fallback */  
  3.     {  
  4.         .id = SND_SOC_FLAT_COMPRESSION,  
  5.         .name = "flat",  
  6.         .init = snd_soc_flat_cache_init,  
  7.         .exit = snd_soc_flat_cache_exit,  
  8.         .read = snd_soc_flat_cache_read,  
  9.         .write = snd_soc_flat_cache_write,  
  10.         .sync = snd_soc_flat_cache_sync  
  11.     },  
  12. #ifdef CONFIG_SND_SOC_CACHE_LZO  
  13.     {  
  14.         .id = SND_SOC_LZO_COMPRESSION,  
  15.         .name = "LZO",  
  16.         .init = snd_soc_lzo_cache_init,  
  17.         .exit = snd_soc_lzo_cache_exit,  
  18.         .read = snd_soc_lzo_cache_read,  
  19.         .write = snd_soc_lzo_cache_write,  
  20.         .sync = snd_soc_lzo_cache_sync  
  21.     },  
  22. #endif  
  23.     {  
  24.         .id = SND_SOC_RBTREE_COMPRESSION,  
  25.         .name = "rbtree",  
  26.         .init = snd_soc_rbtree_cache_init,  
  27.         .exit = snd_soc_rbtree_cache_exit,  
  28.         .read = snd_soc_rbtree_cache_read,  
  29.         .write = snd_soc_rbtree_cache_write,  
  30.         .sync = snd_soc_rbtree_cache_sync  
  31.     }  
  32. };  
static const struct snd_soc_cache_ops cache_types[] = {
	/* Flat *must* be the first entry for fallback */
	{
		.id = SND_SOC_FLAT_COMPRESSION,
		.name = "flat",
		.init = snd_soc_flat_cache_init,
		.exit = snd_soc_flat_cache_exit,
		.read = snd_soc_flat_cache_read,
		.write = snd_soc_flat_cache_write,
		.sync = snd_soc_flat_cache_sync
	},
#ifdef CONFIG_SND_SOC_CACHE_LZO
	{
		.id = SND_SOC_LZO_COMPRESSION,
		.name = "LZO",
		.init = snd_soc_lzo_cache_init,
		.exit = snd_soc_lzo_cache_exit,
		.read = snd_soc_lzo_cache_read,
		.write = snd_soc_lzo_cache_write,
		.sync = snd_soc_lzo_cache_sync
	},
#endif
	{
		.id = SND_SOC_RBTREE_COMPRESSION,
		.name = "rbtree",
		.init = snd_soc_rbtree_cache_init,
		.exit = snd_soc_rbtree_cache_exit,
		.read = snd_soc_rbtree_cache_read,
		.write = snd_soc_rbtree_cache_write,
		.sync = snd_soc_rbtree_cache_sync
	}
};

根据上下文, 我们使用的是SND_SOC_FLAT_COMPRESSION 这个

 这个结构体里面的函数 所有原型如下


init函数

  1. static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)  
  2. {  
  3.     const struct snd_soc_codec_driver *codec_drv;  
  4.   
  5.     codec_drv = codec->driver;  
  6.   
  7.     if (codec->reg_def_copy)  
  8.         codec->reg_cache = kmemdup(codec->reg_def_copy,  
  9.                        codec->reg_size, GFP_KERNEL);  
  10.     else  
  11.         codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);  
  12.     if (!codec->reg_cache)  
  13.         return -ENOMEM;  
  14.   
  15.     return 0;  
  16. }  
static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
{
	const struct snd_soc_codec_driver *codec_drv;

	codec_drv = codec->driver;

	if (codec->reg_def_copy)
		codec->reg_cache = kmemdup(codec->reg_def_copy,
					   codec->reg_size, GFP_KERNEL);
	else
		codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
	if (!codec->reg_cache)
		return -ENOMEM;

	return 0;
}


如果def_copy有初始值, 那么就赋值给reg_cache (寄存器缓存值)  这个函数主要是 给寄存器的cache赋初始值



read函数

  1. static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,  
  2.                    unsigned int reg, unsigned int *value)  
  3. {  
  4.     *value = snd_soc_get_cache_val(codec->reg_cache, reg,  
  5.                        codec->driver->reg_word_size);  
  6.     return 0;  
  7. }  
static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
				   unsigned int reg, unsigned int *value)
{
	*value = snd_soc_get_cache_val(codec->reg_cache, reg,
				       codec->driver->reg_word_size);
	return 0;
}

  1. static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,  
  2.         unsigned int word_size)  
  3. {  
  4.     if (!base)  
  5.         return -1;  
  6.   
  7.     switch (word_size) {  
  8.     case 1: {  
  9.         const u8 *cache = base;  
  10.         return cache[idx];  
  11.     }  
  12.     case 2: {  
  13.         const u16 *cache = base;  
  14.         return cache[idx];  
  15.     }  
  16.     default:  
  17.         BUG();  
  18.     }  
  19.     /* unreachable */  
  20.     return -1;  
  21. }  
static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
		unsigned int word_size)
{
	if (!base)
		return -1;

	switch (word_size) {
	case 1: {
		const u8 *cache = base;
		return cache[idx];
	}
	case 2: {
		const u16 *cache = base;
		return cache[idx];
	}
	default:
		BUG();
	}
	/* unreachable */
	return -1;
}

 从代码中可以看到, read函数,是直接从codec->reg_cache 中读取de ,  通过查找init的代码 得知 如果codec->reg_def_copy有值,那么 codec->reg_cache 是从codec->reg_def_copy拷贝来的, 不然codec->reg_cache的值默认为0


上面是soc_sound ,read的流程。


write函数

  1. static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,  
  2.                     unsigned int reg, unsigned int value)  
  3. {  
  4.     snd_soc_set_cache_val(codec->reg_cache, reg, value,  
  5.                   codec->driver->reg_word_size);  
  6.     return 0;  
  7. }  
static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
				    unsigned int reg, unsigned int value)
{
	snd_soc_set_cache_val(codec->reg_cache, reg, value,
			      codec->driver->reg_word_size);
	return 0;
}

  1. static bool snd_soc_set_cache_val(void *base, unsigned int idx,  
  2.                   unsigned int val, unsigned int word_size)  
  3. {  
  4.     switch (word_size) {  
  5.     case 1: {  
  6.         u8 *cache = base;  
  7.         if (cache[idx] == val)  
  8.             return true;  
  9.         cache[idx] = val;  
  10.         break;  
  11.     }  
  12.     case 2: {  
  13.         u16 *cache = base;  
  14.         if (cache[idx] == val)  
  15.             return true;  
  16.         cache[idx] = val;  
  17.         break;  
  18.     }  
  19.     default:  
  20.         BUG();  
  21.     }  
  22.     return false;  
  23. }  
static bool snd_soc_set_cache_val(void *base, unsigned int idx,
				  unsigned int val, unsigned int word_size)
{
	switch (word_size) {
	case 1: {
		u8 *cache = base;
		if (cache[idx] == val)
			return true;
		cache[idx] = val;
		break;
	}
	case 2: {
		u16 *cache = base;
		if (cache[idx] == val)
			return true;
		cache[idx] = val;
		break;
	}
	default:
		BUG();
	}
	return false;
}

从代码中可以看到,read ,  write都是操作reg_cache缓存中都写数据 ,  具体往寄存器中写入数值 继续往下看


wm8960为例子 , 写寄存器函数为:


  1. unsigned int snd_soc_write(struct snd_soc_codec *codec,  
  2.                unsigned int reg, unsigned int val)  
  3. {  
  4.     dev_printk(KERN_DEBUG,codec->dev, "write %x = %x\n", reg, val);  
  5.     trace_snd_soc_reg_write(codec, reg, val);  
  6.     return codec->write(codec, reg, val);  
  7. }  
unsigned int snd_soc_write(struct snd_soc_codec *codec,
			   unsigned int reg, unsigned int val)
{
	dev_printk(KERN_DEBUG,codec->dev, "write %x = %x\n", reg, val);
	trace_snd_soc_reg_write(codec, reg, val);
	return codec->write(codec, reg, val);
}


codec->write(codec, reg, val); 调用的是这个函数。


在wm8960.c的wm8960_i2c_probe->snd_soc_register_codec函数中有如下赋值:


  1. codec->write = codec_drv->write;  
  2. codec->read = codec_drv->read;  
	codec->write = codec_drv->write;
	codec->read = codec_drv->read;


所以如果找到了

codec->write 
 codec->read

这二个函数, 那么操作读写也能找到。   继续看


wm8960.c中  初始化执行wm8960_probe之后调用了一个函数ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type); 该函数原型为


  1. int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,  
  2.                    int addr_bits, int data_bits,  
  3.                    enum snd_soc_control_type control)  
  4. {  
  5.     int i;  
  6.   
  7.     for (i = 0; i < ARRAY_SIZE(io_types); i++)  
  8.         if (io_types[i].addr_bits == addr_bits &&  
  9.             io_types[i].data_bits == data_bits)  
  10.             break;  
  11.     if (i == ARRAY_SIZE(io_types)) {  
  12.         printk(KERN_ERR  
  13.                "No I/O functions for %d bit address %d bit data\n",  
  14.                addr_bits, data_bits);  
  15.         return -EINVAL;  
  16.     }  
  17.   
  18.     codec->write = io_types[i].write;  
  19.     codec->read = io_types[i].read;  
  20.     codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;  
  21.   
  22.     switch (control) {  
  23.     case SND_SOC_I2C:  
  24. #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))  
  25.         codec->hw_write = (hw_write_t)i2c_master_send;  
  26. #endif  
  27.         if (io_types[i].i2c_read)  
  28.             codec->hw_read = io_types[i].i2c_read;  
  29.   
  30.         codec->control_data = container_of(codec->dev,  
  31.                            struct i2c_client,  
  32.                            dev);  
  33.         break;  
  34.   
  35.     case SND_SOC_SPI:  
  36. #ifdef CONFIG_SPI_MASTER  
  37.         codec->hw_write = do_spi_write;  
  38. #endif  
  39.   
  40.         codec->control_data = container_of(codec->dev,  
  41.                            struct spi_device,  
  42.                            dev);  
  43.         break;  
  44.     }  
  45.   
  46.     return 0;  
  47. }  
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
			       int addr_bits, int data_bits,
			       enum snd_soc_control_type control)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(io_types); i++)
		if (io_types[i].addr_bits == addr_bits &&
		    io_types[i].data_bits == data_bits)
			break;
	if (i == ARRAY_SIZE(io_types)) {
		printk(KERN_ERR
		       "No I/O functions for %d bit address %d bit data\n",
		       addr_bits, data_bits);
		return -EINVAL;
	}

	codec->write = io_types[i].write;
	codec->read = io_types[i].read;
	codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;

	switch (control) {
	case SND_SOC_I2C:
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
		codec->hw_write = (hw_write_t)i2c_master_send;
#endif
		if (io_types[i].i2c_read)
			codec->hw_read = io_types[i].i2c_read;

		codec->control_data = container_of(codec->dev,
						   struct i2c_client,
						   dev);
		break;

	case SND_SOC_SPI:
#ifdef CONFIG_SPI_MASTER
		codec->hw_write = do_spi_write;
#endif

		codec->control_data = container_of(codec->dev,
						   struct spi_device,
						   dev);
		break;
	}

	return 0;
}


代码中对write和read进行了赋值

  1. codec->write = io_types[i].write;  
  2. codec->read = io_types[i].read;  
codec->write = io_types[i].write;
codec->read = io_types[i].read;

 而io_types的原型如下

  1. static struct {  
  2.     int addr_bits;  
  3.     int data_bits;  
  4.     int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);  
  5.     unsigned int (*read)(struct snd_soc_codec *, unsigned int);  
  6.     unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);  
  7. } io_types[] = {  
  8.     {  
  9.         .addr_bits = 4.data_bits = 12,  
  10.         .write = snd_soc_4_12_write.read = snd_soc_4_12_read,  
  11.     },  
  12.     {  
  13.         .addr_bits = 7.data_bits = 9,  
  14.         .write = snd_soc_7_9_write.read = snd_soc_7_9_read,  
  15.     },  
  16.     {  
  17.         .addr_bits = 8.data_bits = 8,  
  18.         .write = snd_soc_8_8_write.read = snd_soc_8_8_read,  
  19.         .i2c_read = snd_soc_8_8_read_i2c,  
  20.     },  
  21.     {  
  22.         .addr_bits = 8.data_bits = 16,  
  23.         .write = snd_soc_8_16_write.read = snd_soc_8_16_read,  
  24.         .i2c_read = snd_soc_8_16_read_i2c,  
  25.     },  
  26.     {  
  27.         .addr_bits = 16.data_bits = 8,  
  28.         .write = snd_soc_16_8_write.read = snd_soc_16_8_read,  
  29.         .i2c_read = snd_soc_16_8_read_i2c,  
  30.     },  
  31.     {  
  32.         .addr_bits = 16.data_bits = 16,  
  33.         .write = snd_soc_16_16_write.read = snd_soc_16_16_read,  
  34.         .i2c_read = snd_soc_16_16_read_i2c,  
  35.     },  
  36. };  
static struct {
	int addr_bits;
	int data_bits;
	int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
	unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
} io_types[] = {
	{
		.addr_bits = 4, .data_bits = 12,
		.write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
	},
	{
		.addr_bits = 7, .data_bits = 9,
		.write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
	},
	{
		.addr_bits = 8, .data_bits = 8,
		.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
		.i2c_read = snd_soc_8_8_read_i2c,
	},
	{
		.addr_bits = 8, .data_bits = 16,
		.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
		.i2c_read = snd_soc_8_16_read_i2c,
	},
	{
		.addr_bits = 16, .data_bits = 8,
		.write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
		.i2c_read = snd_soc_16_8_read_i2c,
	},
	{
		.addr_bits = 16, .data_bits = 16,
		.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
		.i2c_read = snd_soc_16_16_read_i2c,
	},
};


通过ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type); 这句话得知, 我们使用的是7,9

7_9的读写函数如下

  1. static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,  
  2.                  unsigned int value)  
  3. {  
  4.     u8 data[2];  
  5.   
  6.     data[0] = (reg << 1) | ((value >> 8) & 0x0001);  
  7.     data[1] = value & 0x00ff;  
  8.   
  9.     return do_hw_write(codec, reg, value, data, 2);  
  10. }  
static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
			     unsigned int value)
{
	u8 data[2];

	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
	data[1] = value & 0x00ff;

	return do_hw_write(codec, reg, value, data, 2);
}

  1. static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,  
  2.                unsigned int value, const void *data, int len)  
  3. {  
  4.     int ret;  
  5.   
  6.     if (!snd_soc_codec_volatile_register(codec, reg) &&  
  7.         reg < codec->driver->reg_cache_size &&  
  8.         !codec->cache_bypass) {  
  9.         ret = snd_soc_cache_write(codec, reg, value);  
  10.         if (ret < 0)  
  11.             return -1;  
  12.     }  
  13.   
  14.     if (codec->cache_only) {  
  15.         codec->cache_sync = 1;  
  16.         return 0;  
  17.     }  
  18.   
  19.     ret = codec->hw_write(codec->control_data, data, len);  
  20.     if (ret == len)  
  21.         return 0;  
  22.     if (ret < 0)  
  23.         return ret;  
  24.     else  
  25.         return -EIO;  
  26. }  
static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
		       unsigned int value, const void *data, int len)
{
	int ret;

	if (!snd_soc_codec_volatile_register(codec, reg) &&
	    reg < codec->driver->reg_cache_size &&
	    !codec->cache_bypass) {
		ret = snd_soc_cache_write(codec, reg, value);
		if (ret < 0)
			return -1;
	}

	if (codec->cache_only) {
		codec->cache_sync = 1;
		return 0;
	}

	ret = codec->hw_write(codec->control_data, data, len);
	if (ret == len)
		return 0;
	if (ret < 0)
		return ret;
	else
		return -EIO;
}


  1. int snd_soc_cache_write(struct snd_soc_codec *codec,  
  2.             unsigned int reg, unsigned int value)  
  3. {  
  4.     int ret;  
  5.   
  6.     mutex_lock(&codec->cache_rw_mutex);  
  7.   
  8.     if (codec->cache_ops && codec->cache_ops->write) {  
  9.         ret = codec->cache_ops->write(codec, reg, value);  
  10.         mutex_unlock(&codec->cache_rw_mutex);  
  11.         return ret;  
  12.     }  
  13.   
  14.     mutex_unlock(&codec->cache_rw_mutex);  
  15.     return -ENOSYS;  
  16. }  
int snd_soc_cache_write(struct snd_soc_codec *codec,
			unsigned int reg, unsigned int value)
{
	int ret;

	mutex_lock(&codec->cache_rw_mutex);

	if (codec->cache_ops && codec->cache_ops->write) {
		ret = codec->cache_ops->write(codec, reg, value);
		mutex_unlock(&codec->cache_rw_mutex);
		return ret;
	}

	mutex_unlock(&codec->cache_rw_mutex);
	return -ENOSYS;
}


可以看到, 写函数主要操作了二个部分, 一个是 ret = snd_soc_cache_write(codec, reg, value); 另一个是 ret = codec->hw_write(codec->control_data, data, len);

snd_soc_cache_write的原型如下

  1. int snd_soc_cache_write(struct snd_soc_codec *codec,  
  2.             unsigned int reg, unsigned int value)  
  3. {  
  4.     int ret;  
  5.   
  6.     mutex_lock(&codec->cache_rw_mutex);  
  7.   
  8.     if (codec->cache_ops && codec->cache_ops->write) {  
  9.         ret = codec->cache_ops->write(codec, reg, value);  
  10.         mutex_unlock(&codec->cache_rw_mutex);  
  11.         return ret;  
  12.     }  
  13.   
  14.     mutex_unlock(&codec->cache_rw_mutex);  
  15.     return -ENOSYS;  
  16. }  
int snd_soc_cache_write(struct snd_soc_codec *codec,
			unsigned int reg, unsigned int value)
{
	int ret;

	mutex_lock(&codec->cache_rw_mutex);

	if (codec->cache_ops && codec->cache_ops->write) {
		ret = codec->cache_ops->write(codec, reg, value);
		mutex_unlock(&codec->cache_rw_mutex);
		return ret;
	}

	mutex_unlock(&codec->cache_rw_mutex);
	return -ENOSYS;
}

从代码可以看到 写缓存调用的是 ret = codec->cache_ops->write(codec, reg, value);  这个在上文中已经提到。 cache_ops->write的调用函数


ret = codec->hw_write(codec->control_data, data, len); 这个函数调用的原型在snd_soc_codec_set_cache_io函数中也有赋值

  1.     switch (control) {  
  2.     case SND_SOC_I2C:  
  3. #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))  
  4.         codec->hw_write = (hw_write_t)i2c_master_send;  
  5. #endif  
  6.         if (io_types[i].i2c_read)  
  7.             codec->hw_read = io_types[i].i2c_read;  
  8.   
  9.         codec->control_data = container_of(codec->dev,  
  10.                            struct i2c_client,  
  11.                            dev);  
  12.         break;  
  13.   
  14.     case SND_SOC_SPI:  
  15. #ifdef CONFIG_SPI_MASTER  
  16.         codec->hw_write = do_spi_write;  
  17. #endif  
  18.   
  19.         codec->control_data = container_of(codec->dev,  
  20.                            struct spi_device,  
  21.                            dev);  
  22.         break;  
  23.     }  
	switch (control) {
	case SND_SOC_I2C:
#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
		codec->hw_write = (hw_write_t)i2c_master_send;
#endif
		if (io_types[i].i2c_read)
			codec->hw_read = io_types[i].i2c_read;

		codec->control_data = container_of(codec->dev,
						   struct i2c_client,
						   dev);
		break;

	case SND_SOC_SPI:
#ifdef CONFIG_SPI_MASTER
		codec->hw_write = do_spi_write;
#endif

		codec->control_data = container_of(codec->dev,
						   struct spi_device,
						   dev);
		break;
	}


我们使用的是I2C 所以执行i2c_master_send

  1. int i2c_master_send(const struct i2c_client *client, const char *buf, int count)  
  2. {  
  3.     int ret;  
  4.     struct i2c_adapter *adap = client->adapter;  
  5.     struct i2c_msg msg;  
  6.   
  7.     msg.addr = client->addr;  
  8.     msg.flags = client->flags & I2C_M_TEN;  
  9.     msg.len = count;  
  10.     msg.buf = (char *)buf;  
  11.   
  12.     ret = i2c_transfer(adap, &msg, 1);  
  13.   
  14.     /* If everything went ok (i.e. 1 msg transmitted), return #bytes  
  15.        transmitted, else error code. */  
  16.     return (ret == 1) ? count : ret;  
  17. }  
int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
{
	int ret;
	struct i2c_adapter *adap = client->adapter;
	struct i2c_msg msg;

	msg.addr = client->addr;
	msg.flags = client->flags & I2C_M_TEN;
	msg.len = count;
	msg.buf = (char *)buf;

	ret = i2c_transfer(adap, &msg, 1);

	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
	   transmitted, else error code. */
	return (ret == 1) ? count : ret;
}

以上就吧数据写进寄存器里面去了。


还有一个问题没交代清楚, 就是codec->reg_def_copy 的数值, 在wm8960.c中赋值的。


  在wm8960.c中   i2c初始化 wm8960_i2c_probe函数中调用了

  
 ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8960, &wm8960_dai, 1);


该函数中有一段代码

  1. int snd_soc_register_codec(struct device *dev,  
  2.                const struct snd_soc_codec_driver *codec_drv,  
  3.                struct snd_soc_dai_driver *dai_drv,  
  4.                int num_dai)  
  5. {  
int snd_soc_register_codec(struct device *dev,
			   const struct snd_soc_codec_driver *codec_drv,
			   struct snd_soc_dai_driver *dai_drv,
			   int num_dai)
{

...

  1. /* allocate CODEC register cache */  
  2. if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {  
  3.     reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;  
  4.     codec->reg_size = reg_size;  
  5.     /* it is necessary to make a copy of the default register cache  
  6.      * because in the case of using a compression type that requires  
  7.      * the default register cache to be marked as __devinitconst the  
  8.      * kernel might have freed the array by the time we initialize  
  9.      * the cache.  
  10.      */  
  11.     if (codec_drv->reg_cache_default) {  
  12.         codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,  
  13.                           reg_size, GFP_KERNEL);  
  14.         if (!codec->reg_def_copy) {  
  15.             ret = -ENOMEM;  
  16.             goto fail;  
  17.         }  
  18.     }  
  19. }  
	/* allocate CODEC register cache */
	if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
		reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
		codec->reg_size = reg_size;
		/* it is necessary to make a copy of the default register cache
		 * because in the case of using a compression type that requires
		 * the default register cache to be marked as __devinitconst the
		 * kernel might have freed the array by the time we initialize
		 * the cache.
		 */
		if (codec_drv->reg_cache_default) {
			codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
						      reg_size, GFP_KERNEL);
			if (!codec->reg_def_copy) {
				ret = -ENOMEM;
				goto fail;
			}
		}
	}


如果codec_drv->reg_cache_default有值, 则cade->reg_def_copy就拷贝过来。 code->der是传进来的参数  为soc_codec_dev_wm8960


soc_codec_dev_wm8960的原型为


  1. static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {  
  2.     .probe =    wm8960_probe,  
  3.     .remove =   wm8960_remove,  
  4.     .suspend =  wm8960_suspend,  
  5.     .resume =   wm8960_resume,  
  6.     .set_bias_level = wm8960_set_bias_level,  
  7.     .reg_cache_size = ARRAY_SIZE(wm8960_reg),  
  8.     .reg_word_size = sizeof(u16),  
  9.     .reg_cache_default = wm8960_reg,  
  10. };  
static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
	.probe =	wm8960_probe,
	.remove =	wm8960_remove,
	.suspend =	wm8960_suspend,
	.resume =	wm8960_resume,
	.set_bias_level = wm8960_set_bias_level,
	.reg_cache_size = ARRAY_SIZE(wm8960_reg),
	.reg_word_size = sizeof(u16),
	.reg_cache_default = wm8960_reg,
};

所以code_dev->reg_cache_default 指向的为wm8960_reg数组。

  1. /*  
  2.  * wm8960 register cache  
  3.  * We can't read the WM8960 register space when we are  
  4.  * using 2 wire for device control, so we cache them instead.  
  5.  */  
  6. static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {  
  7.     0x0097, 0x0097, 0x0000, 0x0000,  
  8.     0x0000, 0x0008, 0x0000, 0x000a,  
  9.     0x01c0, 0x0000, 0x00ff, 0x00ff,  
  10.     0x0000, 0x0000, 0x0000, 0x0000,  
  11.     0x0000, 0x007b, 0x0100, 0x0032,  
  12.     0x0000, 0x00c3, 0x00c3, 0x01c0,  
  13.     0x0000, 0x0000, 0x0000, 0x0000,  
  14.     0x0000, 0x0000, 0x0000, 0x0000,  
  15.     0x0100, 0x0100, 0x0050, 0x0050,  
  16.     0x0050, 0x0050, 0x0000, 0x0000,  
  17.     0x0000, 0x0000, 0x0040, 0x0000,  
  18.     0x0000, 0x0050, 0x0050, 0x0000,  
  19.     0x0002, 0x0037, 0x004d, 0x0080,  
  20.     0x0008, 0x0031, 0x0026, 0x00e9,  
  21. };  
/*
 * wm8960 register cache
 * We can't read the WM8960 register space when we are
 * using 2 wire for device control, so we cache them instead.
 */
static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
	0x0097, 0x0097, 0x0000, 0x0000,
	0x0000, 0x0008, 0x0000, 0x000a,
	0x01c0, 0x0000, 0x00ff, 0x00ff,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x007b, 0x0100, 0x0032,
	0x0000, 0x00c3, 0x00c3, 0x01c0,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0000, 0x0000,
	0x0100, 0x0100, 0x0050, 0x0050,
	0x0050, 0x0050, 0x0000, 0x0000,
	0x0000, 0x0000, 0x0040, 0x0000,
	0x0000, 0x0050, 0x0050, 0x0000,
	0x0002, 0x0037, 0x004d, 0x0080,
	0x0008, 0x0031, 0x0026, 0x00e9,
};



综上, soc在进行读的时候, 完全是操作wm8960这个数组,而在写的时候, 会先把数值写进数组, 在进行寄存器操作


新手:接触Linux一个星期, 不知道分析的对不对。  希望大家多多指点。











0
0
 
 
猜你在找
深度学习基础与TensorFlow实践
【在线峰会】前端开发重点难点技术剖析与创新实践
【在线峰会】一天掌握物联网全栈开发之道
【在线峰会】如何高质高效的进行Android技术开发
机器学习40天精英计划
Python数据挖掘与分析速成班
微信小程序开发实战
JFinal极速开发企业实战
备战2017软考 系统集成项目管理工程师 学习套餐
Python大型网络爬虫项目开发实战(全套)
查看评论

  暂无评论

发表评论
  • 用 户 名:
  • u013934858
  •   
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值