fs4412開發板學習筆記(十五)
阿新 • • 發佈:2019-01-06
音效卡驅動dts.
======
wm8960:[email protected]1a{
compatible="wlf,wm8960";
reg = <0x1a>;
};
i2s0:[email protected]03830000 {
compatible = "samsung,exynos4412-i2s";
reg = <0x03830000 0x100>;
dmas = <&pdma0 10
&pdma0 9
&pdma0 8>;
dma-names = "tx", "rx", "tx-sec";
clocks = <&clock_audss EXYNOS_I2S_BUS>,
<&clock_audss EXYNOS_I2S_BUS>,
<&clock_audss EXYNOS_SCLK_I2S>;
clock-names = "iis", "i2s_opclk0", "i2s_opclk1" ;
samsung,supports-6ch;
samsung,supports-rstclr;
samsung,supports-secdai;
samsung,idma-addr = <0x03000000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_0>;
};
sound {
compatible = "bva,implant-bva"
samsung,i2s-controller = <&i2s0>;
samsung,audio-codec = <&wm8960>;
};
============
static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
/* Find CPU DAI from registered DAIs*/
list_for_each_entry(cpu_dai, &dai_list, list) {
if (dai_link->cpu_of_node &&
(cpu_dai->dev->of_node != dai_link->cpu_of_node))
continue;
if (dai_link->cpu_name &&
strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name))
continue;
if (dai_link->cpu_dai_name &&
strcmp(cpu_dai->name, dai_link->cpu_dai_name))
continue;
rtd->cpu_dai = cpu_dai;
}
printk("\n=========soc_bind_dai_link=============\n");//soc-core.c P903
/* Find CODEC from registered CODECs */
list_for_each_entry(codec, &codec_list, list) {
if (dai_link->codec_of_node) {
if (codec->dev->of_node != dai_link->codec_of_node)
continue;
} else {
if (strcmp(codec->name, dai_link->codec_name))
continue;
}
rtd->codec = codec;
/*
* CODEC found, so find CODEC DAI from registered DAIs from
* this CODEC
*/
printk("\n=========list_for_each_entry 903=============\n");
list_for_each_entry(codec_dai, &dai_list, list) {
printk("\n===%s=====%s======\n",codec_dai->name,dai_link->codec_dai_name);
if (codec->dev == codec_dai->dev &&
!strcmp(codec_dai->name,
dai_link->codec_dai_name)) {
rtd->codec_dai = codec_dai;
}
}
if (!rtd->codec_dai) {
dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
dai_link->codec_dai_name);
return -EPROBE_DEFER;
}
}
}
問題:
[ 1.915000] wm8960 0-001a: (wm8960_probe)No platform data supplied
解決:
註冊裝置驅動的匯流排號應該用0而不是4
[ 1.925000] wm8960 0-001a: Failed to issue reset
[ 1.930000] Failed to issue reset ret=-6
[ 1.930000] wm8960 0-001a: ASoC: failed to probe CODEC -6
[ 1.935000] soc-audio soc-audio: ASoC: failed to instantiate card -6
#define ENXIO 6 /* No such device or address */
[ 1.965000] regulator-dummy: disabling
[ 1.600000] ==codec->dev!=NULL snd_soc_register_codec ==
[ 1.605000] ==codec->dev.platform_data!=NULL snd_soc_register_codec ==
[ 1.805000] soc-audio soc-audio: ASoC: CODEC wm8960.0-001a not registered
[ 1.810000] platform soc-audio: Driver soc-audio requests probe deferral
[ 1.910000] soc-audio: probe of soc-audio failed with error -22
1、如何檢視linux核心中註冊了那些i2c裝置。
2、i2c裝置和i2c驅動的匹配。
static int wm8960_probe(struct snd_soc_codec *codec)
{
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type);//設定codec的讀寫等函式
||
codec->write = hw_write;//soc-io.c 98
codec->read = hw_read;
codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev),&config);
||
struct regmap *regmap_init_i2c(struct i2c_client *i2c,const struct regmap_config *config)//regmap-i2c.c 110
{
return regmap_init(&i2c->dev, ®map_i2c, &i2c->dev, config);
}
||
struct regmap *regmap_init(struct device *dev,const struct regmap_bus *bus,void *bus_context,const struct regmap_config *config)//regmap.c 395
{
map->bus = bus;//443
if (map->format.format_write) {//639
map->defer_caching = false;
map->reg_write = _regmap_bus_formatted_write;//在這裡設定了下面要使用的map->reg_write函式。
printk("map->reg_write = _regmap_bus_formatted_write;\n");
} else if (map->format.format_val) {
map->defer_caching = true;
map->reg_write = _regmap_bus_raw_write;
printk("map->reg_write = _regmap_bus_raw_write;\n");
}
}
ret = wm8960_reset(codec);//wm8960.c 1019
}
||
unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val)
{
dev_dbg(codec->dev, "write %x = %x\n", reg, val);
trace_snd_soc_reg_write(codec, reg, val);
return codec->write(codec, reg, val);//soc-core.c 2349
}
||
static int hw_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
ret=regmap_write(codec->control_data, reg, value);//soc-io.c 45
}
||
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{
ret = _regmap_write(map, reg, val);//regmap.c 1348
}
||
int _regmap_write(struct regmap *map, unsigned int reg,
unsigned int val)
{
ret=map->reg_write(context, reg, val);//regmap.c 1322
}
||
static int _regmap_bus_formatted_write(void *context, unsigned int reg,
unsigned int val)
{
ret = map->bus->write(map->bus_context, map->work_buf,map->format.buf_size);//regmap.c 1268
}
||
static int regmap_i2c_write(void *context, const void *data, size_t count)//regmap-i2c.c 18
{
ret = i2c_master_send(i2c, data, count);
}
||
int i2c_master_send(const struct i2c_client *client, const char *buf, int count)//i2c-core.c 1807
{
ret = i2c_transfer(adap, &msg, 1);//<<==== ret=-6
}
||
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
ret = __i2c_transfer(adap, msgs, num);//i2c-core.c 1788
}
||
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
ret = adap->algo->master_xfer(adap, msgs, num);//i2c-core.c 1725
}
||
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {//drivers/i2c/busses/i2c-s3c2410.c
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
||
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
for (retry = 0; retry < adap->retries; retry++) {
ret = s3c24xx_i2c_doxfer(i2c, msgs, num);//第一次就等於-6
}
}
||
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
struct i2c_msg *msgs, int num)
{
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);//drivers/i2c/busses/i2c-s3c2410.c 733
ret = i2c->msg_idx;在這裡將ret=-6
}
||
static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
{
i2c->msg_idx = ret;//drivers/i2c/busses/i2c-s3c2410.c 195
}
||
static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
struct i2c_msg *msg)
{
i2c_s3c_irq_nextbyte(i2c, stat);//drivers/i2c/busses/i2c-s3c2410.c 300
}
------------------------------------------------------------
static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
{
struct s3c24xx_i2c *i2c = dev_id;
unsigned long status;
unsigned long tmp;
status = readl(i2c->regs + S3C2410_IICSTAT);//問題出在這裡,status=0xf1低4位應該為0
printk("\n--%s-----%d-----stat=0x%x\n",__FUNCTION__,__LINE__,status);
if (status & S3C2410_IICSTAT_ARBITR) {
/* deal with arbitration loss */
dev_err(i2c->dev, "deal with arbitration loss\n");
}
if (i2c->state == STATE_IDLE) {
dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_IICCON_IRQPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
goto out;
}
/* pretty much this leaves us with the fact that we've
* transmitted or received whatever byte we last sent */
printk("\n--%s-----%d-----stat=0x%x\n",__FUNCTION__,__LINE__,status);//問題出在這裡,status應該為0,但在這裡變為非零,導致下面的if語句成立。
i2c_s3c_irq_nextbyte(i2c, status);
out:
return IRQ_HANDLED;
}
||
static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
{
case STATE_START:
if (iicstat & S3C2410_IICSTAT_LASTBIT &&!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
/* ack was not received... */
dev_dbg(i2c->dev, "ack was not received\n");
s3c24xx_i2c_stop(i2c, -ENXIO); //drivers/i2c/busses/i2c-s3c2410.c 435
printk("--%s-----%d-----\n",__FUNCTION__,__LINE__);// -ENXIO=-6最終在這裡出錯
goto out_ack;
}
}