📄 uda1341.c
字号:
static void __devinit snd_uda1341_proc_init(snd_card_t *card, struct l3_client *clnt){ snd_info_entry_t *entry; if (! snd_card_proc_new(card, "uda1341", &entry)) snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_read); if (! snd_card_proc_new(card, "uda1341-regs", &entry)) snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_regs_read);}/* }}} *//* {{{ Mixer controls setting *//* {{{ UDA1341 single functions */#define UDA1341_SINGLE(xname, where, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_single, \ .get = snd_uda1341_get_single, .put = snd_uda1341_put_single, \ .private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) \}static int snd_uda1341_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ int mask = (kcontrol->private_value >> 12) & 63; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}static int snd_uda1341_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ struct l3_client *clnt = snd_kcontrol_chip(kcontrol); uda1341_t *uda = clnt->driver_data; int where = kcontrol->private_value & 31; int mask = (kcontrol->private_value >> 12) & 63; int invert = (kcontrol->private_value >> 18) & 1; ucontrol->value.integer.value[0] = uda->cfg[where]; if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0;}static int snd_uda1341_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ struct l3_client *clnt = snd_kcontrol_chip(kcontrol); uda1341_t *uda = clnt->driver_data; int where = kcontrol->private_value & 31; int reg = (kcontrol->private_value >> 5) & 15; int shift = (kcontrol->private_value >> 9) & 7; int mask = (kcontrol->private_value >> 12) & 63; int invert = (kcontrol->private_value >> 18) & 1; unsigned short val; val = (ucontrol->value.integer.value[0] & mask); if (invert) val = mask - val; uda->cfg[where] = val; return snd_uda1341_update_bits(clnt, reg, mask, shift, val, FLUSH);}/* }}} *//* {{{ UDA1341 enum functions */#define UDA1341_ENUM(xname, where, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_enum, \ .get = snd_uda1341_get_enum, .put = snd_uda1341_put_enum, \ .private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) \}static int snd_uda1341_info_enum(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ int where = kcontrol->private_value & 31; const char **texts; // this register we don't handle this way if (!uda1341_enum_items[where]) return -EINVAL; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = uda1341_enum_items[where]; if (uinfo->value.enumerated.item >= uda1341_enum_items[where]) uinfo->value.enumerated.item = uda1341_enum_items[where] - 1; texts = uda1341_enum_names[where]; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_uda1341_get_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ struct l3_client *clnt = snd_kcontrol_chip(kcontrol); uda1341_t *uda = clnt->driver_data; int where = kcontrol->private_value & 31; ucontrol->value.enumerated.item[0] = uda->cfg[where]; return 0;}static int snd_uda1341_put_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ struct l3_client *clnt = snd_kcontrol_chip(kcontrol); uda1341_t *uda = clnt->driver_data; int where = kcontrol->private_value & 31; int reg = (kcontrol->private_value >> 5) & 15; int shift = (kcontrol->private_value >> 9) & 7; int mask = (kcontrol->private_value >> 12) & 63; uda->cfg[where] = (ucontrol->value.enumerated.item[0] & mask); return snd_uda1341_update_bits(clnt, reg, mask, shift, uda->cfg[where], FLUSH);}/* }}} *//* {{{ UDA1341 2regs functions */#define UDA1341_2REGS(xname, where, reg_1, reg_2, shift_1, shift_2, mask_1, mask_2, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_uda1341_info_2regs, \ .get = snd_uda1341_get_2regs, .put = snd_uda1341_put_2regs, \ .private_value = where | (reg_1 << 5) | (reg_2 << 9) | (shift_1 << 13) | (shift_2 << 16) | \ (mask_1 << 19) | (mask_2 << 25) | (invert << 31) \}static int snd_uda1341_info_2regs(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ int mask_1 = (kcontrol->private_value >> 19) & 63; int mask_2 = (kcontrol->private_value >> 25) & 63; int mask; mask = (mask_2 + 1) * (mask_1 + 1) - 1; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}static int snd_uda1341_get_2regs(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ struct l3_client *clnt = snd_kcontrol_chip(kcontrol); uda1341_t *uda = clnt->driver_data; int where = kcontrol->private_value & 31; int mask_1 = (kcontrol->private_value >> 19) & 63; int mask_2 = (kcontrol->private_value >> 25) & 63; int invert = (kcontrol->private_value >> 31) & 1; int mask; mask = (mask_2 + 1) * (mask_1 + 1) - 1; ucontrol->value.integer.value[0] = uda->cfg[where]; if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0;}static int snd_uda1341_put_2regs(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ struct l3_client *clnt = snd_kcontrol_chip(kcontrol); uda1341_t *uda = clnt->driver_data; int where = kcontrol->private_value & 31; int reg_1 = (kcontrol->private_value >> 5) & 15; int reg_2 = (kcontrol->private_value >> 9) & 15; int shift_1 = (kcontrol->private_value >> 13) & 7; int shift_2 = (kcontrol->private_value >> 16) & 7; int mask_1 = (kcontrol->private_value >> 19) & 63; int mask_2 = (kcontrol->private_value >> 25) & 63; int invert = (kcontrol->private_value >> 31) & 1; int mask; unsigned short val1, val2, val; val = ucontrol->value.integer.value[0]; mask = (mask_2 + 1) * (mask_1 + 1) - 1; val1 = val & mask_1; val2 = (val / (mask_1 + 1)) & mask_2; if (invert) { val1 = mask_1 - val1; val2 = mask_2 - val2; } uda->cfg[where] = invert ? mask - val : val; //FIXME - return value snd_uda1341_update_bits(clnt, reg_1, mask_1, shift_1, val1, FLUSH); return snd_uda1341_update_bits(clnt, reg_2, mask_2, shift_2, val2, FLUSH);}/* }}} */ static snd_kcontrol_new_t snd_uda1341_controls[] = { UDA1341_SINGLE("Master Playback Switch", CMD_MUTE, data0_2, 2, 1, 1), UDA1341_SINGLE("Master Playback Volume", CMD_VOLUME, data0_0, 0, 63, 1), UDA1341_SINGLE("Bass Playback Volume", CMD_BASS, data0_1, 2, 15, 0), UDA1341_SINGLE("Treble Playback Volume", CMD_TREBBLE, data0_1, 0, 3, 0), UDA1341_SINGLE("Input Gain Switch", CMD_IGAIN, stat1, 5, 1, 0), UDA1341_SINGLE("Output Gain Switch", CMD_OGAIN, stat1, 6, 1, 0), UDA1341_SINGLE("Mixer Gain Channel 1 Volume", CMD_CH1, ext0, 0, 31, 1), UDA1341_SINGLE("Mixer Gain Channel 2 Volume", CMD_CH2, ext1, 0, 31, 1), UDA1341_SINGLE("Mic Sensitivity Volume", CMD_MIC, ext2, 2, 7, 0), UDA1341_SINGLE("AGC Output Level", CMD_AGC_LEVEL, ext6, 0, 3, 0), UDA1341_SINGLE("AGC Time Constant", CMD_AGC_TIME, ext6, 2, 7, 0), UDA1341_SINGLE("AGC Time Constant Switch", CMD_AGC, ext4, 4, 1, 0), UDA1341_SINGLE("DAC Power", CMD_DAC, stat1, 0, 1, 0), UDA1341_SINGLE("ADC Power", CMD_ADC, stat1, 1, 1, 0), UDA1341_ENUM("Peak detection", CMD_PEAK, data0_2, 5, 1, 0), UDA1341_ENUM("De-emphasis", CMD_DEEMP, data0_2, 3, 3, 0), UDA1341_ENUM("Mixer mode", CMD_MIXER, ext2, 0, 3, 0), UDA1341_ENUM("Filter mode", CMD_FILTER, data0_2, 0, 3, 0), UDA1341_2REGS("Gain Input Amplifier Gain (channel 2)", CMD_IG, ext4, ext5, 0, 0, 3, 31, 0),};static void uda1341_free(struct l3_client *uda1341){ l3_detach_client(uda1341); // calls kfree for driver_data (uda1341_t) kfree(uda1341);}static int uda1341_dev_free(snd_device_t *device){ struct l3_client *clnt = device->device_data; uda1341_free(clnt); return 0;}int __init snd_chip_uda1341_mixer_new(snd_card_t *card, struct l3_client **clnt){ static snd_device_ops_t ops = { .dev_free = uda1341_dev_free, }; struct l3_client *uda1341; int idx, err; snd_assert(card != NULL, return -EINVAL); uda1341 = kzalloc(sizeof(*uda1341), GFP_KERNEL); if (uda1341 == NULL) return -ENOMEM; if ((err = l3_attach_client(uda1341, "l3-bit-sa1100-gpio", "snd-uda1341"))) { kfree(uda1341); return err; } if ((err = snd_device_new(card, SNDRV_DEV_CODEC, uda1341, &ops)) < 0) { l3_detach_client(uda1341); kfree(uda1341); return err; } for (idx = 0; idx < ARRAY_SIZE(snd_uda1341_controls); idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_uda1341_controls[idx], uda1341))) < 0) return err; } *clnt = uda1341; strcpy(card->mixername, "UDA1341TS Mixer"); ((uda1341_t *)uda1341->driver_data)->card = card; snd_uda1341_proc_init(card, uda1341); return 0;}/* }}} *//* {{{ L3 operations */static int uda1341_attach(struct l3_client *clnt){ struct uda1341 *uda; uda = kzalloc(sizeof(*uda), 0, GFP_KERNEL); if (!uda) return -ENOMEM; /* init fixed parts of my copy of registers */ uda->regs[stat0] = STAT0; uda->regs[stat1] = STAT1; uda->regs[data0_0] = DATA0_0; uda->regs[data0_1] = DATA0_1; uda->regs[data0_2] = DATA0_2; uda->write = snd_uda1341_codec_write; uda->read = snd_uda1341_codec_read; spin_lock_init(&uda->reg_lock); clnt->driver_data = uda; return 0;}static void uda1341_detach(struct l3_client *clnt){ kfree(clnt->driver_data);}static intuda1341_command(struct l3_client *clnt, int cmd, void *arg){ if (cmd != CMD_READ_REG) return snd_uda1341_cfg_write(clnt, cmd, (int) arg, FLUSH); return snd_uda1341_codec_read(clnt, (int) arg);}static int uda1341_open(struct l3_client *clnt){ struct uda1341 *uda = clnt->driver_data; uda->active = 1; /* init default configuration */ snd_uda1341_cfg_write(clnt, CMD_RESET, 0, REGS_ONLY); snd_uda1341_cfg_write(clnt, CMD_FS, F256, FLUSH); // unknown state after reset snd_uda1341_cfg_write(clnt, CMD_FORMAT, LSB16, FLUSH); // unknown state after reset snd_uda1341_cfg_write(clnt, CMD_OGAIN, ON, FLUSH); // default off after reset snd_uda1341_cfg_write(clnt, CMD_IGAIN, ON, FLUSH); // default off after reset snd_uda1341_cfg_write(clnt, CMD_DAC, ON, FLUSH); // ??? default value after reset snd_uda1341_cfg_write(clnt, CMD_ADC, ON, FLUSH); // ??? default value after reset snd_uda1341_cfg_write(clnt, CMD_VOLUME, 20, FLUSH); // default 0dB after reset snd_uda1341_cfg_write(clnt, CMD_BASS, 0, REGS_ONLY); // default value after reset snd_uda1341_cfg_write(clnt, CMD_TREBBLE, 0, REGS_ONLY); // default value after reset snd_uda1341_cfg_write(clnt, CMD_PEAK, AFTER, REGS_ONLY);// default value after reset snd_uda1341_cfg_write(clnt, CMD_DEEMP, NONE, REGS_ONLY);// default value after reset //at this moment should be QMUTED by h3600_audio_init snd_uda1341_cfg_write(clnt, CMD_MUTE, OFF, REGS_ONLY); // default value after reset snd_uda1341_cfg_write(clnt, CMD_FILTER, MAX, FLUSH); // defaul flat after reset snd_uda1341_cfg_write(clnt, CMD_CH1, 31, FLUSH); // default value after reset snd_uda1341_cfg_write(clnt, CMD_CH2, 4, FLUSH); // default value after reset snd_uda1341_cfg_write(clnt, CMD_MIC, 4, FLUSH); // default 0dB after reset snd_uda1341_cfg_write(clnt, CMD_MIXER, MIXER, FLUSH); // default doub.dif.mode snd_uda1341_cfg_write(clnt, CMD_AGC, OFF, FLUSH); // default value after reset snd_uda1341_cfg_write(clnt, CMD_IG, 0, FLUSH); // unknown state after reset snd_uda1341_cfg_write(clnt, CMD_AGC_TIME, 0, FLUSH); // default value after reset snd_uda1341_cfg_write(clnt, CMD_AGC_LEVEL, 0, FLUSH); // default value after reset return 0;}static void uda1341_close(struct l3_client *clnt){ struct uda1341 *uda = clnt->driver_data; uda->active = 0;}/* }}} *//* {{{ Module and L3 initialization */static struct l3_ops uda1341_ops = { .open = uda1341_open, .command = uda1341_command, .close = uda1341_close,};static struct l3_driver uda1341_driver = { .name = UDA1341_ALSA_NAME, .attach_client = uda1341_attach, .detach_client = uda1341_detach, .ops = &uda1341_ops, .owner = THIS_MODULE,};static int __init uda1341_init(void){ return l3_add_driver(&uda1341_driver);}static void __exit uda1341_exit(void){ l3_del_driver(&uda1341_driver);}module_init(uda1341_init);module_exit(uda1341_exit);MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Philips UDA1341 CODEC driver for ALSA");MODULE_SUPPORTED_DEVICE("{{UDA1341,UDA1341TS}}");EXPORT_SYMBOL(snd_chip_uda1341_mixer_new);/* }}} *//* * Local variables: * indent-tabs-mode: t * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -