diff options
Diffstat (limited to 'sound/soc/codecs/aic3xxx_cfw_ops.c')
-rw-r--r-- | sound/soc/codecs/aic3xxx_cfw_ops.c | 918 |
1 files changed, 0 insertions, 918 deletions
diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.c b/sound/soc/codecs/aic3xxx_cfw_ops.c deleted file mode 100644 index 4f8e3a533a08..000000000000 --- a/sound/soc/codecs/aic3xxx_cfw_ops.c +++ /dev/null @@ -1,918 +0,0 @@ -#ifndef AIC3XXX_CFW_HOST_BLD -# include <linux/module.h> -# include <linux/delay.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <linux/slab.h> -#include <sound/tlv.h> -# define warn(fmt, ...) printk(fmt "\n", ##__VA_ARGS__) -# define error(fmt, ...) printk(fmt "\n", ##__VA_ARGS__) - -#else -# define _GNU_SOURCE -# include <stdlib.h> -# include "utils.h" -# include <string.h> -# include <assert.h> -# define EINVAL 1 - -#endif - -#include "aic3xxx_cfw.h" -#include "aic3xxx_cfw_ops.h" -#ifndef AIC3XXX_CFW_HOST_BLD -static struct cfw_project *aic3xxx_cfw_unpickle(void *pcfw, int n); -#endif - - -/* - * Firmware version numbers are used to make sure that the - * host and target code stay in sync. It is _not_ recommended - * to provide this number from the outside (E.g., from a makefile) - * Instead, a set of automated tools are relied upon to keep the numbers - * in sync at the time of host testing. - */ -#define CFW_FW_VERSION 0x000100B3 - -static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim); -static int aic3xxx_cfw_dlcfg(struct cfw_state *ps, struct cfw_image *pim); -static int aic3xxx_cfw_dlctl(struct cfw_state *ps, struct cfw_block *pb, - u32 mute_flags); -static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb); -static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask, - u8 data); -static int aic3xxx_cfw_set_mode_id(struct cfw_state *ps); -static int aic3xxx_cfw_mute(struct cfw_state *ps, int mute, u32 flags); -static int aic3xxx_cfw_setmode_cfg_u(struct cfw_state *ps, int mode, int cfg); -static int aic3xxx_cfw_setcfg_u(struct cfw_state *ps, int cfg); -static int aic3xxx_cfw_transition_u(struct cfw_state *ps, char *ttype); -static int aic3xxx_cfw_set_pll_u(struct cfw_state *ps, int asi); -static int aic3xxx_cfw_control_u(struct cfw_state *ps, char *cname, int param); - - -#if defined(AIC3XXX_CFW_HOST_BLD) - -static int mutex_init(struct mutex *m) -{ - m->lock = 0; - return 0; -} - -static int mutex_lock(struct mutex *m) -{ - assert(m->lock == 0); - m->lock = 1; - return 0; -} - -static int mutex_unlock(struct mutex *m) -{ - assert(m->lock == 1); - m->lock = 0; - return 0; -} -/* -static void mdelay(int val) -{ - int i; - for (i = 0; i < (val * 10); i++); -} -*/ -#endif - -int aic3xxx_cfw_init(struct cfw_state *ps, struct aic3xxx_codec_ops const *ops, - void *ops_obj) -{ - ps->ops = ops; - ps->ops_obj = ops_obj; - ps->pjt = NULL; - mutex_init(&ps->mutex); - return 0; -} - -int aic3xxx_cfw_lock(struct cfw_state *ps, int lock) -{ - if (lock) - mutex_lock(&ps->mutex); - else - mutex_unlock(&ps->mutex); - return 0; -} - -int aic3xxx_cfw_reload(struct cfw_state *ps, void *pcfw, int n) -{ - ps->pjt = aic3xxx_cfw_unpickle(pcfw, n); - ps->cur_mode_id = - ps->cur_mode = ps->cur_pfw = ps->cur_ovly = ps->cur_cfg = -1; - if (ps->pjt == NULL) - return -1; - return 0; -} - -int aic3xxx_cfw_setmode(struct cfw_state *ps, int mode) -{ - struct cfw_project *pjt; - int ret; - - aic3xxx_cfw_lock(ps, 1); - pjt = ps->pjt; - if (pjt == NULL) { - aic3xxx_cfw_lock(ps, 0); - return -1; - } - ret = aic3xxx_cfw_setmode_cfg_u(ps, mode, pjt->mode[mode]->cfg); - aic3xxx_cfw_lock(ps, 0); - return ret; -} - -int aic3xxx_cfw_setcfg(struct cfw_state *ps, int cfg) -{ - int ret; - - aic3xxx_cfw_lock(ps, 1); - ret = aic3xxx_cfw_setcfg_u(ps, cfg); - aic3xxx_cfw_lock(ps, 0); - return ret; -} - -static int aic3xxx_cfw_setcfg_u(struct cfw_state *ps, int cfg) -{ - struct cfw_project *pjt = ps->pjt; - struct cfw_pfw *pfw; - - if (pjt == NULL) - return -1; - if (ps->cur_pfw < 0 || ps->cur_pfw >= pjt->npfw) - return -1; - if (ps->cur_cfg == cfg) - return 0; - pfw = pjt->pfw[ps->cur_pfw]; - if (pfw->ncfg == 0 && cfg != 0) - return -1; - if (cfg > 0 && cfg >= pfw->ncfg) - return -1; - ps->cur_cfg = cfg; - aic3xxx_cfw_set_mode_id(ps); - if (pfw->ncfg != 0) - return aic3xxx_cfw_dlcfg(ps, - pfw->ovly_cfg[ps->cur_ovly][ps-> - cur_cfg]); - return 0; -} - -int aic3xxx_cfw_setmode_cfg(struct cfw_state *ps, int mode, int cfg) -{ - int ret; - - aic3xxx_cfw_lock(ps, 1); - ret = aic3xxx_cfw_setmode_cfg_u(ps, mode, cfg); - aic3xxx_cfw_lock(ps, 0); - return ret; -} - -static int aic3xxx_cfw_setmode_cfg_u(struct cfw_state *ps, int mode, int cfg) -{ - struct cfw_project *pjt = ps->pjt; - int which = 0; - struct cfw_pfw *pfw; - struct cfw_image *im; - - if (pjt == NULL) - return -1; - if ((mode < 0) || (mode >= pjt->nmode)) - return -1; - if (cfg < 0) - return -1; - if (mode == ps->cur_mode) - return aic3xxx_cfw_setcfg_u(ps, cfg); - - /* Apply exit sequence for previous mode if present */ - if (ps->cur_mode >= 0 && pjt->mode[ps->cur_mode]->exit) - aic3xxx_cfw_dlcmds(ps, pjt->mode[ps->cur_mode]->exit); - - if (pjt->mode[mode]->pfw < pjt->npfw) { - /* New mode uses miniDSP */ - pfw = pjt->pfw[pjt->mode[mode]->pfw]; - /* Make sure cfg is valid and supported in this mode */ - if (pfw->ncfg == 0 && cfg != 0) - return -1; - if (cfg > 0 && cfg >= pfw->ncfg) - return -1; - /* - * Decisions about which miniDSP to stop/restart are taken - * on the basis of sections present in the _base_ image - * This allows for correct sync mode operation even in cases - * where the base PFW uses both miniDSPs where a particular - * overlay applies only to one - */ - im = pfw->base; - if (im->block[CFW_BLOCK_A_INST]) - which |= AIC3XX_COPS_MDSP_A; - if (im->block[CFW_BLOCK_D_INST]) - which |= AIC3XX_COPS_MDSP_D; - - /* New mode requires different PFW */ - if (pjt->mode[mode]->pfw != ps->cur_pfw) { - ps->cur_pfw = pjt->mode[mode]->pfw; - ps->cur_ovly = 0; - ps->cur_cfg = 0; - - which = ps->ops->stop(ps->ops_obj, which); - aic3xxx_cfw_dlimage(ps, im); - if (pjt->mode[mode]->ovly - && pjt->mode[mode]->ovly < pfw->novly) { - /* New mode uses ovly */ - if (pfw->ovly_cfg[pjt->mode[mode] - ->ovly][cfg] != NULL) - aic3xxx_cfw_dlimage(ps, - pfw->ovly_cfg[pjt-> - mode[mode]-> - ovly][cfg]); - } else if (pfw->ncfg > 0) { - /* new mode needs only a cfg change */ - aic3xxx_cfw_dlimage(ps, pfw->ovly_cfg[0][cfg]); - } - ps->ops->restore(ps->ops_obj, which); - - } else if (pjt->mode[mode]->ovly != ps->cur_ovly) { - /* New mode requires only an ovly change */ - which = ps->ops->stop(ps->ops_obj, which); - aic3xxx_cfw_dlimage(ps, - pfw->ovly_cfg[pjt->mode[mode]-> - ovly][cfg]); - ps->ops->restore(ps->ops_obj, which); - } else if (pfw->ncfg > 0 && cfg != ps->cur_cfg) { - /* New mode requires only a cfg change */ - aic3xxx_cfw_dlcfg(ps, - pfw->ovly_cfg[pjt->mode[mode]-> - ovly][cfg]); - } - ps->cur_ovly = pjt->mode[mode]->ovly; - ps->cur_cfg = cfg; - - ps->cur_mode = mode; - aic3xxx_cfw_set_pll_u(ps, 0); - - } else if (pjt->mode[mode]->pfw != 0xFF) { - warn("Bad pfw setting detected (%d). Max pfw=%d", - pjt->mode[mode]->pfw, pjt->npfw); - } - ps->cur_mode = mode; - aic3xxx_cfw_set_mode_id(ps); - /* Transition to netural mode */ - aic3xxx_cfw_transition_u(ps, "NEUTRAL"); - /* Apply entry sequence if present */ - if (pjt->mode[mode]->entry) - aic3xxx_cfw_dlcmds(ps, pjt->mode[mode]->entry); - DBG("setmode_cfg: DONE (mode=%d pfw=%d ovly=%d cfg=%d)", ps->cur_mode, - ps->cur_pfw, ps->cur_ovly, ps->cur_cfg); - return 0; -} - -int aic3xxx_cfw_transition(struct cfw_state *ps, char *ttype) -{ - int ret; - - aic3xxx_cfw_lock(ps, 1); - ret = aic3xxx_cfw_transition_u(ps, ttype); - aic3xxx_cfw_lock(ps, 0); - return ret; -} - -static int aic3xxx_cfw_transition_u(struct cfw_state *ps, char *ttype) -{ - int i; - - if (ps->pjt == NULL) - return -1; - for (i = 0; i < CFW_TRN_N; ++i) { - if (!strcasecmp(ttype, cfw_transition_id[i])) { - DBG("Sending transition %s[%d]", ttype, i); - if (ps->pjt->transition[i]) { - aic3xxx_cfw_dlcmds(ps, - ps->pjt->transition[i]-> - block); - } - return 0; - } - } - warn("Transition %s not present or invalid", ttype); - return 0; -} - -int aic3xxx_cfw_set_pll(struct cfw_state *ps, int asi) -{ - int ret; - - aic3xxx_cfw_lock(ps, 1); - ret = aic3xxx_cfw_set_pll_u(ps, asi); - aic3xxx_cfw_lock(ps, 0); - return ret; -} - -static int aic3xxx_cfw_set_pll_u(struct cfw_state *ps, int asi) -{ - struct cfw_project *pjt = ps->pjt; - struct cfw_pfw *pfw; - - if (pjt == NULL) - return -1; - if (ps->cur_mode < 0) - return -EINVAL; - pfw = pjt->pfw[pjt->mode[ps->cur_mode]->pfw]; - if (pfw->pll) { - DBG("Configuring PLL for ASI%d using PFW%d", asi, - pjt->mode[ps->cur_mode]->pfw); - aic3xxx_cfw_dlcmds(ps, pfw->pll); - } - return 0; -} - -int aic3xxx_cfw_control(struct cfw_state *ps, char *cname, int param) -{ - int ret; - - aic3xxx_cfw_lock(ps, 1); - ret = aic3xxx_cfw_control_u(ps, cname, param); - aic3xxx_cfw_lock(ps, 0); - return ret; -} - -static int aic3xxx_cfw_control_u(struct cfw_state *ps, char *cname, int param) -{ - struct cfw_pfw *pfw; - int i; - - if (ps->cur_pfw < 0 || ps->cur_pfw >= ps->pjt->npfw) { - warn("Not in MiniDSP mode"); - return 0; - } - pfw = ps->pjt->pfw[ps->cur_pfw]; - for (i = 0; i < pfw->nctrl; ++i) { - if (!strcasecmp(cname, pfw->ctrl[i]->name)) { - struct cfw_control *pc = pfw->ctrl[i]; - if (param < 0 || param > pc->imax) { - warn("Parameter out of range\n"); - return -EINVAL; - } - DBG("Sending control %s[%d]", cname, param); - pc->icur = param; - aic3xxx_cfw_dlctl(ps, pc->output[param], - pc->mute_flags); - return 0; - } - } - warn("Control named %s nort found in pfw %s", cname, pfw->name); - - return 0; -} - -static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb) -{ - int i = 0, lock = 0; - - while (i < pb->ncmds) { - if (CFW_BLOCK_BURSTS(pb->type)) - ps->ops->bulk_write(ps->ops_obj, - pb->cmd[i].burst->reg.bpod, - pb->cmd[i].burst->length, - pb->cmd[i].burst->data); - else { - struct cfw_meta_delay d = pb->cmd[i].reg.meta.delay; - struct cfw_meta_bitop b = pb->cmd[i].reg.meta.bitop; - switch (pb->cmd[i].reg.meta.mcmd) { - case CFW_META_DELAY: - mdelay(d.delay); - break; - case CFW_META_UPDTBITS: - ps->ops->set_bits(ps->ops_obj, - pb->cmd[i + 1].reg.bpod, - b.mask, - pb->cmd[i + 1].reg.data); - i++; - break; - case CFW_META_WAITBITS: - aic3xxx_wait(ps, pb->cmd[i + 1].reg.bpod, - b.mask, pb->cmd[i + 1].reg.data); - i++; - break; - case CFW_META_LOCK: - if (d.delay) { - ps->ops->lock(ps->ops_obj); - lock = 1; - } else { - if (!lock) - error("already lock\n"); - ps->ops->unlock(ps->ops_obj); - lock = 0; - } - break; - default: - ps->ops->reg_write(ps->ops_obj, - pb->cmd[i].reg.bpod, - pb->cmd[i].reg.data); - } - } - ++i; - } - if (lock) - error("exiting blkcmds with lock ON"); -} - -static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask, - u8 data) -{ - while ((ps->ops->reg_read(ps->ops_obj, reg) & mask) != data) - mdelay(2); -} - -static const struct { - u32 mdsp; - int buf_a, buf_b; - u32 swap; -} csecs[] = { - { - .mdsp = AIC3XX_COPS_MDSP_A, - .swap = AIC3XX_ABUF_MDSP_A, - .buf_a = CFW_BLOCK_A_A_COEF, - .buf_b = CFW_BLOCK_A_B_COEF - }, - { - .mdsp = AIC3XX_COPS_MDSP_D, - .swap = AIC3XX_ABUF_MDSP_D1, - .buf_a = CFW_BLOCK_D_A1_COEF, - .buf_b = CFW_BLOCK_D_B1_COEF - }, - { - .mdsp = AIC3XX_COPS_MDSP_D, - .swap = AIC3XX_ABUF_MDSP_D2, - .buf_a = CFW_BLOCK_D_A2_COEF, - .buf_b = CFW_BLOCK_D_B2_COEF - }, -}; - -static int aic3xxx_cfw_dlctl(struct cfw_state *ps, struct cfw_block *pb, - u32 mute_flags) -{ - int i, btype = CFW_BLOCK_TYPE(pb->type); - int run_state = ps->ops->lock(ps->ops_obj); - - DBG("Download CTL"); - for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) { - if (csecs[i].buf_a == btype || csecs[i].buf_b == btype) { - DBG("\tDownload once to %d", btype); - aic3xxx_cfw_dlcmds(ps, pb); - if (run_state & csecs[i].mdsp) { - DBG("Download again %d", btype); - aic3xxx_cfw_mute(ps, 1, run_state & mute_flags); - ps->ops->bswap(ps->ops_obj, csecs[i].swap); - aic3xxx_cfw_mute(ps, 0, run_state & mute_flags); - aic3xxx_cfw_dlcmds(ps, pb); - } - break; - } - } - ps->ops->unlock(ps->ops_obj); - return 0; -} - -static int aic3xxx_cfw_dlcfg(struct cfw_state *ps, struct cfw_image *pim) -{ - int i, run_state, swap; - - DBG("Download CFG %s", pim->name); - run_state = ps->ops->lock(ps->ops_obj); - swap = 0; - for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) { - if (pim->block[csecs[i].buf_a]) { - if (run_state & csecs[i].mdsp) { - aic3xxx_cfw_dlcmds(ps, - pim->block[csecs[i].buf_a]); - swap |= csecs[i].swap; - } else { - aic3xxx_cfw_dlcmds(ps, - pim->block[csecs[i].buf_a]); - aic3xxx_cfw_dlcmds(ps, - pim->block[csecs[i].buf_b]); - } - } - } - if (swap) { - aic3xxx_cfw_mute(ps, 1, run_state & pim->mute_flags); - ps->ops->bswap(ps->ops_obj, swap); - aic3xxx_cfw_mute(ps, 0, run_state & pim->mute_flags); - for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) { - if (pim->block[csecs[i].buf_a]) { - if (run_state & csecs[i].mdsp) - aic3xxx_cfw_dlcmds(ps, - pim->block[csecs[i]. - buf_a]); - } - } - } - ps->ops->unlock(ps->ops_obj); - return 0; -} - -static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim) -{ - int i; - - DBG("Download IMAGE %s", pim->name); - for (i = 0; i < CFW_BLOCK_N; ++i) - if (pim->block[i]) - aic3xxx_cfw_dlcmds(ps, pim->block[i]); - return 0; -} - -static int aic3xxx_cfw_mute(struct cfw_state *ps, int mute, u32 flags) -{ - if ((flags & AIC3XX_COPS_MDSP_D) && (flags & AIC3XX_COPS_MDSP_A)) - aic3xxx_cfw_transition_u(ps, mute ? "AD_MUTE" : "AD_UNMUTE"); - else if (flags & AIC3XX_COPS_MDSP_D) - aic3xxx_cfw_transition_u(ps, mute ? "D_MUTE" : "D_UNMUTE"); - else if (flags & AIC3XX_COPS_MDSP_A) - aic3xxx_cfw_transition_u(ps, mute ? "A_MUTE" : "A_UNMUTE"); - return 0; -} - -#define FW_NDX2PTR(x, b) do { \ -x = (void *)((u8 *)(b) + ((int)(x))); \ -} while (0) - -static void aic3xxx_cfw_unpickle_block(struct cfw_block *pb, void *p) -{ - int i; - - if (CFW_BLOCK_BURSTS(pb->type)) - for (i = 0; i < pb->ncmds; ++i) - FW_NDX2PTR(pb->cmd[i].burst, p); -} - -static void aic3xxx_cfw_unpickle_image(struct cfw_image *im, void *p) -{ - int i; - for (i = 0; i < CFW_BLOCK_N; ++i) - if (im->block[i]) { - FW_NDX2PTR(im->block[i], p); - aic3xxx_cfw_unpickle_block(im->block[i], p); - } -} - -static void aic3xxx_cfw_unpickle_control(struct cfw_control *ct, void *p) -{ - int i; - FW_NDX2PTR(ct->output, p); - for (i = 0; i <= ct->imax; ++i) { - FW_NDX2PTR(ct->output[i], p); - aic3xxx_cfw_unpickle_block(ct->output[i], p); - } -} -#ifndef AIC3XXX_CFW_HOST_BLD -static -#endif -unsigned int crc32(unsigned int *pdata, int n) -{ - u32 crc = 0, i, crc_poly = 0x04C11DB7; /* CRC - 32 */ - u32 msb; - u32 residue_value = 0; - int bits; - - for (i = 0; i < (n >> 2); i++) { - bits = 32; - while (--bits >= 0) { - msb = crc & 0x80000000; - crc = (crc << 1) ^ ((*pdata >> bits) & 1); - if (msb) - crc = crc ^ crc_poly; - } - pdata++; - } - - switch (n & 3) { - case 0: - break; - case 1: - residue_value = (*pdata & 0xFF); - bits = 8; - break; - case 2: - residue_value = (*pdata & 0xFFFF); - bits = 16; - break; - case 3: - residue_value = (*pdata & 0xFFFFFF); - bits = 24; - break; - } - - if (n & 3) { - while (--bits >= 0) { - msb = crc & 0x80000000; - crc = (crc << 1) ^ ((residue_value >> bits) & 1); - if (msb) - crc = crc ^ crc_poly; - } - } - return crc; -} - -static int crc_chk(void *p, int n) -{ - struct cfw_project *pjt = (void *)p; - u32 crc = pjt->cksum, crc_comp; - - pjt->cksum = 0; - DBG("Entering crc %d", n); - crc_comp = crc32(p, n); - if (crc_comp != crc) { - DBG("CRC mismatch 0x%08X != 0x%08X", crc, crc_comp); - return 0; - } - DBG("CRC pass"); - pjt->cksum = crc; - return 1; -} -#ifndef AIC3XXX_CFW_HOST_BLD -static -#endif -struct cfw_project *aic3xxx_cfw_unpickle(void *p, int n) -{ - struct cfw_project *pjt = p; - int i, j, k; - - if (pjt->magic != CFW_FW_MAGIC || - pjt->size != n || pjt->bmagic != CFW_FW_VERSION || - !crc_chk(p, n)) { - error - ("magic:0x%08X!=0x%08X || size:%d!=%d ||version:0x%08X!=0x%08X", - pjt->magic, CFW_FW_MAGIC, pjt->size, n, pjt->cksum, - CFW_FW_VERSION); - - return NULL; - } - DBG("Loaded firmware inside unpickle\n"); - - for (i = 0; i < CFW_MAX_TRANSITIONS; i++) { - if (pjt->transition[i]) { - FW_NDX2PTR(pjt->transition[i], p); - FW_NDX2PTR(pjt->transition[i]->block, p); - aic3xxx_cfw_unpickle_block(pjt->transition[i]->block, - p); - } - } - - for (i = 0; i < pjt->npfw; i++) { - DBG("loading pfw %d\n", i); - FW_NDX2PTR(pjt->pfw[i], p); - if (pjt->pfw[i]->base) { - FW_NDX2PTR(pjt->pfw[i]->base, p); - aic3xxx_cfw_unpickle_image(pjt->pfw[i]->base, p); - } - if (pjt->pfw[i]->pll) { - FW_NDX2PTR(pjt->pfw[i]->pll, p); - aic3xxx_cfw_unpickle_block(pjt->pfw[i]->pll, p); - } - for (j = 0; j < pjt->pfw[i]->novly; ++j) - for (k = 0; k < pjt->pfw[i]->ncfg; ++k) { - FW_NDX2PTR(pjt->pfw[i]->ovly_cfg[j][k], p); - aic3xxx_cfw_unpickle_image(pjt->pfw[i]-> - ovly_cfg[j][k], p); - } - for (j = 0; j < pjt->pfw[i]->nctrl; ++j) { - FW_NDX2PTR(pjt->pfw[i]->ctrl[j], p); - aic3xxx_cfw_unpickle_control(pjt->pfw[i]->ctrl[j], p); - } - } - - DBG("loaded pfw's\n"); - for (i = 0; i < pjt->nmode; i++) { - FW_NDX2PTR(pjt->mode[i], p); - if (pjt->mode[i]->entry) { - FW_NDX2PTR(pjt->mode[i]->entry, p); - aic3xxx_cfw_unpickle_block(pjt->mode[i]->entry, p); - } - if (pjt->mode[i]->exit) { - FW_NDX2PTR(pjt->mode[i]->exit, p); - aic3xxx_cfw_unpickle_block(pjt->mode[i]->exit, p); - } - } - if (pjt->asoc_toc) - FW_NDX2PTR(pjt->asoc_toc, p); - else { - warn("asoc_toc not defined. FW version mismatch?"); - return NULL; - } - DBG("loaded modes"); - return pjt; -} - -#ifndef AIC3XXX_CFW_HOST_BLD -static int aic3xxx_get_control(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct cfw_state *ps = - (struct cfw_state *) kcontrol->private_value; - struct cfw_pfw *pfw; - int i; - - if (ps->cur_pfw >= ps->pjt->npfw) { - DBG("Not in MiniDSP mode"); - return 0; - } - pfw = ps->pjt->pfw[ps->cur_pfw]; - for (i = 0; i < pfw->nctrl; ++i) { - if (!strcasecmp(kcontrol->id.name, pfw->ctrl[i]->name)) { - struct cfw_control *pc = pfw->ctrl[i]; - ucontrol->value.integer.value[0] = pc->icur; - return 0; - } - } - return 0; -} - -static int aic3xxx_put_control(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct cfw_state *ps = - (struct cfw_state *) kcontrol->private_value; - - aic3xxx_cfw_control(ps, kcontrol->id.name, - ucontrol->value.integer.value[0]); - return 0; -} - -static int aic3xxx_info_control(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *ucontrol) -{ - struct cfw_state *ps = - (struct cfw_state *) kcontrol->private_value; - struct cfw_pfw *pfw; - int i; - - if (ps->cur_pfw >= ps->pjt->npfw) { - DBG("Not in MiniDSP mode"); - return 0; - } - pfw = ps->pjt->pfw[ps->cur_pfw]; - for (i = 0; i < pfw->nctrl; ++i) { - if (!strcasecmp(kcontrol->id.name, pfw->ctrl[i]->name)) { - struct cfw_control *pc = pfw->ctrl[i]; - ucontrol->value.integer.min = 0; - ucontrol->value.integer.max = pc->imax; - if (pc->imax == 1) - ucontrol->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - else - ucontrol->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - } - } - - ucontrol->count = 1; - return 0; -} -#endif -int aic3xxx_cfw_add_controls(struct snd_soc_codec *codec, struct cfw_state *ps) -{ - int i, j; - struct cfw_pfw *pfw; - - for (j = 0; j < ps->pjt->npfw; ++j) { - pfw = ps->pjt->pfw[j]; - - for (i = 0; i < pfw->nctrl; ++i) { - struct cfw_control *pc = pfw->ctrl[i]; -#ifndef AIC3XXX_CFW_HOST_BLD - struct snd_kcontrol_new *generic_control = - kzalloc(sizeof(struct snd_kcontrol_new), - GFP_KERNEL); - unsigned int *tlv_array = - kzalloc(4 * sizeof(unsigned int), GFP_KERNEL); - - if (generic_control == NULL) - return -ENOMEM; - generic_control->access = - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_READWRITE; - tlv_array[0] = SNDRV_CTL_TLVT_DB_SCALE; - tlv_array[1] = 2 * sizeof(unsigned int); - tlv_array[2] = pc->min; - tlv_array[3] = ((pc->step) & TLV_DB_SCALE_MASK); - if (pc->step > 0) - generic_control->tlv.p = tlv_array; - generic_control->name = pc->name; - generic_control->private_value = (unsigned long) ps; - generic_control->get = aic3xxx_get_control; - generic_control->put = aic3xxx_put_control; - generic_control->info = aic3xxx_info_control; - generic_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER; -#endif - DBG("Adding control %s", pc->name); -#ifndef AIC3XXX_CFW_HOST_BLD - snd_soc_add_codec_controls(codec, generic_control, 1); -#endif - } - } - return 0; - -} - -static int aic3xxx_cfw_set_mode_id(struct cfw_state *ps) -{ - struct cfw_asoc_toc *toc = ps->pjt->asoc_toc; - int i; - - for (i = 0; i < toc->nentries; ++i) { - if (toc->entry[i].cfg == ps->cur_cfg && - toc->entry[i].mode == ps->cur_mode) { - ps->cur_mode_id = i; - return 0; - } - } - DBG("Unknown mode, cfg combination [%d, %d]", - ps->cur_mode, ps->cur_cfg); - return -1; -} -#ifndef AIC3XXX_CFW_HOST_BLD -static int aic3xxx_get_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct cfw_state *ps = (struct cfw_state *)e->mask; - - ucontrol->value.enumerated.item[0] = ps->cur_mode_id; - - return 0; -} -#endif -#ifndef AIC3XXX_CFW_HOST_BLD -static int aic3xxx_put_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct cfw_state *ps = (struct cfw_state *)e->mask; - struct cfw_asoc_toc *toc; - int index, ret; - - aic3xxx_cfw_lock(ps, 1); - toc = ps->pjt->asoc_toc; - - index = ucontrol->value.enumerated.item[0]; - if (index < 0 || index >= toc->nentries) { - aic3xxx_cfw_lock(ps, 0); - return -EINVAL; - } - ret = - aic3xxx_cfw_setmode_cfg_u(ps, toc->entry[index].mode, - toc->entry[index].cfg); - aic3xxx_cfw_lock(ps, 0); - return ret; -} -#endif - -int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps) -{ -#ifndef AIC3XXX_CFW_HOST_BLD - int j; - struct cfw_asoc_toc *toc = ps->pjt->asoc_toc; - struct soc_enum *mode_cfg_enum = - kzalloc(sizeof(struct soc_enum), GFP_KERNEL); - struct snd_kcontrol_new *mode_cfg_control = - kzalloc(sizeof(struct snd_kcontrol_new), GFP_KERNEL); - char **enum_texts; - - if (mode_cfg_enum == NULL) - goto mem_err; - if (mode_cfg_control == NULL) - goto mem_err; - - mode_cfg_enum->texts = - kzalloc(toc->nentries * sizeof(char *), GFP_KERNEL); - if (mode_cfg_enum->texts == NULL) - goto mem_err; - /* Hack to overwrite the const * const pointer */ - enum_texts = (char **)mode_cfg_enum->texts; - - for (j = 0; j < toc->nentries; j++) - enum_texts[j] = toc->entry[j].etext; - mode_cfg_enum->reg = j; - mode_cfg_enum->max = toc->nentries; - mode_cfg_enum->mask = (unsigned int)ps; - mode_cfg_control->name = "Codec Firmware Setmode"; - mode_cfg_control->get = aic3xxx_get_mode; - mode_cfg_control->put = aic3xxx_put_mode; - mode_cfg_control->info = snd_soc_info_enum_ext; - mode_cfg_control->private_value = (unsigned long)mode_cfg_enum; - mode_cfg_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER; - snd_soc_add_codec_controls(codec, mode_cfg_control, 1); - return 0; -mem_err: - kfree(mode_cfg_control); - kfree(mode_cfg_enum); - kfree(mode_cfg_enum->texts); - return -ENOMEM; -#else - return 0; -#endif - -} |