datasheet 看到這個不叫 i2c,叫 2 wire。
從 2 wire command diagram 來看.. 的確很奇怪:
address 部份跟一般 i2c 一樣,前 7 個是 address,最後一個 bit 是 read/write bit
接著是 reg , 只有 7 bit,所以最後一個 bit 是 data 的 highest bit
wm8974 的 reg 只有 7 bit,data 有 9 bit
register value 說明也真的有定義第9bit..
所以 i2c protocl:
1: chip address(7)+R/W(1) 2: reg index(7) + Data 8th bit(1) 3: Data 7-0 bit (8)跟一般 I2C 裝置不一樣。
因為這樣,wm8974 沒有 read 動作。
也就是說,不能 read register。 --- 不然 protocol 要怎樣....
Linux driver 的部份:
古老的 wm8974 driver 使用自己提供的 i2c_read, i2c_write,看得出這個奇怪的動作:
static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec * codec, unsigned int reg) { u16 *cache = codec->reg_cache; if (reg == WM8974_RESET) return 0; if (reg >= WM8974_CACHEREGNUM) return -1; return cache[reg]; } /* * write wm8974 register cache */ static inline void wm8974_write_reg_cache(struct snd_soc_codec *codec, u16 reg, unsigned int value) { u16 *cache = codec->reg_cache; if (reg >= WM8974_CACHEREGNUM) return; cache[reg] = value; } /* * write to the WM8974 register space */ static int wm8974_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[2]; /* data is * D15..D9 WM8974 register offset * D8...D0 register data */ data[0] = (reg << 1) | ((value >> 8) & 0x0001); data[1] = value & 0x00ff; wm8974_write_reg_cache (codec, reg, value); if (codec->hw_write(codec->control_data, data, 2) == 2) return 0; else return -EIO; }i2c_write 內容有看到把 data shift 到 reg 一個bit
然後沒有提供 i2c_read
然後 driver 註冊時...
static int wm8974_init(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; int ret = 0; codec->name = "WM8974"; codec->owner = THIS_MODULE; codec->read = wm8974_read_reg_cache; codec->write = wm8974_write; ..read 用的是 read_reg_cache
然後新版的kernel (3.1 以上),新增加了 regmap 這個 結構,
就是把 register map cache 起來,write 時同時更新 cache,
read 時就拿 cache 值,不用真的去 read。
-- 當然也可以真的去 read
同時 regmap 也增加了 reg_bits, val_bits 這兩個 properties。
所以新版的 wm8974 driver,已經有:
static const struct regmap_config wm8974_regmap = { .reg_bits = 7, .val_bits = 9, .max_register = WM8974_MONOMIX, .reg_defaults = wm8974_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults), .cache_type = REGCACHE_FLAT, };比較漂亮的寫法就是用regmap : regmap, 有關沒對齊的 reg, value bits 的 i2c transfer function.
用了 regmap,cache type 用 FLAT,就會 使用 cache,這樣,read 就會從 cache 做,
這時候,要 dump register 舊只能用 regmap support 的地方:
# cat /sys/kernel/debug/regmap/2-001a/registers 00: 0000 01: 002e 02: 0000 03: 0000 04: 0010 05: 0001 06: 0120 07: 0000 08: 0000 09: 0000 0a: 0041 0b: 00d7 0c: 0000 0d: 0000 0e: 0100 0f: 00ff 10: 0000 11: 0000 12: 012c 13: 002c 14: 002c 15: 002c 16: 002c 17: 0000 18: 0032 19: 0000 1a: 0000 1b: 0000 1c: 0000 1d: 0000 1e: 0000 1f: 0000 20: 0038 21: 000b 22: 0032 23: 0000 24: 001b 25: 0001 26: 0133 27: 0066 28: 0000 29: 0000 2a: 0000 2b: 0000 2c: 0003 2d: 0010 2e: 0000 2f: 0000 30: 0000 31: 0002 32: 0000 33: 0000 34: 0000 35: 0000 36: 0025 37: 0000 38: 0001
沒有留言:
張貼留言