linux 驱动 i2c
来源:互联网 发布:淘宝店铺头像图片 编辑:程序博客网 时间:2024/06/05 05:55
http://www.cnblogs.com/swnuwangyun/p/4233460.html
在分析snd_soc_codec_driver的结构体时,发现有些芯片的驱动中定义了字段reg_word_size, reg_cache_size, reg_cache_default,但没有定义read/write,如wm8993:
static struct snd_soc_codec_driver soc_codec_dev_wm8993 = { .probe = wm8993_probe, .remove = wm8993_remove, .suspend = wm8993_suspend, .resume = wm8993_resume, .set_bias_level = wm8993_set_bias_level, .reg_cache_size = ARRAY_SIZE(wm8993_reg_defaults), .reg_word_size = sizeof(u16), .reg_cache_default = wm8993_reg_defaults, .volatile_register = wm8993_volatile,};
而另外的一些芯片驱动中,则定义了字段read, write,如wm8400和cx20442:
static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .probe = wm8400_codec_probe, .remove = wm8400_codec_remove, .suspend = wm8400_suspend, .resume = wm8400_resume, .read = wm8400_read, .write = wm8400_write, .set_bias_level = wm8400_set_bias_level,};
static struct snd_soc_codec_driver cx20442_codec_dev = { .probe = cx20442_codec_probe, .remove = cx20442_codec_remove, .reg_cache_default = &cx20442_reg, .reg_cache_size = 1, .reg_word_size = sizeof(u8), .read = cx20442_read_reg_cache, .write = cx20442_write, .dapm_widgets = cx20442_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets), .dapm_routes = cx20442_audio_map, .num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),};
猜测read/write应该和snd_soc_read/write有关,在soc_core.c中注意到snd_soc_read的源码:
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg){ unsigned int ret; ret = codec->read(codec, reg); dev_dbg(codec->dev, "read %x => %x\n", reg, ret); trace_snd_soc_reg_read(codec, reg, ret); return ret;}EXPORT_SYMBOL_GPL(snd_soc_read);
因此,要想使用snd_soc_read,必须要设置codec->read回调函数,当我们提供了read/write函数时,在snd_soc_register_codec函数中会设置codec->read
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){ ... codec->write = codec_drv->write; codec->read = codec_drv->read; codec->volatile_register = codec_drv->volatile_register;
OK,这里和我们soc_codec_dev_wm8400以及cx20442_codec_dev都对应的上,snd_soc_read最终会调用我们提供的回调函数。
问题来了,soc_codec_dev_wm8993中并没有提供回调函数,snd_soc_read是如何工作的呢?刚开始百思不得其解,肯定会有什么地方设置了codec->read!继续找代码,终于在soc_cache.c中找到了一个神奇的函数:snd_soc_codec_set_cache_io,看看代码片段:
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, int addr_bits, int data_bits, enum snd_soc_control_type control){ ... codec->write = io_types[i].write; codec->read = io_types[i].read; codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
果然,它设置了codec->read!而在wm8993的probe函数中,有如下的调用:
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
它设置了I2C的地址宽度为8位,寄存器宽度为16位,I2C通信方式,如果根据这些参数继续追踪io_types[i].read,则会发现它最终调用了I2C的标准读函数:
static unsigned int do_i2c_read(struct snd_soc_codec *codec, void *reg, int reglen, void *data, int datalen){ struct i2c_msg xfer[2]; int ret; struct i2c_client *client = codec->control_data; /* Write register */ xfer[0].addr = client->addr; xfer[0].flags = 0; xfer[0].len = reglen; xfer[0].buf = reg; xfer[0].scl_rate = 100 * 1000; /* Read data */ xfer[1].addr = client->addr; xfer[1].flags = I2C_M_RD; xfer[1].len = datalen; xfer[1].buf = data; ret = i2c_transfer(client->adapter, xfer, 2); if (ret == 2) return 0; else if (ret < 0) return ret; else return -EIO;}
- LINUX:i2c 驱动架构
- linux i2c驱动笔记
- linux I2C驱动分析
- linux I2C驱动分析
- linux i2c驱动总结
- Linux I2C 驱动分析
- linux下I2C驱动
- linux i2c驱动笔记
- Linux驱动I2C分析
- linux i2c 驱动分析
- linux i2c驱动笔记
- Linux--I2C驱动分析
- linux i2c设备驱动
- Linux I2C 总线驱动
- Linux I2C 设备驱动
- Linux I2C驱动:i2c_device_id
- linux i2c驱动分析
- linux i2c驱动
- Android实现数据存储技术
- Java中字符表示
- xctool工具
- Android Gradle 中的使用maven私有仓库
- TextView通过Html显示图片
- linux 驱动 i2c
- 详解LINUX的交换分区---SWAP
- Mac系统如何编辑hosts文件
- iOS键盘弹出遮挡输入框问题
- xcode项目依赖_基于一个工作空间不同工程的分层
- 推荐!手把手教你使用Git
- Redis学习记录之Script(二十)
- 使用对象集合(通过Foundation框架使用OC处理数组)
- STVD环境下的#pragma section 用法