From 3ec0b02088b6a46a0c29515b81ac05ed620721a0 Mon Sep 17 00:00:00 2001 From: Manoj Gangwal Date: Thu, 22 Nov 2012 11:42:15 +0530 Subject: asoc: aic326x codec: Add TI codec support Added support for TI aic326x codec for K3.4 Bug 1179798 Change-Id: Ib9efcf67c7b99cc9c7cfc1d6150aa587b88bd3cd Signed-off-by: Manoj Gangwal Reviewed-on: http://git-master/r/165611 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Vijay Mali Reviewed-by: Scott Peterson --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/Makefile | 3 +- sound/soc/codecs/aic3xxx/aic3xxx_cfw.h | 529 ++++++++++ sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.c | 1133 +++++++++++++++++++++ sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.h | 95 ++ sound/soc/codecs/aic3xxx_cfw.h | 427 -------- sound/soc/codecs/aic3xxx_cfw_ops.c | 918 ----------------- sound/soc/codecs/aic3xxx_cfw_ops.h | 76 -- sound/soc/codecs/tlv320aic326x.c | 1494 ++++++++++++++++------------ sound/soc/codecs/tlv320aic326x.h | 73 +- 10 files changed, 2633 insertions(+), 2116 deletions(-) create mode 100644 sound/soc/codecs/aic3xxx/aic3xxx_cfw.h create mode 100644 sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.c create mode 100644 sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.h delete mode 100644 sound/soc/codecs/aic3xxx_cfw.h delete mode 100644 sound/soc/codecs/aic3xxx_cfw_ops.c delete mode 100644 sound/soc/codecs/aic3xxx_cfw_ops.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a6d57cbe9bfb..21ab9a33056a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -277,6 +277,7 @@ config SND_SOC_TLV320AIC32X4 config SND_SOC_TLV320AIC3X tristate +# TI TLV320AIC3262 codec config SND_SOC_TLV320AIC326X select AIC3262_CODEC tristate "TI AIC326x Codec" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index e2dcaad1dcc4..da16bac15044 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -43,8 +43,7 @@ snd-soc-stac9766-objs := stac9766.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o -snd-soc-tlv320aic326x-objs := tlv320aic326x.o aic3xxx_cfw_ops.o -snd-soc-tlv320aic326x-objs += aic3262_codec_ops.o aic326x_tiload.o +snd-soc-tlv320aic326x-objs := tlv320aic326x.o aic3xxx/aic3xxx_cfw_ops.o snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o snd-soc-tlv320dac33-objs := tlv320dac33.o snd-soc-twl4030-objs := twl4030.o diff --git a/sound/soc/codecs/aic3xxx/aic3xxx_cfw.h b/sound/soc/codecs/aic3xxx/aic3xxx_cfw.h new file mode 100644 index 000000000000..2012d510f808 --- /dev/null +++ b/sound/soc/codecs/aic3xxx/aic3xxx_cfw.h @@ -0,0 +1,529 @@ +/* + * aic3xxx_cfw.h -- SoC audio for TI OMAP44XX SDP + * Codec Firmware Declarations + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef CFW_FIRMWARE_H_ +#define CFW_FIRMWARE_H_ + + +#define CFW_FW_MAGIC 0xC0D1F1ED + + +/** \defgroup pd Arbitrary Limitations */ +/* @{ */ +#ifndef CFW_MAX_ID +# define CFW_MAX_ID (64) /**= CFW_CMD_DELAY) + +/** + * CFW Block Type + * + * Block identifier + * + */ +enum __attribute__ ((__packed__)) cfw_block_t { + CFW_BLOCK_SYSTEM_PRE, + CFW_BLOCK_A_INST, + CFW_BLOCK_A_A_COEF, + CFW_BLOCK_A_B_COEF, + CFW_BLOCK_A_F_COEF, + CFW_BLOCK_D_INST, + CFW_BLOCK_D_A1_COEF, + CFW_BLOCK_D_B1_COEF, + CFW_BLOCK_D_A2_COEF, + CFW_BLOCK_D_B2_COEF, + CFW_BLOCK_D_F_COEF, + CFW_BLOCK_SYSTEM_POST, + CFW_BLOCK_N, + CFW_BLOCK_INVALID, +}; +#define CFW_BLOCK_D_A_COEF CFW_BLOCK_D_A1_COEF +#define CFW_BLOCK_D_B_COEF CFW_BLOCK_D_B1_COEF + +/** + * CFW Block + * + * A block of logically grouped sequences/commands/cmd-commands + * + */ +struct cfw_block { + enum cfw_block_t type; + int ncmds; + union cfw_cmd cmd[]; +}; +#define CFW_BLOCK_SIZE(ncmds) (sizeof(struct cfw_block) + \ + ((ncmds)*sizeof(union cfw_cmd))) + +/** + * CFW Image + * + * A downloadable image + */ +struct cfw_image { + char name[CFW_MAX_ID]; /**< Name of the pfw/overlay/configuration*/ + char *desc; /**< User string*/ + int mute_flags; + struct cfw_block *block[CFW_BLOCK_N]; +}; + + + +/** + * CFW PLL + * + * PLL configuration sequence and match critirea + */ +struct cfw_pll { + char name[CFW_MAX_ID]; /**< Name of the PLL sequence*/ + char *desc; /**< User string*/ + struct cfw_block *seq; +}; + +/** + * CFW Control + * + * Run-time control for a process flow + */ +struct cfw_control { + char name[CFW_MAX_ID]; /**< Control identifier*/ + char *desc; /**< User string*/ + int mute_flags; + + int min; /**< Min value of control (*100)*/ + int max; /**< Max value of control (*100)*/ + int step; /**< Control step size (*100)*/ + + int imax; /**< Max index into controls array*/ + int ireset; /**< Reset control to defaults*/ + int icur; /**< Last value set*/ + struct cfw_block **output; /**< Array of sequences to send*/ +}; + +/** + * Process flow + * + * Complete description of a process flow + */ +struct cfw_pfw { + char name[CFW_MAX_ID]; /**< Name of the process flow*/ + char *desc; /**< User string*/ + u32 version; + u8 prb_a; + u8 prb_d; + int novly; /**< Number of overlays (1 or more)*/ + int ncfg; /**< Number of configurations (0 or more)*/ + int nctrl; /**< Number of run-time controls*/ + struct cfw_image *base; /**< Base sequence*/ + struct cfw_image **ovly_cfg; /**< Overlay and cfg*/ + /**< patches (if any)*/ + struct cfw_control **ctrl; /**< Array of run-time controls*/ +}; + +#define CFW_OCFG_NDX(p, o, c) (((o)*(p)->ncfg)+(c)) +/** + * Process transition + * + * Sequence for specific state transisitions within the driver + * + */ +struct cfw_transition { + char name[CFW_MAX_ID]; /**< Name of the transition*/ + char *desc; /**< User string*/ + struct cfw_block *block; +}; + +/** + * Device audio mode + * + * Link operating modes to process flows, + * configurations and sequences + * + */ +struct cfw_mode { + char name[CFW_MAX_ID]; + char *desc; /**< User string*/ + u32 flags; + u8 pfw; + u8 ovly; + u8 cfg; + u8 pll; + struct cfw_block *entry; + struct cfw_block *exit; +}; + +struct cfw_asoc_toc_entry { + char etext[CFW_MAX_ID]; + int mode; + int cfg; +}; + +struct cfw_asoc_toc { + int nentries; + struct cfw_asoc_toc_entry entry[]; +}; + +/** + * CFW Project + * + * Top level structure describing the CFW project + */ +struct cfw_project { + u32 magic; /**< magic number for identifying F/W file*/ + u32 if_id; /**< Interface match code */ + u32 size; /**< Total size of the firmware (including this header)*/ + u32 cksum; /**< CRC32 of the pickled firmware */ + u32 version; /**< Firmware version (from CFD file)*/ + u32 tstamp; /**< Time stamp of firmware build (epoch seconds)*/ + char name[CFW_MAX_ID]; /**< Project name*/ + char *desc; /**< User string*/ + enum cfw_dfamily dfamily; /**< Device family*/ + enum cfw_device device; /**< Device identifier*/ + u32 flags; /**< CFW flags*/ + + struct cfw_transition **transition; /**< Transition sequences*/ + + u16 npll; /**< Number of PLL settings*/ + struct cfw_pll **pll; /**< PLL settings*/ + + u16 npfw; /**< Number of process flows*/ + struct cfw_pfw **pfw; /**< Process flows*/ + + u16 nmode; /**< Number of operating modes*/ + struct cfw_mode **mode; /**< Modes*/ + + struct cfw_asoc_toc *asoc_toc; /**< list of amixer controls*/ +}; + + +/* @} */ + +/* **CFW_INTERFACE_ID=0x3FA6D547** */ + +#endif /* CFW_FIRMWARE_H_ */ diff --git a/sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.c b/sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.c new file mode 100644 index 000000000000..83c6b4843576 --- /dev/null +++ b/sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.c @@ -0,0 +1,1133 @@ +/* + * linux/sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.c + * + * Copyright (C) 2011 Texas Instruments Inc., + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* FIXME to be removed/replaced */ +#define warn(fmt, ...) printk(fmt "\n", ##__VA_ARGS__) +#define error(fmt, ...) printk(fmt "\n", ##__VA_ARGS__) +#define DBG printk + +#include "aic3xxx_cfw.h" +#include "aic3xxx_cfw_ops.h" + + +/* **Code beyond this point is compilable on host** */ + +/* + * 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. + */ +#undef CFW_FW_IF_ID +#define CFW_FW_IF_ID 0x3FA6D547 +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 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); +static struct cfw_project *aic3xxx_cfw_unpickle(void *pcfw, int n); + +static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask, + u8 data); +static void aic3xxx_set_bits(u8 *data, u8 mask, u8 val); +static int aic3xxx_driver_init(struct cfw_state *ps); + +int aic3xxx_cfw_init(struct cfw_state *ps, const struct aic3xxx_codec_ops *ops, + struct snd_soc_codec *codec) +{ + ps->ops = ops; + ps->codec = codec; + ps->pjt = NULL; + mutex_init(&ps->mutex); + + /* FIXME Need a special CONFIG flag to disable debug driver */ + aic3xxx_driver_init(ps); + 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_pll = 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; + struct cfw_image *patch; + + if (pjt == NULL) + return -1; + if (ps->cur_pfw < 0 || ps->cur_pfw >= pjt->npfw) + return -1; /* Non miniDSP */ + 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); + patch = + pfw->ovly_cfg[CFW_OCFG_NDX(pfw, ps->cur_ovly, ps->cur_cfg)]; + if (pfw->ncfg != 0) + return aic3xxx_cfw_dlcfg(ps, patch); + 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; + struct cfw_mode *pmode; + int which = 0, ocndx; + + if (pjt == NULL) + goto err; + if ((mode < 0) || (mode >= pjt->nmode)) + goto err; + if (cfg < 0) + goto err; + 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) + aic3xxx_cfw_dlcmds(ps, pjt->mode[ps->cur_mode]->exit); + pmode = pjt->mode[mode]; + if (pjt->mode[mode]->pfw < pjt->npfw) { /* New mode uses miniDSP */ + struct cfw_image *im; + struct cfw_pfw *pfw = pjt->pfw[pmode->pfw]; + + /* Make sure cfg is valid and supported in this mode */ + if (pfw->ncfg == 0 && cfg != 0) + goto err; + if (cfg > 0 && cfg >= pfw->ncfg) + goto err; + + /* + * 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 |= AIC3XXX_COPS_MDSP_A; + if (im->block[CFW_BLOCK_D_INST]) + which |= AIC3XXX_COPS_MDSP_D; + + if (pmode->pfw != ps->cur_pfw) { + + /* New mode requires different PFW */ + ps->cur_pfw = pmode->pfw; + ps->cur_ovly = 0; + ps->cur_cfg = 0; + + which = ps->ops->stop(ps->codec, which); + aic3xxx_cfw_dlimage(ps, im); + if (pmode->ovly && pmode->ovly < pfw->novly) { + + /* New mode uses ovly */ + ocndx = CFW_OCFG_NDX(pfw, pmode->ovly, cfg); + aic3xxx_cfw_dlimage(ps, + pfw->ovly_cfg[ocndx]); + } else if (pfw->ncfg > 0) { + + /* new mode needs only a cfg change */ + ocndx = CFW_OCFG_NDX(pfw, 0, cfg); + aic3xxx_cfw_dlimage(ps, + pfw->ovly_cfg[ocndx]); + } + ps->ops->restore(ps->codec, which); + + } else if (pmode->ovly != ps->cur_ovly) { + + /* New mode requires only an ovly change */ + ocndx = CFW_OCFG_NDX(pfw, pmode->ovly, cfg); + which = ps->ops->stop(ps->codec, which); + aic3xxx_cfw_dlimage(ps, pfw->ovly_cfg[ocndx]); + ps->ops->restore(ps->codec, which); + } else if (pfw->ncfg > 0 && cfg != ps->cur_cfg) { + + /* New mode requires only a cfg change */ + ocndx = CFW_OCFG_NDX(pfw, pmode->ovly, cfg); + aic3xxx_cfw_dlcfg(ps, pfw->ovly_cfg[ocndx]); + } + ps->cur_ovly = pmode->ovly; + ps->cur_cfg = cfg; + + ps->cur_mode = mode; + aic3xxx_cfw_set_pll_u(ps, 0); + + } else if (pjt->mode[mode]->pfw != 0xFF) { + + /* Not bypass mode */ + warn("Bad pfw setting detected (%d). Max pfw=%d", + pmode->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 */ + aic3xxx_cfw_dlcmds(ps, pmode->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; + +err: + DBG("Failed to set firmware mode"); + return -EINVAL; +} + +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 -EINVAL; + for (i = 0; i < CFW_TRN_N; ++i) { + if (!strcasecmp(ttype, cfw_transition_id[i])) { + struct cfw_transition *pt = ps->pjt->transition[i]; + DBG("Sending transition %s[%d]", ttype, i); + if (pt) + aic3xxx_cfw_dlcmds(ps, pt->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; + int pll_id; + + if (pjt == NULL) + return -EINVAL; + if (ps->cur_mode < 0) + return -EINVAL; + pll_id = pjt->mode[ps->cur_mode]->pll; + if (ps->cur_pll != pll_id) { + DBG("Re-configuring PLL: %s==>%d", pjt->pll[pll_id]->name, + pll_id); + aic3xxx_cfw_dlcmds(ps, pjt->pll[pll_id]->seq); + ps->cur_pll = pll_id; + } + 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) { + struct cfw_control *pc = pfw->ctrl[i]; + if (strcasecmp(cname, pfw->ctrl[i]->name)) + continue; + 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 not found in pfw %s", cname, pfw->name); + + return -EINVAL; +} + +static void aic3xxx_cfw_op(struct cfw_state *ps, unsigned char *var, + struct cfw_cmd_op cmd) +{ + u32 op1, op2; + u32 cid = cmd.cid; + + op1 = cmd.op1; + op2 = cmd.op2; + if (cid & CFW_CMD_OP1_ID) + op1 = var[op1]; + if (cid & CFW_CMD_OP2_ID) + op2 = var[op2]; + cid &= ~(CFW_CMD_OP1_ID | CFW_CMD_OP2_ID); + + switch (cid) { + case CFW_CMD_OP_ADD: + var[cmd.dst] = op1 + op2; + break; + case CFW_CMD_OP_SUB: + var[cmd.dst] = op1 - op2; + break; + case CFW_CMD_OP_MUL: + var[cmd.dst] = op1 * op2; + break; + case CFW_CMD_OP_DIV: + var[cmd.dst] = op1 / op2; + break; + case CFW_CMD_OP_AND: + var[cmd.dst] = op1 & op2; + break; + case CFW_CMD_OP_OR: + var[cmd.dst] = op1 | op2; + break; + case CFW_CMD_OP_SHL: + var[cmd.dst] = (op1 << op2); + break; + case CFW_CMD_OP_SHR: + var[cmd.dst] = (op1 >> op2); + break; + case CFW_CMD_OP_RR: + while (op2--) + var[cmd.dst] = (op1 >> 1) | ((op1 & 1) << 7); + break; + case CFW_CMD_OP_XOR: + var[cmd.dst] = op1 ^ op2; + break; + case CFW_CMD_OP_NOT: + var[cmd.dst] = ~op1; + break; + case CFW_CMD_OP_LNOT: + var[cmd.dst] = !op1; + break; + default: + break; + } +} + +static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb) +{ + int pc = 0, cond = 0; + unsigned char var[256]; + + if (!pb) + return; + while (pc < pb->ncmds) { + union cfw_cmd *c = &(pb->cmd[pc]); + if (c->cid != CFW_CMD_BRANCH_IM && + c->cid != CFW_CMD_BRANCH_ID && c->cid != CFW_CMD_NOP) + cond = 0; + switch (c->cid) { + case 0 ... (CFW_CMD_NOP - 1): + ps->ops->reg_write(ps->codec, c->reg.bpod, + c->reg.data); + pc += 1; + break; + case CFW_CMD_NOP: + pc += 1; + break; + case CFW_CMD_DELAY: + mdelay(c->delay.delay); + pc += 1; + break; + case CFW_CMD_UPDTBITS: + ps->ops->set_bits(ps->codec, c[1].reg.bpod, + c->bitop.mask, c[1].reg.data); + pc += 2; + break; + case CFW_CMD_WAITBITS: + aic3xxx_wait(ps, c[1].reg.bpod, c->bitop.mask, + c[1].reg.data); + pc += 2; + break; + case CFW_CMD_LOCK: + if (c->delay.delay) + ps->ops->lock(ps->codec); + else + ps->ops->unlock(ps->codec); + pc += 1; + break; + case CFW_CMD_BURST: + ps->ops->bulk_write(ps->codec, c[1].reg.bpod, + c->bhdr.len, c[1].burst.data); + pc += CFW_CMD_BURST_LEN(c->bhdr.len); + break; + case CFW_CMD_RBURST: + ps->ops->bulk_read(ps->codec, c[1].reg.bpod, + c->bhdr.len, c[1].burst.data); + pc += CFW_CMD_BURST_LEN(c->bhdr.len); + break; + case CFW_CMD_LOAD_VAR_IM: + aic3xxx_set_bits(&var[c->ldst.dvar], + c->ldst.mask, c->ldst.svar); + pc += 1; + break; + case CFW_CMD_LOAD_VAR_ID: + if (c->ldst.svar != c->ldst.dvar) { + aic3xxx_set_bits(&var[c->ldst.dvar], + c->ldst.mask, + var[c->ldst.svar]); + pc += 1; + } else { + u8 data; + data = ps->ops->reg_read(ps->codec, + c[1].reg.bpod); + aic3xxx_set_bits(&var[c->ldst.dvar], + c->ldst.mask, data); + pc += 2; + } + break; + case CFW_CMD_STORE_VAR: + if (c->ldst.svar != c->ldst.dvar) + ps->ops->set_bits(ps->codec, + c[1].reg.bpod, + var[c->ldst.dvar], + var[c->ldst.svar]); + else + ps->ops->set_bits(ps->codec, + c[1].reg.bpod, + c->ldst.mask, + var[c->ldst.svar]); + pc += 2; + break; + case CFW_CMD_COND: + cond = var[c->cond.svar] & c->cond.mask; + pc += 1; + break; + case CFW_CMD_BRANCH: + pc = c->branch.address; + break; + case CFW_CMD_BRANCH_IM: + if (c->branch.match == cond) + pc = c->branch.address; + else + pc += 1; + break; + case CFW_CMD_BRANCH_ID: + if (var[c->branch.match] == cond) + pc = c->branch.address; + else + pc += 1; + break; + case CFW_CMD_PRINT: + { + union cfw_cmd *parglist = + c + CFW_CMD_PRINT_ARG(c->print); + printk(c->print.fmt, + var[parglist->print_arg[0]], + var[parglist->print_arg[1]], + var[parglist->print_arg[2]], + var[parglist->print_arg[3]]); + pc += CFW_CMD_PRINT_LEN(c->print); + } + break; + case CFW_CMD_OP_START ... CFW_CMD_OP_END: + aic3xxx_cfw_op(ps, var, c->op); + pc += 1; + break; + default: + warn("Unknown cmd command %x. Skipped", c->cid); + pc += 1; + break; + } + } +} + +static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask, + u8 data) +{ + while ((ps->ops->reg_read(ps->codec, reg) & mask) != data) + mdelay(2); +} + +static void aic3xxx_set_bits(u8 *data, u8 mask, u8 val) +{ + *data = (*data & (~mask)) | (val & mask); +} + +static const struct { + u32 mdsp; + int buf_a, buf_b; + u32 swap; +} csecs[] = { + { + .mdsp = AIC3XXX_COPS_MDSP_A, + .swap = AIC3XXX_ABUF_MDSP_A, + .buf_a = CFW_BLOCK_A_A_COEF, + .buf_b = CFW_BLOCK_A_B_COEF + }, + { + .mdsp = AIC3XXX_COPS_MDSP_D, + .swap = AIC3XXX_ABUF_MDSP_D1, + .buf_a = CFW_BLOCK_D_A1_COEF, + .buf_b = CFW_BLOCK_D_B1_COEF + }, + { + .mdsp = AIC3XXX_COPS_MDSP_D, + .swap = AIC3XXX_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 = pb->type; + int run_state = ps->ops->lock(ps->codec); + + DBG("Download CTL"); + for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) { + if (csecs[i].buf_a != btype && csecs[i].buf_b != btype) + continue; + DBG("\tDownload once to %d", btype); + aic3xxx_cfw_dlcmds(ps, pb); + if (run_state & csecs[i].mdsp) { + DBG("\tDownload again to make sure it reaches B"); + aic3xxx_cfw_mute(ps, 1, run_state & mute_flags); + ps->ops->bswap(ps->codec, csecs[i].swap); + aic3xxx_cfw_mute(ps, 0, run_state & mute_flags); + aic3xxx_cfw_dlcmds(ps, pb); + } + break; + } + ps->ops->unlock(ps->codec); + 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->codec); + swap = 0; + for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) { + if (!pim->block[csecs[i].buf_a]) + continue; + aic3xxx_cfw_dlcmds(ps, pim->block[csecs[i].buf_a]); + aic3xxx_cfw_dlcmds(ps, pim->block[csecs[i].buf_b]); + if (run_state & csecs[i].mdsp) + swap |= csecs[i].swap; + } + if (swap) { + aic3xxx_cfw_mute(ps, 1, run_state & pim->mute_flags); + ps->ops->bswap(ps->codec, 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]) + continue; + if (!(run_state & csecs[i].mdsp)) + continue; + aic3xxx_cfw_dlcmds(ps, pim->block[csecs[i].buf_a]); + aic3xxx_cfw_dlcmds(ps, pim->block[csecs[i].buf_b]); + } + } + ps->ops->unlock(ps->codec); + return 0; +} + +static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim) +{ + int i; + + if (!pim) + return 0; + DBG("Download IMAGE %s", pim->name); + for (i = 0; i < CFW_BLOCK_N; ++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 & AIC3XXX_COPS_MDSP_D) && (flags & AIC3XXX_COPS_MDSP_A)) + aic3xxx_cfw_transition_u(ps, + mute ? "AD_MUTE" : "AD_UNMUTE"); + else if (flags & AIC3XXX_COPS_MDSP_D) + aic3xxx_cfw_transition_u(ps, mute ? "D_MUTE" : "D_UNMUTE"); + else if (flags & AIC3XXX_COPS_MDSP_A) + aic3xxx_cfw_transition_u(ps, mute ? "A_MUTE" : "A_UNMUTE"); + return 0; +} + +static inline void *aic3xxx_cfw_ndx2ptr(void *p, u8 *base) +{ + return &base[(int)p]; +} +static inline char *aic3xxx_cfw_desc(void *p, u8 *base) +{ + if (p) + return aic3xxx_cfw_ndx2ptr(p, base); + return NULL; +} + +static void aic3xxx_cfw_unpickle_image(struct cfw_image *im, void *p) +{ + int i; + + im->desc = aic3xxx_cfw_desc(im->desc, p); + for (i = 0; i < CFW_BLOCK_N; ++i) + if (im->block[i]) + im->block[i] = aic3xxx_cfw_ndx2ptr(im->block[i], p); +} + +static void aic3xxx_cfw_unpickle_control(struct cfw_control *ct, void *p) +{ + int i; + + ct->output = aic3xxx_cfw_ndx2ptr(ct->output, p); + ct->desc = aic3xxx_cfw_desc(ct->desc, p); + for (i = 0; i <= ct->imax; ++i) + ct->output[i] = aic3xxx_cfw_ndx2ptr(ct->output[i], p); +} + +static 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; +} + +static struct cfw_project *aic3xxx_cfw_unpickle(void *p, int n) +{ + struct cfw_project *pjt = p; + int i, j; + + if (pjt->magic != CFW_FW_MAGIC || pjt->size != n || + pjt->if_id != CFW_FW_IF_ID || !crc_chk(p, n)) { + error("Version mismatch: unable to load firmware\n"); + return NULL; + } + DBG("Loaded firmware inside unpickle\n"); + + pjt->desc = aic3xxx_cfw_desc(pjt->desc, p); + pjt->transition = aic3xxx_cfw_ndx2ptr(pjt->transition, p); + for (i = 0; i < CFW_TRN_N; i++) { + if (!pjt->transition[i]) + continue; + pjt->transition[i] = aic3xxx_cfw_ndx2ptr(pjt->transition[i], p); + pjt->transition[i]->desc = aic3xxx_cfw_desc( + pjt->transition[i]->desc, p); + pjt->transition[i]->block = aic3xxx_cfw_ndx2ptr( + pjt->transition[i]->block, p); + } + pjt->pll = aic3xxx_cfw_ndx2ptr(pjt->pll, p); + for (i = 0; i < pjt->npll; i++) { + pjt->pll[i] = aic3xxx_cfw_ndx2ptr(pjt->pll[i], p); + pjt->pll[i]->desc = aic3xxx_cfw_desc(pjt->pll[i]->desc, p); + pjt->pll[i]->seq = aic3xxx_cfw_ndx2ptr(pjt->pll[i]->seq, p); + } + + pjt->pfw = aic3xxx_cfw_ndx2ptr(pjt->pfw, p); + for (i = 0; i < pjt->npfw; i++) { + DBG("loading pfw %d\n", i); + pjt->pfw[i] = aic3xxx_cfw_ndx2ptr(pjt->pfw[i], p); + pjt->pfw[i]->desc = aic3xxx_cfw_desc(pjt->pfw[i]->desc, p); + if (pjt->pfw[i]->base) { + pjt->pfw[i]->base = aic3xxx_cfw_ndx2ptr( + pjt->pfw[i]->base, p); + aic3xxx_cfw_unpickle_image(pjt->pfw[i]->base, p); + } + pjt->pfw[i]->ovly_cfg = aic3xxx_cfw_ndx2ptr( + pjt->pfw[i]->ovly_cfg, p); + for (j = 0; j < pjt->pfw[i]->novly * pjt->pfw[i]->ncfg; ++j) { + pjt->pfw[i]->ovly_cfg[j] = aic3xxx_cfw_ndx2ptr( + pjt->pfw[i]->ovly_cfg[j], p); + aic3xxx_cfw_unpickle_image(pjt->pfw[i]->ovly_cfg[j], p); + } + if (pjt->pfw[i]->nctrl) + pjt->pfw[i]->ctrl = aic3xxx_cfw_ndx2ptr( + pjt->pfw[i]->ctrl, p); + for (j = 0; j < pjt->pfw[i]->nctrl; ++j) { + pjt->pfw[i]->ctrl[j] = aic3xxx_cfw_ndx2ptr( + pjt->pfw[i]->ctrl[j], p); + aic3xxx_cfw_unpickle_control(pjt->pfw[i]->ctrl[j], p); + } + } + + DBG("loaded pfw's\n"); + pjt->mode = aic3xxx_cfw_ndx2ptr(pjt->mode, p); + for (i = 0; i < pjt->nmode; i++) { + pjt->mode[i] = aic3xxx_cfw_ndx2ptr(pjt->mode[i], p); + pjt->mode[i]->desc = aic3xxx_cfw_desc(pjt->mode[i]->desc, p); + if (pjt->mode[i]->entry) + pjt->mode[i]->entry = aic3xxx_cfw_ndx2ptr( + pjt->mode[i]->entry, p); + if (pjt->mode[i]->exit) + pjt->mode[i]->exit = aic3xxx_cfw_ndx2ptr( + pjt->mode[i]->exit, p); + } + if (pjt->asoc_toc) + pjt->asoc_toc = aic3xxx_cfw_ndx2ptr(pjt->asoc_toc, p); + else { + warn("asoc_toc not defined. FW version mismatch?"); + return NULL; + } + DBG("loaded modes"); + return pjt; +} +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; +} + +/* **Code beyond this point is not compilable on host** */ + +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; +} +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]; + 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; + snd_soc_add_codec_controls(codec, generic_control, 1); + DBG("Added control %s", pc->name); + } + } + return 0; + +} + + +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; +} + +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; +} + +int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps) +{ + 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; + +} + +#if defined(CONFIG_AIC3111_CODEC) || defined(CONFIG_AIC3111_CORE) + +# define AIC3XXX_CFW_DEVICE "aic3111_cfw" +#elif defined(CONFIG_AIC3256_CODEC) || defined(CONFIG_AIC3256_CORE) + +# define AIC3XXX_CFW_DEVICE "aic3256_cfw" +#elif defined(CONFIG_AIC3262_CODEC) || defined(CONFIG_AIC3262_CORE) +# define AIC3XXX_CFW_DEVICE "aic3262_cfw" +#else +# define AIC3XXX_CFW_DEVICE "aic3xxx_cfw" +#endif + +static int aic3xxx_cfw_open(struct inode *in, struct file *filp) +{ + struct cfw_state *ps = container_of(in->i_cdev, struct cfw_state, cdev); + if (ps->is_open) { + warn("driver_open: device is already open"); + return -1; + } + ps->is_open++; + filp->private_data = ps; + return 0; +} +static int aic3xxx_cfw_release(struct inode *in, struct file *filp) +{ + struct cfw_state *ps = filp->private_data; + ps->is_open--; + return ps->is_open; +} +static long aic3xxx_cfw_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return 0; +} +static ssize_t aic3xxx_cfw_rw(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct cfw_state *ps = filp->private_data; + struct cfw_block *kbuf = kmalloc(count, GFP_KERNEL); + if (!kbuf || copy_from_user(kbuf, buf, count)) { + warn("dev_rw: Allocation or copy failure"); + goto err; + } + if (count != CFW_BLOCK_SIZE(kbuf->ncmds)) { + warn("dev_rw: Bad packet received\n"); + goto err; + } + aic3xxx_cfw_dlcmds(ps, kbuf); + if (copy_to_user(buf, kbuf, count)) { + warn("dev_rw: copy failure"); + goto err; + } + kfree(kbuf); + return count; +err: + kfree(kbuf); + return -EINVAL; +} + +static const struct file_operations aic3xxx_cfw_fops = { + .owner = THIS_MODULE, + .open = aic3xxx_cfw_open, + .release = aic3xxx_cfw_release, + .read = aic3xxx_cfw_rw, + .write = (ssize_t (*)(struct file *filp, const char __user *buf, + size_t count, loff_t *offset))aic3xxx_cfw_rw, + .unlocked_ioctl = aic3xxx_cfw_ioctl, +}; +static int aic3xxx_driver_init(struct cfw_state *ps) +{ + int err; + + dev_t dev = MKDEV(0, 0); + + err = alloc_chrdev_region(&dev, 0, 1, AIC3XXX_CFW_DEVICE); + if (err < 0) { + warn("driver_init: Error allocating device number"); + return err; + } + warn("driver_init: Allocated Major Number: %d\n", MAJOR(dev)); + + cdev_init(&(ps->cdev), &aic3xxx_cfw_fops); + ps->cdev.owner = THIS_MODULE; + ps->cdev.ops = &aic3xxx_cfw_fops; + ps->is_open = 0; + + err = cdev_add(&(ps->cdev), dev, 1); + if (err < 0) { + warn("driver_init: cdev_add failed"); + unregister_chrdev_region(dev, 1); + return err; + } + warn("driver_init: Registered cfw driver"); + return 0; +} + +MODULE_DESCRIPTION("ASoC tlv320aic3xxx codec driver firmware functions"); +MODULE_AUTHOR("Hari Rajagopala "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.h b/sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.h new file mode 100644 index 000000000000..fe5b63c1d940 --- /dev/null +++ b/sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.h @@ -0,0 +1,95 @@ +/* + * aic3xxx_cfw_ops.h -- SoC audio for TI OMAP44XX SDP + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef AIC3XXX_CFW_OPS_H_ +#define AIC3XXX_CFW_OPS_H_ + +#include +#include +#include + +struct cfw_project; +struct aic3xxx_codec_ops; + +struct cfw_state { + struct cfw_project *pjt; + const struct aic3xxx_codec_ops *ops; + struct snd_soc_codec *codec; + struct mutex mutex; + int cur_mode_id; + int cur_pll; + int cur_mode; + int cur_pfw; + int cur_ovly; + int cur_cfg; + struct cdev cdev; + int is_open; +}; + +int aic3xxx_cfw_init(struct cfw_state *ps, const struct aic3xxx_codec_ops *ops, + struct snd_soc_codec *codec); +int aic3xxx_cfw_lock(struct cfw_state *ps, int lock); +int aic3xxx_cfw_reload(struct cfw_state *ps, void *pcfw, int n); +int aic3xxx_cfw_setmode(struct cfw_state *ps, int mode); +int aic3xxx_cfw_setmode_cfg(struct cfw_state *ps, int mode, int cfg); +int aic3xxx_cfw_setcfg(struct cfw_state *ps, int cfg); +int aic3xxx_cfw_transition(struct cfw_state *ps, char *ttype); +int aic3xxx_cfw_set_pll(struct cfw_state *ps, int asi); +int aic3xxx_cfw_control(struct cfw_state *ps, char *cname, int param); +int aic3xxx_cfw_add_controls(struct snd_soc_codec *codec, struct cfw_state *ps); +int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps); + + +#define AIC3XXX_COPS_MDSP_D_L (0x00000002u) +#define AIC3XXX_COPS_MDSP_D_R (0x00000001u) +#define AIC3XXX_COPS_MDSP_D (AIC3XXX_COPS_MDSP_D_L|AIC3XXX_COPS_MDSP_D_R) + +#define AIC3XXX_COPS_MDSP_A_L (0x00000020u) +#define AIC3XXX_COPS_MDSP_A_R (0x00000010u) +#define AIC3XXX_COPS_MDSP_A (AIC3XXX_COPS_MDSP_A_L|AIC3XXX_COPS_MDSP_A_R) + +#define AIC3XXX_COPS_MDSP_ALL (AIC3XXX_COPS_MDSP_D|AIC3XXX_COPS_MDSP_A) + +#define AIC3XXX_ABUF_MDSP_D1 (0x00000001u) +#define AIC3XXX_ABUF_MDSP_D2 (0x00000002u) +#define AIC3XXX_ABUF_MDSP_A (0x00000010u) +#define AIC3XXX_ABUF_MDSP_ALL \ + (AIC3XXX_ABUF_MDSP_D1|AIC3XXX_ABUF_MDSP_D2|AIC3XXX_ABUF_MDSP_A) + + +struct aic3xxx_codec_ops { + int (*reg_read) (struct snd_soc_codec *codec, unsigned int reg); + int (*reg_write) (struct snd_soc_codec *codec, unsigned int reg, + unsigned char val); + int (*set_bits) (struct snd_soc_codec *codec, unsigned int reg, + unsigned char mask, unsigned char val); + int (*bulk_read) (struct snd_soc_codec *codec, unsigned int reg, + int count, u8 *buf); + int (*bulk_write) (struct snd_soc_codec *codec, unsigned int reg, + int count, const u8 *buf); + int (*lock) (struct snd_soc_codec *codec); + int (*unlock) (struct snd_soc_codec *codec); + int (*stop) (struct snd_soc_codec *codec, int mask); + int (*restore) (struct snd_soc_codec *codec, int runstate); + int (*bswap) (struct snd_soc_codec *codec, int mask); +}; + +MODULE_LICENSE("GPL"); + +#endif diff --git a/sound/soc/codecs/aic3xxx_cfw.h b/sound/soc/codecs/aic3xxx_cfw.h deleted file mode 100644 index 12bc85575195..000000000000 --- a/sound/soc/codecs/aic3xxx_cfw.h +++ /dev/null @@ -1,427 +0,0 @@ -/** - * \file Codec Firmware Declarations - */ - -#ifndef CFW_FIRMWARE_H_ -#define CFW_FIRMWARE_H_ -/** \defgroup bt Basic Types */ -/* @{ */ -#ifndef AIC3XXX_CFW_HOST_BLD -#include -#else -typedef unsigned char u8; -typedef unsigned short int u16; -typedef unsigned long int u32; -#endif - -#define CFW_FW_MAGIC 0xC0D1F1ED - -/** defgroup pd Arbitrary Limitations */ - -#ifndef CFW_MAX_ID -#define CFW_MAX_ID (64) /* Max length of string identifies */ -#endif - -#ifndef CFW_MAX_DESC -#define CFW_MAX_DESC (512) /* Max length of description */ -#endif -/* -# include -#include -#include -#include -#include -#include -# define warn(fmt, ...) printk(fmt "\n", ##__VA_ARGS__) -# define error(fmt, ...) printk(fmt "\n", ##__VA_ARGS__) - -#else -# define _GNU_SOURCE -# include -# include "utils.h" -# include -# include -# 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 - -} diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.h b/sound/soc/codecs/aic3xxx_cfw_ops.h deleted file mode 100644 index 81f6bda3581b..000000000000 --- a/sound/soc/codecs/aic3xxx_cfw_ops.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef AIC3XXX_CFW_OPS_H_ -#define AIC3XXX_CFW_OPS_H_ -#define DEBUG -#ifdef AIC3XXX_CFW_HOST_BLD -struct mutex { - int lock; -}; -#endif - -struct cfw_state { - struct cfw_project *pjt; - struct aic3xxx_codec_ops const *ops; - void *ops_obj; - struct mutex mutex; - int cur_mode_id; - int cur_mode; - int cur_pfw; - int cur_ovly; - int cur_cfg; -}; - -#ifdef AIC3XXX_CFW_HOST_BLD -struct cfw_project *aic3xxx_cfw_unpickle(void *pcfw, int n); -unsigned int crc32(unsigned int *pdata, int n); -struct snd_soc_codec; -#else -#ifdef DEBUG -#define DBG(fmt, ...) printk(KERN_DEBUG "CFW[%s:%d]: " fmt "\n", \ - __FILE__, __LINE__, ##__VA_ARGS__) -#else - #define DBG(fmt, ...) -#endif -#endif -int aic3xxx_cfw_init(struct cfw_state *ps, struct aic3xxx_codec_ops const *ops, - void *ops_obj); -int aic3xxx_cfw_lock(struct cfw_state *ps, int lock); -int aic3xxx_cfw_reload(struct cfw_state *ps, void *pcfw, int n); -int aic3xxx_cfw_setmode(struct cfw_state *ps, int mode); -int aic3xxx_cfw_setmode_cfg(struct cfw_state *ps, int mode, int cfg); -int aic3xxx_cfw_setcfg(struct cfw_state *ps, int cfg); -int aic3xxx_cfw_transition(struct cfw_state *ps, char *ttype); -int aic3xxx_cfw_set_pll(struct cfw_state *ps, int asi); -int aic3xxx_cfw_control(struct cfw_state *ps, char *cname, int param); -int aic3xxx_cfw_add_controls(struct snd_soc_codec *codec, struct cfw_state *ps); -int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps); - - -#define AIC3XX_COPS_MDSP_D (0x00000003u) -#define AIC3XX_COPS_MDSP_A (0x00000030u) -#define AIC3XX_COPS_MDSP_ALL (AIC3XX_COPS_MDSP_D|AIC3XX_COPS_MDSP_A) - -#define AIC3XX_ABUF_MDSP_D1 (0x00000001u) -#define AIC3XX_ABUF_MDSP_D2 (0x00000002u) -#define AIC3XX_ABUF_MDSP_A (0x00000010u) -#define AIC3XX_ABUF_MDSP_ALL \ - (AIC3XX_ABUF_MDSP_D1 | AIC3XX_ABUF_MDSP_D2 | AIC3XX_ABUF_MDSP_A) - -struct aic3xxx_codec_ops { - int (*reg_read)(void *p, unsigned int reg); - int (*reg_write)(void *p, unsigned int reg, - unsigned int val); - int (*set_bits)(void *p, unsigned int reg, - unsigned char mask, unsigned char val); - int (*bulk_read)(void *p, unsigned int reg, - int count, u8 *buf); - int (*bulk_write)(void *p, unsigned int reg, - int count, const u8 *buf); - - int (*lock) (void *p); - int (*unlock) (void *p); - int (*stop) (void *p, int mask); - int (*restore) (void *p, int runstate); - int (*bswap) (void *p, int mask); -}; - -#endif diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c index 65e92c6847a6..d985311295c8 100644 --- a/sound/soc/codecs/tlv320aic326x.c +++ b/sound/soc/codecs/tlv320aic326x.c @@ -37,9 +37,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -56,30 +56,29 @@ #include #include #include -#include -#include "aic3xxx_cfw.h" -#include "aic3xxx_cfw_ops.h" +#include +#include "aic3xxx/aic3xxx_cfw.h" +#include "aic3xxx/aic3xxx_cfw_ops.h" #include "tlv320aic326x.h" -#include "aic3262_codec_ops.h" -#include "tlv320aic3262_default_fw.h" -#define SOC_DOUBLE_R_SX_TLV3262(xname, xreg_left, xreg_right, xshift,\ - xmin, xmax, tlv_array) \ + +#define SOC_DOUBLE_R_SX_TLV3262(xname, xreg_left, xreg_right, xshift, \ + xmin, xmax, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ .tlv.p = (tlv_array), \ .info = snd_soc_info_volsw_2r_sx, \ .get = snd_soc_get_volsw_2r_sx, \ .put = snd_soc_put_volsw_2r_sx_aic3262, \ - .private_value = (unsigned long) &(struct soc_mixer_control) \ - {.reg = xreg_left, \ - .rreg = xreg_right, .shift = xshift, \ - .min = xmin, .max = xmax} } + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg_left, \ + .rreg = xreg_right, .shift = xshift, \ + .min = xmin, .max = xmax} } -/***************************************************************************** +/****************************************************************************** Macros ****************************************************************************** @@ -93,9 +92,6 @@ static int aic3262_hw_params(struct snd_pcm_substream *substream, static int aic3262_mute(struct snd_soc_dai *dai, int mute); -static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir); - static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt); static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, @@ -111,33 +107,37 @@ static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol, static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +static int aic3262_get_runstate(struct snd_soc_codec *codec); +static int aic3262_dsp_pwrdwn_status(struct snd_soc_codec *codec); +static int aic3262_dsp_pwrup(struct snd_soc_codec *codec, int state); +static int aic3262_restart_dsps_sync(struct snd_soc_codec *codec, int rs); -static long debug_level; -module_param(debug_level, long, 0); -MODULE_PARM_DESC(debug_level, "Debug level for printing"); +static inline unsigned int dsp_non_sync_mode(unsigned int state) + { return (!((state & 0x03) && (state & 0x30))); } /** * snd_soc_put_volsw_2r_sx - double with tlv and variable data size - * mixer put callback + * mixer put callback * @kcontrol: mixer control * @uinfo: control element information * * Returns 0 for success. */ int snd_soc_put_volsw_2r_sx_aic3262(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int mask = (1 << mc->shift) - 1; + unsigned int mask = (1<shift)-1; int min = mc->min; int ret; unsigned int val, valr; - val = ((ucontrol->value.integer.value[0] + min) & 0xff); + + val = ((ucontrol->value.integer.value[0]+min) & 0xff); val &= mask; - valr = ((ucontrol->value.integer.value[1] + min) & 0xff); + valr = ((ucontrol->value.integer.value[1]+min) & 0xff); valr &= mask; ret = 0; @@ -150,27 +150,6 @@ int snd_soc_put_volsw_2r_sx_aic3262(struct snd_kcontrol *kcontrol, return 0; } -static ssize_t debug_level_show(struct device *dev, - struct device_attribute *attr, - char *buf, size_t count) -{ - return sprintf(buf, "%ld\n", debug_level); -} - -static ssize_t debug_level_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int ret; - - ret = kstrtol(buf, 10, &debug_level); - if (ret) - return ret; - return count; -} - -static DEVICE_ATTR(debug_level, 0644, debug_level_show, debug_level_set); - static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1200, 50, 0); static const DECLARE_TLV_DB_SCALE(spk_gain_tlv, 600, 600, 0); @@ -284,7 +263,6 @@ static const struct snd_kcontrol_new aic3262_snd_controls[] = { struct snd_soc_dai_ops aic3262_asi1_dai_ops = { .hw_params = aic3262_hw_params, .digital_mute = aic3262_mute, - .set_sysclk = aic3262_set_dai_sysclk, .set_fmt = aic3262_set_dai_fmt, .set_pll = aic3262_dai_set_pll, }; @@ -292,7 +270,6 @@ struct snd_soc_dai_ops aic3262_asi1_dai_ops = { struct snd_soc_dai_ops aic3262_asi2_dai_ops = { .hw_params = aic3262_hw_params, .digital_mute = aic3262_mute, - .set_sysclk = aic3262_set_dai_sysclk, .set_fmt = aic3262_set_dai_fmt, .set_pll = aic3262_dai_set_pll, }; @@ -300,7 +277,6 @@ struct snd_soc_dai_ops aic3262_asi2_dai_ops = { struct snd_soc_dai_ops aic3262_asi3_dai_ops = { .hw_params = aic3262_hw_params, .digital_mute = aic3262_mute, - .set_sysclk = aic3262_set_dai_sysclk, .set_fmt = aic3262_set_dai_fmt, .set_pll = aic3262_dai_set_pll, }; @@ -311,14 +287,14 @@ struct snd_soc_dai_driver aic326x_dai_driver[] = { .playback = { .stream_name = "ASI1 Playback", .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = AIC3262_RATES, .formats = AIC3262_FORMATS, }, .capture = { .stream_name = "ASI1 Capture", .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = AIC3262_RATES, .formats = AIC3262_FORMATS, }, @@ -363,148 +339,150 @@ struct snd_soc_dai_driver aic326x_dai_driver[] = { }; - static const unsigned int adc_ma_tlv[] = { - TLV_DB_RANGE_HEAD(4), - 0, 29, TLV_DB_SCALE_ITEM(-1450, 500, 0), - 30, 35, TLV_DB_SCALE_ITEM(-2060, 1000, 0), - 36, 38, TLV_DB_SCALE_ITEM(-2660, 2000, 0), - 39, 40, TLV_DB_SCALE_ITEM(-3610, 5000, 0), + TLV_DB_RANGE_HEAD(7), + 1, 1, TLV_DB_SCALE_ITEM(-3610, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(-3010, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(-2660, 0, 0), + 4, 4, TLV_DB_SCALE_ITEM(-2410, 0, 0), + 5, 7, TLV_DB_SCALE_ITEM(-2210, 1500, 0), + 8, 11, TLV_DB_SCALE_ITEM(-1810, 1000, 0), + 12, 41 , TLV_DB_SCALE_ITEM(-1450, 500, 0) }; static const DECLARE_TLV_DB_SCALE(lo_hp_tlv, -7830, 50, 0); static const struct snd_kcontrol_new mal_pga_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1L Switch", AIC3262_MA_CNTL, 5, 1, 0), + SOC_DAPM_SINGLE("IN1 Left Capture Switch", AIC3262_MA_CNTL, 5, 1, 0), SOC_DAPM_SINGLE_TLV("Left MicPGA Volume", AIC3262_LADC_PGA_MAL_VOL, 0, 0x3f, 1, adc_ma_tlv), }; static const struct snd_kcontrol_new mar_pga_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1R Switch", AIC3262_MA_CNTL, 4, 1, 0), + SOC_DAPM_SINGLE("IN1 Right Capture Switch", AIC3262_MA_CNTL, 4, 1, 0), SOC_DAPM_SINGLE_TLV("Right MicPGA Volume", AIC3262_RADC_PGA_MAR_VOL, 0, 0x3f, 1, adc_ma_tlv), }; /* Left HPL Mixer */ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", AIC3262_HP_AMP_CNTL_R1, 7, 1, + SOC_DAPM_SINGLE("MA Left Playback Switch", AIC3262_HP_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Left DAC Playback Switch", AIC3262_HP_AMP_CNTL_R1, 5, 1, 0), - SOC_DAPM_SINGLE_TLV("LOL-B1 Volume", + SOC_DAPM_SINGLE_TLV("LO Left-B1 Playback Volume", AIC3262_HP_AMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), }; /* Right HPR Mixer */ static const struct snd_kcontrol_new hpr_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOR-B1 Volume", + SOC_DAPM_SINGLE_TLV("LO Right-B1 Playback Volume", AIC3262_HP_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Left DAC Playback Switch", AIC3262_HP_AMP_CNTL_R1, 2, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", AIC3262_HP_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Right DAC Playback Switch", AIC3262_HP_AMP_CNTL_R1, 4, 1, 0), - SOC_DAPM_SINGLE("MAR Switch", AIC3262_HP_AMP_CNTL_R1, + SOC_DAPM_SINGLE("MA Right Playback Switch", AIC3262_HP_AMP_CNTL_R1, 6, 1, 0), }; /* Left LOL Mixer */ static const struct snd_kcontrol_new lol_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", AIC3262_LINE_AMP_CNTL_R2, + SOC_DAPM_SINGLE("MA Left Playback Switch", AIC3262_LINE_AMP_CNTL_R2, 7, 1, 0), - SOC_DAPM_SINGLE("IN1L-B Switch", AIC3262_LINE_AMP_CNTL_R2, + SOC_DAPM_SINGLE("IN1 Left-B Capture Switch", AIC3262_LINE_AMP_CNTL_R2, 3, 1, 0), - SOC_DAPM_SINGLE("LDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Left DAC Playback Switch", AIC3262_LINE_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Right DAC Playback Switch", AIC3262_LINE_AMP_CNTL_R1, 5, 1, 0), }; /* Right LOR Mixer */ static const struct snd_kcontrol_new lor_output_mixer_controls[] = { - SOC_DAPM_SINGLE("LOL Switch", AIC3262_LINE_AMP_CNTL_R1, + SOC_DAPM_SINGLE("LO Left Playback Switch", AIC3262_LINE_AMP_CNTL_R1, 2, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Right DAC Playback Switch", AIC3262_LINE_AMP_CNTL_R1, 6, 1, 0), - SOC_DAPM_SINGLE("MAR Switch", AIC3262_LINE_AMP_CNTL_R2, + SOC_DAPM_SINGLE("MA Right Playback Switch", AIC3262_LINE_AMP_CNTL_R2, 6, 1, 0), - SOC_DAPM_SINGLE("IN1R-B Switch", AIC3262_LINE_AMP_CNTL_R2, + SOC_DAPM_SINGLE("IN1 Right-B Capture Switch", AIC3262_LINE_AMP_CNTL_R2, 0, 1, 0), }; /* Left SPKL Mixer */ static const struct snd_kcontrol_new spkl_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", AIC3262_SPK_AMP_CNTL_R1, + SOC_DAPM_SINGLE("MA Left Playback Switch", AIC3262_SPK_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE_TLV("LOL Volume", + SOC_DAPM_SINGLE_TLV("LO Left Playback Volume", AIC3262_SPK_AMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), SOC_DAPM_SINGLE("SPR_IN Switch", AIC3262_SPK_AMP_CNTL_R1, 2, 1, 0), }; /* Right SPKR Mixer */ static const struct snd_kcontrol_new spkr_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOR Volume", + SOC_DAPM_SINGLE_TLV("LO Right Playback Volume", AIC3262_SPK_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE("MAR Switch", + SOC_DAPM_SINGLE("MA Right Playback Switch", AIC3262_SPK_AMP_CNTL_R1, 6, 1, 0), }; /* REC Mixer */ static const struct snd_kcontrol_new rec_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOL-B2 Volume", + SOC_DAPM_SINGLE_TLV("LO Left-B2 Playback Volume", AIC3262_RAMP_CNTL_R1, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("IN1L Volume", + SOC_DAPM_SINGLE_TLV("IN1 Left Capture Volume", AIC3262_IN1L_SEL_RM, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("IN1R Volume", + SOC_DAPM_SINGLE_TLV("IN1 Right Capture Volume", AIC3262_IN1R_SEL_RM, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("LOR-B2 Volume", + SOC_DAPM_SINGLE_TLV("LO Right-B2 Playback Volume", AIC3262_RAMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), }; /* Left Input Mixer */ static const struct snd_kcontrol_new left_input_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1L Switch", AIC3262_LMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN1 Left Capture Switch", AIC3262_LMIC_PGA_PIN, 6, 3, 0), - SOC_DAPM_SINGLE("IN2L Switch", AIC3262_LMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN2 Left Capture Switch", AIC3262_LMIC_PGA_PIN, 4, 3, 0), - SOC_DAPM_SINGLE("IN3L Switch", AIC3262_LMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN3 Left Capture Switch", AIC3262_LMIC_PGA_PIN, 2, 3, 0), - SOC_DAPM_SINGLE("IN4L Switch", AIC3262_LMIC_PGA_PM_IN4, + SOC_DAPM_SINGLE("IN4 Left Capture Switch", AIC3262_LMIC_PGA_PM_IN4, 5, 1, 0), - SOC_DAPM_SINGLE("IN1R Switch", AIC3262_LMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN1 Right Capture Switch", AIC3262_LMIC_PGA_PIN, 0, 3, 0), - SOC_DAPM_SINGLE("IN2R Switch", AIC3262_LMIC_PGA_MIN, + SOC_DAPM_SINGLE("IN2 Right Capture Switch", AIC3262_LMIC_PGA_MIN, 4, 3, 0), - SOC_DAPM_SINGLE("IN3R Switch", AIC3262_LMIC_PGA_MIN, + SOC_DAPM_SINGLE("IN3 Right Capture Switch", AIC3262_LMIC_PGA_MIN, 2, 3, 0), - SOC_DAPM_SINGLE("IN4R Switch", AIC3262_LMIC_PGA_PM_IN4, + SOC_DAPM_SINGLE("IN4 Right Capture Switch", AIC3262_LMIC_PGA_PM_IN4, 4, 1, 0), - SOC_DAPM_SINGLE("CM2L Switch", AIC3262_LMIC_PGA_MIN, + SOC_DAPM_SINGLE("CM2 Left Capture Switch", AIC3262_LMIC_PGA_MIN, 0, 3, 0), - SOC_DAPM_SINGLE("CM1L Switch", AIC3262_LMIC_PGA_MIN, + SOC_DAPM_SINGLE("CM1 Left Capture Switch", AIC3262_LMIC_PGA_MIN, 6, 3, 0), }; /* Right Input Mixer */ static const struct snd_kcontrol_new right_input_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1R Switch", AIC3262_RMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN1 Right Capture Switch", AIC3262_RMIC_PGA_PIN, 6, 3, 0), - SOC_DAPM_SINGLE("IN2R Switch", AIC3262_RMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN2 Right Capture Switch", AIC3262_RMIC_PGA_PIN, 4, 3, 0), - SOC_DAPM_SINGLE("IN3R Switch", AIC3262_RMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN3 Right Capture Switch", AIC3262_RMIC_PGA_PIN, 2, 3, 0), - SOC_DAPM_SINGLE("IN4R Switch", AIC3262_RMIC_PGA_PM_IN4, + SOC_DAPM_SINGLE("IN4 Right Capture Switch", AIC3262_RMIC_PGA_PM_IN4, 5, 1, 0), - SOC_DAPM_SINGLE("IN2L Switch", AIC3262_RMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN2 Left Capture Switch", AIC3262_RMIC_PGA_PIN, 0, 3, 0), - SOC_DAPM_SINGLE("IN1L Switch", AIC3262_RMIC_PGA_MIN, + SOC_DAPM_SINGLE("IN1 Left Capture Switch", AIC3262_RMIC_PGA_MIN, 4, 3, 0), - SOC_DAPM_SINGLE("IN3L Switch", AIC3262_RMIC_PGA_MIN, + SOC_DAPM_SINGLE("IN3 Left Capture Switch", AIC3262_RMIC_PGA_MIN, 2, 3, 0), - SOC_DAPM_SINGLE("IN4L Switch", AIC3262_RMIC_PGA_PM_IN4, + SOC_DAPM_SINGLE("IN4 Left Capture Switch", AIC3262_RMIC_PGA_PM_IN4, 4, 1, 0), - SOC_DAPM_SINGLE("CM1R Switch", AIC3262_RMIC_PGA_MIN, + SOC_DAPM_SINGLE("CM1 Right Capture Switch", AIC3262_RMIC_PGA_MIN, 6, 3, 0), - SOC_DAPM_SINGLE("CM2R Switch", AIC3262_RMIC_PGA_MIN, + SOC_DAPM_SINGLE("CM2 Right Capture Switch", AIC3262_RMIC_PGA_MIN, 0, 3, 0), }; @@ -720,31 +698,69 @@ static int aic326x_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { int reg_mask = 0; + int mute_reg = 0; int ret_wbits = 0; + u8 hpl_hpr; - if (w->shift == 1) - reg_mask = AIC3262_HPL_POWER_MASK; - if (w->shift == 0) - reg_mask = AIC3262_HPR_POWER_MASK; + if (w->shift == 1) { + reg_mask = AIC3262_HPL_POWER_STATUS_MASK; + mute_reg = AIC3262_HPL_VOL; + } + if (w->shift == 0) { + reg_mask = AIC3262_HPR_POWER_STATUS_MASK; + mute_reg = AIC3262_HPR_VOL; + } switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(w->codec, AIC3262_CHARGE_PUMP_CNTL, + AIC3262_DYNAMIC_OFFSET_CALIB_MASK, + AIC3262_DYNAMIC_OFFSET_CALIB); + snd_soc_write(w->codec, mute_reg, 0x80); + snd_soc_update_bits(w->codec, AIC3262_HP_CTL, + AIC3262_HP_STAGE_MASK , + AIC3262_HP_STAGE_25 << AIC3262_HP_STAGE_SHIFT); + break; + case SND_SOC_DAPM_POST_PMU: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_HP_FLAG, reg_mask, - reg_mask, TIME_DELAY, - DELAY_COUNTER); + reg_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); if (!ret_wbits) { dev_err(w->codec->dev, "HP POST_PMU timedout\n"); return -1; } + snd_soc_update_bits(w->codec, AIC3262_HP_CTL, + AIC3262_HP_STAGE_MASK , + AIC3262_HP_STAGE_100 << AIC3262_HP_STAGE_SHIFT); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(w->codec, AIC3262_HP_CTL, + AIC3262_HP_STAGE_MASK , + AIC3262_HP_STAGE_25 << AIC3262_HP_STAGE_SHIFT); + hpl_hpr = snd_soc_read(w->codec, AIC3262_HP_AMP_CNTL_R1); + if ((hpl_hpr & 0x3) == 0x3) { + snd_soc_update_bits(w->codec, AIC3262_HP_AMP_CNTL_R1, + AIC3262_HPL_POWER_MASK, 0x0); + mdelay(1); + snd_soc_update_bits(w->codec, AIC3262_HP_AMP_CNTL_R1, + AIC3262_HPR_POWER_MASK, 0x0); + } break; + case SND_SOC_DAPM_POST_PMD: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_HP_FLAG, reg_mask, 0, - TIME_DELAY, DELAY_COUNTER); + AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); if (!ret_wbits) { dev_err(w->codec->dev, "HP POST_PMD timedout\n"); return -1; } + snd_soc_write(w->codec, mute_reg, 0xb9); + snd_soc_write(w->codec, AIC3262_POWER_CONF, + snd_soc_read(w->codec, AIC3262_POWER_CONF)); break; default: BUG(); @@ -773,29 +789,31 @@ static int aic326x_dac_event(struct snd_soc_dapm_widget *w, int other_dsp = 0, run_state = 0; if (w->shift == 7) { - reg_mask = AIC3262_LDAC_POWER_MASK; - run_state_mask = AIC3262_COPS_MDSP_D_L; + reg_mask = AIC3262_LDAC_POWER_STATUS_MASK; + run_state_mask = AIC3XXX_COPS_MDSP_D_L; } if (w->shift == 6) { - reg_mask = AIC3262_RDAC_POWER_MASK; - run_state_mask = AIC3262_COPS_MDSP_D_R; + reg_mask = AIC3262_RDAC_POWER_STATUS_MASK; + run_state_mask = AIC3XXX_COPS_MDSP_D_R; } switch (event) { case SND_SOC_DAPM_POST_PMU: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_DAC_FLAG, reg_mask, - reg_mask, TIME_DELAY, - DELAY_COUNTER); + reg_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); - sync_needed = SYNC_STATE(aic3262); - non_sync_state = DSP_NON_SYNC_MODE(aic3262->dsp_runstate); - other_dsp = aic3262->dsp_runstate & AIC3262_COPS_MDSP_A; + sync_needed = aic3xxx_reg_read(w->codec->control_data, + AIC3262_DAC_PRB); + non_sync_state = dsp_non_sync_mode(aic3262->dsp_runstate); + other_dsp = aic3262->dsp_runstate & AIC3XXX_COPS_MDSP_A; if (sync_needed && non_sync_state && other_dsp) { - run_state = get_runstate(aic3262->codec->control_data); - aic3262_dsp_pwrdwn_status(aic3262); - aic3262_dsp_pwrup(aic3262, run_state); + run_state = aic3262_get_runstate( + aic3262->codec); + aic3262_dsp_pwrdwn_status(aic3262->codec); + aic3262_dsp_pwrup(aic3262->codec, run_state); } aic3262->dsp_runstate |= run_state_mask; @@ -806,9 +824,10 @@ static int aic326x_dac_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_DAC_FLAG, reg_mask, 0, - TIME_DELAY, DELAY_COUNTER); + AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); aic3262->dsp_runstate = (aic3262->dsp_runstate & ~run_state_mask); @@ -839,9 +858,9 @@ static int aic326x_spk_event(struct snd_soc_dapm_widget *w, int reg_mask; if (w->shift == 1) - reg_mask = AIC3262_SPKL_POWER_MASK; + reg_mask = AIC3262_SPKL_POWER_STATUS_MASK; if (w->shift == 0) - reg_mask = AIC3262_SPKR_POWER_MASK; + reg_mask = AIC3262_SPKR_POWER_STATUS_MASK; switch (event) { case SND_SOC_DAPM_POST_PMU: mdelay(1); @@ -914,7 +933,6 @@ static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol, else ret = aic3xxx_cfw_setmode_cfg(priv_ds->cfw_p, next_mode, next_cfg); - return ret; } @@ -939,25 +957,27 @@ static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, if (w->shift == 7) { reg_mask = AIC3262_LADC_POWER_MASK; - run_state_mask = AIC3262_COPS_MDSP_A_L; + run_state_mask = AIC3XXX_COPS_MDSP_A_L; } if (w->shift == 6) { reg_mask = AIC3262_RADC_POWER_MASK; - run_state_mask = AIC3262_COPS_MDSP_A_R; + run_state_mask = AIC3XXX_COPS_MDSP_A_R; } switch (event) { case SND_SOC_DAPM_POST_PMU: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_ADC_FLAG, reg_mask, - reg_mask, TIME_DELAY, - DELAY_COUNTER); - sync_needed = SYNC_STATE(aic3262); - non_sync_state = DSP_NON_SYNC_MODE(aic3262->dsp_runstate); - other_dsp = aic3262->dsp_runstate & AIC3262_COPS_MDSP_D; + reg_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); + sync_needed = aic3xxx_reg_read(w->codec->control_data, + AIC3262_DAC_PRB); + non_sync_state = dsp_non_sync_mode(aic3262->dsp_runstate); + other_dsp = aic3262->dsp_runstate & AIC3XXX_COPS_MDSP_D; if (sync_needed && non_sync_state && other_dsp) { - run_state = get_runstate(aic3262->codec->control_data); - aic3262_dsp_pwrdwn_status(aic3262); - aic3262_dsp_pwrup(aic3262, run_state); + run_state = aic3262_get_runstate( + aic3262->codec); + aic3262_dsp_pwrdwn_status(aic3262->codec); + aic3262_dsp_pwrup(aic3262->codec, run_state); } aic3262->dsp_runstate |= run_state_mask; if (!ret_wbits) { @@ -966,9 +986,10 @@ static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, } break; case SND_SOC_DAPM_POST_PMD: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_ADC_FLAG, reg_mask, 0, - TIME_DELAY, DELAY_COUNTER); + AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); aic3262->dsp_runstate = (aic3262->dsp_runstate & ~run_state_mask); if (!ret_wbits) { @@ -984,6 +1005,7 @@ static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { + /* TODO: Can we switch these off ? */ SND_SOC_DAPM_AIF_IN("DIN1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("DIN2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("DIN3", "ASI3 Playback", 0, SND_SOC_NOPM, 0, 0), @@ -996,68 +1018,65 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { SND_SOC_DAPM_POST_PMD), /* dapm widget (path domain) for HPL Output Mixer */ - SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0, - &hpl_output_mixer_controls[0], - ARRAY_SIZE(hpl_output_mixer_controls)), + SND_SOC_DAPM_MIXER("HP Left Mixer", SND_SOC_NOPM, 0, 0, + &hpl_output_mixer_controls[0], + ARRAY_SIZE(hpl_output_mixer_controls)), /* dapm widget (path domain) for HPR Output Mixer */ - SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0, - &hpr_output_mixer_controls[0], - ARRAY_SIZE(hpr_output_mixer_controls)), - - - SND_SOC_DAPM_PGA_E("HPL Driver", AIC3262_HP_AMP_CNTL_R1, - 1, 0, NULL, 0, aic326x_hp_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("HPR Driver", AIC3262_HP_AMP_CNTL_R1, - 0, 0, NULL, 0, aic326x_hp_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - + SND_SOC_DAPM_MIXER("HP Right Mixer", SND_SOC_NOPM, 0, 0, + &hpr_output_mixer_controls[0], + ARRAY_SIZE(hpr_output_mixer_controls)), + + SND_SOC_DAPM_PGA_S("HP Left Playback Driver", 3, + AIC3262_HP_AMP_CNTL_R1, 1, 0, aic326x_hp_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_S("HP Right Playback Driver", 3, + AIC3262_HP_AMP_CNTL_R1, 0, 0, aic326x_hp_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), /* dapm widget (path domain) for LOL Output Mixer */ - SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0, - &lol_output_mixer_controls[0], - ARRAY_SIZE(lol_output_mixer_controls)), + SND_SOC_DAPM_MIXER("LO Left Mixer", SND_SOC_NOPM, 0, 0, + &lol_output_mixer_controls[0], + ARRAY_SIZE(lol_output_mixer_controls)), /* dapm widget (path domain) for LOR Output Mixer mixer */ - SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0, - &lor_output_mixer_controls[0], - ARRAY_SIZE(lor_output_mixer_controls)), - - SND_SOC_DAPM_PGA("LOL Driver", AIC3262_LINE_AMP_CNTL_R1, - 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("LOR Driver", AIC3262_LINE_AMP_CNTL_R1, - 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("LO Right Mixer", SND_SOC_NOPM, 0, 0, + &lor_output_mixer_controls[0], + ARRAY_SIZE(lor_output_mixer_controls)), + SND_SOC_DAPM_PGA_S("LO Left Playback Driver", 2, + AIC3262_LINE_AMP_CNTL_R1, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("LO Right Playback Driver", 2, + AIC3262_LINE_AMP_CNTL_R1, 0, 0, NULL, 0), /* dapm widget (path domain) for SPKL Output Mixer */ - SND_SOC_DAPM_MIXER("SPKL Output Mixer", SND_SOC_NOPM, 0, 0, - &spkl_output_mixer_controls[0], - ARRAY_SIZE(spkl_output_mixer_controls)), + SND_SOC_DAPM_MIXER("SPK Left Mixer", SND_SOC_NOPM, 0, 0, + &spkl_output_mixer_controls[0], + ARRAY_SIZE(spkl_output_mixer_controls)), /* dapm widget (path domain) for SPKR Output Mixer */ - SND_SOC_DAPM_MIXER("SPKR Output Mixer", SND_SOC_NOPM, 0, 0, - &spkr_output_mixer_controls[0], - ARRAY_SIZE(spkr_output_mixer_controls)), - - SND_SOC_DAPM_PGA_E("SPKL Driver", AIC3262_SPK_AMP_CNTL_R1, - 1, 0, NULL, 0, aic326x_spk_event, - SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_PGA_E("SPKR Driver", AIC3262_SPK_AMP_CNTL_R1, - 0, 0, NULL, 0, aic326x_spk_event, - SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MIXER("SPK Right Mixer", SND_SOC_NOPM, 0, 0, + &spkr_output_mixer_controls[0], + ARRAY_SIZE(spkr_output_mixer_controls)), + SND_SOC_DAPM_PGA_S("SPK Left Playback Driver", 3, + AIC3262_SPK_AMP_CNTL_R1, 1, 0, aic326x_spk_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("SPK Right Playback Driver", 3, + AIC3262_SPK_AMP_CNTL_R1, 0, 0, aic326x_spk_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), /* dapm widget (path domain) for SPKR Output Mixer */ - SND_SOC_DAPM_MIXER("REC Output Mixer", SND_SOC_NOPM, 0, 0, - &rec_output_mixer_controls[0], - ARRAY_SIZE(rec_output_mixer_controls)), - - SND_SOC_DAPM_PGA("RECP Driver", AIC3262_REC_AMP_CNTL_R5, - 7, 0, NULL, 0), - SND_SOC_DAPM_PGA("RECM Driver", AIC3262_REC_AMP_CNTL_R5, - 6, 0, NULL, 0), + SND_SOC_DAPM_MIXER("REC Mixer", SND_SOC_NOPM, 0, 0, + &rec_output_mixer_controls[0], + ARRAY_SIZE(rec_output_mixer_controls)), + SND_SOC_DAPM_PGA_S("RECP Playback Driver", 3, AIC3262_REC_AMP_CNTL_R5, + 7, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("RECM Playback Driver", 3, AIC3262_REC_AMP_CNTL_R5, + 6, 0, NULL, 0), SND_SOC_DAPM_MUX("ASI1LIN Route", SND_SOC_NOPM, 0, 0, &asi1lin_control), @@ -1097,10 +1116,10 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { SND_SOC_NOPM, 0, 0, &adcdacroute_control), SND_SOC_DAPM_PGA("CM", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("CM1L", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("CM2L", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("CM1R", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("CM2R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("CM1 Left Capture", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("CM2 Left Capture", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("CM1 Right Capture", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("CM2 Right Capture", SND_SOC_NOPM, 0, 0, NULL, 0), /* TODO: Can we switch these off ? */ SND_SOC_DAPM_AIF_OUT("DOUT1", "ASI1 Capture", 0, SND_SOC_NOPM, 0, 0), @@ -1131,9 +1150,6 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { SND_SOC_DAPM_PGA("ADC MiniDSP OUT2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ADC MiniDSP OUT3", SND_SOC_NOPM, 0, 0, NULL, 0), -/* SND_SOC_DAPM_MUX("DMICDAT Input Route", - SND_SOC_NOPM, 0, 0, &dmicinput_control),*/ - SND_SOC_DAPM_MUX("Left ADC Route", SND_SOC_NOPM, 0, 0, &adcl_mux), SND_SOC_DAPM_MUX("Right ADC Route", SND_SOC_NOPM, 0, 0, &adcr_mux), @@ -1144,72 +1160,80 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { aic326x_adc_dsp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA("Left MicPGA", AIC3262_MICL_PGA, 7, 1, NULL, 0), - SND_SOC_DAPM_PGA("Right MicPGA", AIC3262_MICR_PGA, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA_S("Left MicPGA", 0, AIC3262_MICL_PGA, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA_S("Right MicPGA", 0, AIC3262_MICR_PGA, 7, 1, NULL, 0), - SND_SOC_DAPM_PGA("MAL PGA", AIC3262_MA_CNTL, - 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("MAR PGA", AIC3262_MA_CNTL, - 2, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("MA Left Playback PGA", 1, AIC3262_MA_CNTL, + 3, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("MA Right Playback PGA", 1, AIC3262_MA_CNTL, + 2, 0, NULL, 0), /* dapm widget for MAL PGA Mixer */ - SND_SOC_DAPM_MIXER("MAL PGA Mixer", SND_SOC_NOPM, 0, 0, - &mal_pga_mixer_controls[0], - ARRAY_SIZE(mal_pga_mixer_controls)), + SND_SOC_DAPM_MIXER("MA Left PGA Mixer", SND_SOC_NOPM, 0, 0, + &mal_pga_mixer_controls[0], + ARRAY_SIZE(mal_pga_mixer_controls)), /* dapm widget for MAR PGA Mixer */ - SND_SOC_DAPM_MIXER("MAR PGA Mixer", SND_SOC_NOPM, 0, 0, - &mar_pga_mixer_controls[0], - ARRAY_SIZE(mar_pga_mixer_controls)), + SND_SOC_DAPM_MIXER("MA Right PGA Mixer", SND_SOC_NOPM, 0, 0, + &mar_pga_mixer_controls[0], + ARRAY_SIZE(mar_pga_mixer_controls)), /* dapm widget for Left Input Mixer */ SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0, - &left_input_mixer_controls[0], - ARRAY_SIZE(left_input_mixer_controls)), + &left_input_mixer_controls[0], + ARRAY_SIZE(left_input_mixer_controls)), /* dapm widget for Right Input Mixer */ SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0, - &right_input_mixer_controls[0], - ARRAY_SIZE(right_input_mixer_controls)), - - SND_SOC_DAPM_OUTPUT("HPL"), - SND_SOC_DAPM_OUTPUT("HPR"), - SND_SOC_DAPM_OUTPUT("LOL"), - SND_SOC_DAPM_OUTPUT("LOR"), - SND_SOC_DAPM_OUTPUT("SPKL"), - SND_SOC_DAPM_OUTPUT("SPKR"), - SND_SOC_DAPM_OUTPUT("RECP"), - SND_SOC_DAPM_OUTPUT("RECM"), - - SND_SOC_DAPM_INPUT("IN1L"), - SND_SOC_DAPM_INPUT("IN2L"), - SND_SOC_DAPM_INPUT("IN3L"), - SND_SOC_DAPM_INPUT("IN4L"), - SND_SOC_DAPM_INPUT("IN1R"), - SND_SOC_DAPM_INPUT("IN2R"), - SND_SOC_DAPM_INPUT("IN3R"), - SND_SOC_DAPM_INPUT("IN4R"), - SND_SOC_DAPM_INPUT("Left DMIC"), - SND_SOC_DAPM_INPUT("Right DMIC"), + &right_input_mixer_controls[0], + ARRAY_SIZE(right_input_mixer_controls)), + + SND_SOC_DAPM_OUTPUT("HP Left Playback"), + SND_SOC_DAPM_OUTPUT("HP Right Playback"), + SND_SOC_DAPM_OUTPUT("LO Left Playback"), + SND_SOC_DAPM_OUTPUT("LO Right Playback"), + SND_SOC_DAPM_OUTPUT("SPK Left Playback"), + SND_SOC_DAPM_OUTPUT("SPK Right Playback"), + SND_SOC_DAPM_OUTPUT("RECP Playback"), + SND_SOC_DAPM_OUTPUT("RECM Playback"), + + SND_SOC_DAPM_INPUT("IN1 Left Capture"), + SND_SOC_DAPM_INPUT("IN2 Left Capture"), + SND_SOC_DAPM_INPUT("IN3 Left Capture"), + SND_SOC_DAPM_INPUT("IN4 Left Capture"), + SND_SOC_DAPM_INPUT("IN1 Right Capture"), + SND_SOC_DAPM_INPUT("IN2 Right Capture"), + SND_SOC_DAPM_INPUT("IN3 Right Capture"), + SND_SOC_DAPM_INPUT("IN4 Right Capture"), + SND_SOC_DAPM_INPUT("Left DMIC Capture"), + SND_SOC_DAPM_INPUT("Right DMIC Capture"), SND_SOC_DAPM_MICBIAS("Mic Bias Ext", AIC3262_MIC_BIAS_CNTL, 6, 0), SND_SOC_DAPM_MICBIAS("Mic Bias Int", AIC3262_MIC_BIAS_CNTL, 2, 0), - SND_SOC_DAPM_SUPPLY("PLLCLK", AIC3262_PLL_PR_POW_REG, 7, 0, + SND_SOC_DAPM_SUPPLY_S("PLLCLK", 0, AIC3262_PLL_PR_POW_REG, 7, 0, pll_power_on_event, SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_SUPPLY("DACCLK", AIC3262_NDAC_DIV_POW_REG, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC_MOD_CLK", AIC3262_MDAC_DIV_POW_REG, - 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADCCLK", AIC3262_NADC_DIV_POW_REG, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK", AIC3262_MADC_DIV_POW_REG, - 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI1_BCLK", AIC3262_ASI1_BCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI1_WCLK", AIC3262_ASI1_WCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI2_BCLK", AIC3262_ASI2_BCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI2_WCLK", AIC3262_ASI2_WCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI3_BCLK", AIC3262_ASI3_BCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI3_WCLK", AIC3262_ASI3_WCLK_N, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACCLK", 2, AIC3262_NDAC_DIV_POW_REG, 7, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("CODEC_CLK_IN", 1, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC_MOD_CLK", 3, AIC3262_MDAC_DIV_POW_REG, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADCCLK", 2, AIC3262_NADC_DIV_POW_REG, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC_MOD_CLK", 3, AIC3262_MADC_DIV_POW_REG, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI1_BCLK", 4, AIC3262_ASI1_BCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI1_WCLK", 4, AIC3262_ASI1_WCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI2_BCLK", 4, AIC3262_ASI2_BCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI2_WCLK", 4, AIC3262_ASI2_WCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI3_BCLK", 4, AIC3262_ASI3_BCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI3_WCLK", 4, AIC3262_ASI3_WCLK_N, + 7, 0, NULL, 0), SND_SOC_DAPM_MUX("ASI1_BCLK Route", SND_SOC_NOPM, 0, 0, &asi1bclk_control), SND_SOC_DAPM_MUX("ASI2_BCLK Route", @@ -1249,122 +1273,89 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { {"ASI1_BCLK", NULL, "ASI1_BCLK Route"}, {"ASI2_BCLK", NULL, "ASI2_BCLK Route"}, {"ASI3_BCLK", NULL, "ASI3_BCLK Route"}, - - {"DIN1", NULL, "PLLCLK"}, - {"DIN1", NULL, "DACCLK"}, - {"DIN1", NULL, "ADCCLK"}, - {"DIN1", NULL, "DAC_MOD_CLK"}, - {"DIN1", NULL, "ADC_MOD_CLK"}, - - {"DOUT1", NULL, "PLLCLK"}, - {"DOUT1", NULL, "DACCLK"}, - {"DOUT1", NULL, "ADCCLK"}, - {"DOUT1", NULL, "DAC_MOD_CLK"}, - {"DOUT1", NULL, "ADC_MOD_CLK"}, #ifdef AIC3262_ASI1_MASTER {"DIN1", NULL, "ASI1_BCLK"}, {"DOUT1", NULL, "ASI1_BCLK"}, {"DIN1", NULL, "ASI1_WCLK"}, {"DOUT1", NULL, "ASI1_WCLK"}, -#else - #endif - {"DIN2", NULL, "PLLCLK"}, - {"DIN2", NULL, "DACCLK"}, - {"DIN2", NULL, "ADCCLK"}, - {"DIN2", NULL, "DAC_MOD_CLK"}, - {"DIN2", NULL, "ADC_MOD_CLK"}, - - {"DOUT2", NULL, "PLLCLK"}, - {"DOUT2", NULL, "DACCLK"}, - {"DOUT2", NULL, "ADCCLK"}, - {"DOUT2", NULL, "DAC_MOD_CLK"}, - {"DOUT2", NULL, "ADC_MOD_CLK"}, - #ifdef AIC3262_ASI2_MASTER {"DIN2", NULL, "ASI2_BCLK"}, {"DOUT2", NULL, "ASI2_BCLK"}, {"DIN2", NULL, "ASI2_WCLK"}, {"DOUT2", NULL, "ASI2_WCLK"}, -#else - #endif - {"DIN3", NULL, "PLLCLK"}, - {"DIN3", NULL, "DACCLK"}, - {"DIN3", NULL, "ADCCLK"}, - {"DIN3", NULL, "DAC_MOD_CLK"}, - {"DIN3", NULL, "ADC_MOD_CLK"}, - - {"DOUT3", NULL, "PLLCLK"}, - {"DOUT3", NULL, "DACCLK"}, - {"DOUT3", NULL, "ADCCLK"}, - {"DOUT3", NULL, "DAC_MOD_CLK"}, - {"DOUT3", NULL, "ADC_MOD_CLK"}, - #ifdef AIC3262_ASI3_MASTER {"DIN3", NULL, "ASI3_BCLK"}, {"DOUT3", NULL, "ASI3_BCLK"}, {"DIN3", NULL, "ASI3_WCLK"}, {"DOUT3", NULL, "ASI3_WCLK"}, -#else - #endif + {"Left DAC", NULL, "DAC_MOD_CLK"}, + {"Right DAC", NULL, "DAC_MOD_CLK"}, + /* When we are master, ASI bclk and wclk are generated by + * DAC_MOD_CLK, so we put them as dependency for ADC too. + */ + {"Left ADC", NULL, "DAC_MOD_CLK"}, + {"Right ADC", NULL, "DAC_MOD_CLK"}, + {"Left ADC", NULL, "ADC_MOD_CLK"}, + {"Right ADC", NULL, "ADC_MOD_CLK"}, /* Playback (DAC) Portion */ - {"HPL Output Mixer", "LDAC Switch", "Left DAC"}, - {"HPL Output Mixer", "MAL Switch", "MAL PGA"}, - {"HPL Output Mixer", "LOL-B1 Volume", "LOL"}, - - {"HPR Output Mixer", "LOR-B1 Volume", "LOR"}, - {"HPR Output Mixer", "LDAC Switch", "Left DAC"}, - {"HPR Output Mixer", "RDAC Switch", "Right DAC"}, - {"HPR Output Mixer", "MAR Switch", "MAR PGA"}, + {"HP Left Mixer", "Left DAC Playback Switch", "Left DAC"}, + {"HP Left Mixer", "MA Left Playback Switch", "MA Left Playback PGA"}, + {"HP Left Mixer", "LO Left-B1 Playback Volume", "LO Left Playback"}, - {"HPL Driver", NULL, "HPL Output Mixer"}, - {"HPR Driver", NULL, "HPR Output Mixer"}, + {"HP Right Mixer", "LO Right-B1 Playback Volume", "LO Right Playback"}, + {"HP Right Mixer", "Left DAC Playback Switch", "Left DAC"}, + {"HP Right Mixer", "Right DAC Playback Switch", "Right DAC"}, + {"HP Right Mixer", "MA Right Playback Switch", "MA Right Playback PGA"}, - {"HPL", NULL, "HPL Driver"}, - {"HPR", NULL, "HPR Driver"}, + {"HP Left Playback Driver", NULL, "HP Left Mixer"}, + {"HP Right Playback Driver", NULL, "HP Right Mixer"}, - {"LOL Output Mixer", "MAL Switch", "MAL PGA"}, - {"LOL Output Mixer", "IN1L-B Switch", "IN1L"}, - {"LOL Output Mixer", "LDAC Switch", "Left DAC"}, - {"LOL Output Mixer", "RDAC Switch", "Right DAC"}, + {"HP Left Playback", NULL, "HP Left Playback Driver"}, + {"HP Right Playback", NULL, "HP Right Playback Driver"}, - {"LOR Output Mixer", "LOL Switch", "LOL"}, - {"LOR Output Mixer", "RDAC Switch", "Right DAC"}, - {"LOR Output Mixer", "MAR Switch", "MAR PGA"}, - {"LOR Output Mixer", "IN1R-B Switch", "IN1R"}, + {"LO Left Mixer", "MA Left Playback Switch", "MA Left Playback PGA"}, + {"LO Left Mixer", "IN1 Left-B Capture Switch", "IN1 Left Capture"}, + {"LO Left Mixer", "Left DAC Playback Switch", "Left DAC"}, + {"LO Left Mixer", "Right DAC Playback Switch", "Right DAC"}, - {"LOL Driver", NULL, "LOL Output Mixer"}, - {"LOR Driver", NULL, "LOR Output Mixer"}, + {"LO Right Mixer", "LO Left Playback Switch", "LO Left Playback"}, + {"LO Right Mixer", "Right DAC Playback Switch", "Right DAC"}, + {"LO Right Mixer", "MA Right Playback Switch", "MA Right Playback PGA"}, + {"LO Right Mixer", "IN1 Right-B Capture Switch", "IN1 Right Capture"}, - {"LOL", NULL, "LOL Driver"}, - {"LOR", NULL, "LOR Driver"}, + {"LO Left Playback Driver", NULL, "LO Left Mixer"}, + {"LO Right Playback Driver", NULL, "LO Right Mixer"}, - {"REC Output Mixer", "LOL-B2 Volume", "LOL"}, - {"REC Output Mixer", "IN1L Volume", "IN1L"}, - {"REC Output Mixer", "IN1R Volume", "IN1R"}, - {"REC Output Mixer", "LOR-B2 Volume", "LOR"}, + {"LO Left Playback", NULL, "LO Left Playback Driver"}, + {"LO Right Playback", NULL, "LO Right Playback Driver"}, - {"RECP Driver", NULL, "REC Output Mixer"}, - {"RECM Driver", NULL, "REC Output Mixer"}, + {"REC Mixer", "LO Left-B2 Playback Volume", "LO Left Playback"}, + {"REC Mixer", "IN1 Left Capture Volume", "IN1 Left Capture"}, + {"REC Mixer", "IN1 Right Capture Volume", "IN1 Right Capture"}, + {"REC Mixer", "LO Right-B2 Playback Volume", "LO Right Playback"}, - {"RECP", NULL, "RECP Driver"}, - {"RECM", NULL, "RECM Driver"}, + {"RECP Playback Driver", NULL, "REC Mixer"}, + {"RECM Playback Driver", NULL, "REC Mixer"}, - {"SPKL Output Mixer", "MAL Switch", "MAL PGA"}, - {"SPKL Output Mixer", "LOL Volume", "LOL"}, - {"SPKL Output Mixer", "SPR_IN Switch", "SPKR Output Mixer"}, + {"RECP Playback", NULL, "RECP Playback Driver"}, + {"RECM Playback", NULL, "RECM Playback Driver"}, - {"SPKR Output Mixer", "LOR Volume", "LOR"}, - {"SPKR Output Mixer", "MAR Switch", "MAR PGA"}, + {"SPK Left Mixer", "MA Left Playback Switch", "MA Left Playback PGA"}, + {"SPK Left Mixer", "LO Left Playback Volume", "LO Left Playback"}, + {"SPK Left Mixer", "SPR_IN Switch", "SPK Right Mixer"}, + {"SPK Right Mixer", "LO Right Playback Volume", "LO Right Playback"}, + {"SPK Right Mixer", "MA Right Playback Switch", + "MA Right Playback PGA"}, - {"SPKL Driver", NULL, "SPKL Output Mixer"}, - {"SPKR Driver", NULL, "SPKR Output Mixer"}, + {"SPK Left Playback Driver", NULL, "SPK Left Mixer"}, + {"SPK Right Playback Driver", NULL, "SPK Right Mixer"}, - {"SPKL", NULL, "SPKL Driver"}, - {"SPKR", NULL, "SPKR Driver"}, + {"SPK Left Playback", NULL, "SPK Left Playback Driver"}, + {"SPK Right Playback", NULL, "SPK Right Playback Driver"}, /* ASI Input routing */ {"ASI1LIN", NULL, "DIN1"}, {"ASI1RIN", NULL, "DIN1"}, @@ -1428,18 +1419,15 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { {"Right DAC", "NULL", "DAC MiniDSP IN3 Route"}, /* Mixer Amplifier */ + {"MA Left PGA Mixer", "IN1 Left Capture Switch", "IN1 Left Capture"}, + {"MA Left PGA Mixer", "Left MicPGA Volume", "Left MicPGA"}, - {"MAL PGA Mixer", "IN1L Switch", "IN1L"}, - {"MAL PGA Mixer", "Left MicPGA Volume", "Left MicPGA"}, - - {"MAL PGA", NULL, "MAL PGA Mixer"}, - + {"MA Left Playback PGA", NULL, "MA Left PGA Mixer"}, - {"MAR PGA Mixer", "IN1R Switch", "IN1R"}, - {"MAR PGA Mixer", "Right MicPGA Volume", "Right MicPGA"}, - - {"MAR PGA", NULL, "MAR PGA Mixer"}, + {"MA Right PGA Mixer", "IN1 Right Capture Switch", "IN1 Right Capture"}, + {"MA Right PGA Mixer", "Right MicPGA Volume", "Right MicPGA"}, + {"MA Right Playback PGA", NULL, "MA Right PGA Mixer"}, /* Virtual connection between DAC and ADC for miniDSP IPC */ {"ADC DAC Route", "On", "Left ADC"}, @@ -1450,46 +1438,44 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { /* Capture (ADC) portions */ /* Left Positive PGA input */ - {"Left Input Mixer", "IN1L Switch", "IN1L"}, - {"Left Input Mixer", "IN2L Switch", "IN2L"}, - {"Left Input Mixer", "IN3L Switch", "IN3L"}, - {"Left Input Mixer", "IN4L Switch", "IN4L"}, - {"Left Input Mixer", "IN1R Switch", "IN1R"}, + {"Left Input Mixer", "IN1 Left Capture Switch", "IN1 Left Capture"}, + {"Left Input Mixer", "IN2 Left Capture Switch", "IN2 Left Capture"}, + {"Left Input Mixer", "IN3 Left Capture Switch", "IN3 Left Capture"}, + {"Left Input Mixer", "IN4 Left Capture Switch", "IN4 Left Capture"}, + {"Left Input Mixer", "IN1 Right Capture Switch", "IN1 Right Capture"}, /* Left Negative PGA input */ - {"Left Input Mixer", "IN2R Switch", "IN2R"}, - {"Left Input Mixer", "IN3R Switch", "IN3R"}, - {"Left Input Mixer", "IN4R Switch", "IN4R"}, - {"Left Input Mixer", "CM2L Switch", "CM2L"}, - {"Left Input Mixer", "CM1L Switch", "CM1L"}, - + {"Left Input Mixer", "IN2 Right Capture Switch", "IN2 Right Capture"}, + {"Left Input Mixer", "IN3 Right Capture Switch", "IN3 Right Capture"}, + {"Left Input Mixer", "IN4 Right Capture Switch", "IN4 Right Capture"}, + {"Left Input Mixer", "CM2 Left Capture Switch", "CM2 Left Capture"}, + {"Left Input Mixer", "CM1 Left Capture Switch", "CM1 Left Capture"}, /* Right Positive PGA Input */ - {"Right Input Mixer", "IN1R Switch", "IN1R"}, - {"Right Input Mixer", "IN2R Switch", "IN2R"}, - {"Right Input Mixer", "IN3R Switch", "IN3R"}, - {"Right Input Mixer", "IN4R Switch", "IN4R"}, - {"Right Input Mixer", "IN2L Switch", "IN2L"}, + {"Right Input Mixer", "IN1 Right Capture Switch", "IN1 Right Capture"}, + {"Right Input Mixer", "IN2 Right Capture Switch", "IN2 Right Capture"}, + {"Right Input Mixer", "IN3 Right Capture Switch", "IN3 Right Capture"}, + {"Right Input Mixer", "IN4 Right Capture Switch", "IN4 Right Capture"}, + {"Right Input Mixer", "IN2 Left Capture Switch", "IN2 Left Capture"}, /* Right Negative PGA Input */ - {"Right Input Mixer", "IN1L Switch", "IN1L"}, - {"Right Input Mixer", "IN3L Switch", "IN3L"}, - {"Right Input Mixer", "IN4L Switch", "IN4L"}, - {"Right Input Mixer", "CM1R Switch", "CM1R"}, - {"Right Input Mixer", "CM2R Switch", "CM2R"}, - + {"Right Input Mixer", "IN1 Left Capture Switch", "IN1 Left Capture"}, + {"Right Input Mixer", "IN3 Left Capture Switch", "IN3 Left Capture"}, + {"Right Input Mixer", "IN4 Left Capture Switch", "IN4 Left Capture"}, + {"Right Input Mixer", "CM1 Right Capture Switch", "CM1 Right Capture"}, + {"Right Input Mixer", "CM2 Right Capture Switch", "CM2 Right Capture"}, - {"CM1L", NULL, "CM"}, - {"CM2L", NULL, "CM"}, - {"CM1R", NULL, "CM"}, - {"CM2R", NULL, "CM"}, + {"CM1 Left Capture", NULL, "CM"}, + {"CM2 Left Capture", NULL, "CM"}, + {"CM1 Right Capture", NULL, "CM"}, + {"CM2 Right Capture", NULL, "CM"}, {"Left MicPGA", NULL, "Left Input Mixer"}, {"Right MicPGA", NULL, "Right Input Mixer"}, {"Left ADC Route", "Analog", "Left MicPGA"}, - {"Left ADC Route", "Digital", "Left DMIC"}, + {"Left ADC Route", "Digital", "Left DMIC Capture"}, {"Right ADC Route", "Analog", "Right MicPGA"}, - {"Right ADC Route", "Digital", "Right DMIC"}, + {"Right ADC Route", "Digital", "Right DMIC Capture"}, {"Left ADC", NULL, "Left ADC Route"}, {"Right ADC", NULL, "Right ADC Route"}, @@ -1555,7 +1541,7 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { * * Returns 0 for success. */ -void aic3262_firmware_load(const struct firmware *fw, void *context) +static void aic3262_firmware_load(const struct firmware *fw, void *context) { struct snd_soc_codec *codec = context; struct aic3262_priv *private_ds = snd_soc_codec_get_drvdata(codec); @@ -1569,37 +1555,35 @@ void aic3262_firmware_load(const struct firmware *fw, void *context) if (fw != NULL) { dev_dbg(codec->dev, "Firmware binary load\n"); private_ds->cur_fw = (void *)fw; - ret = aic3xxx_cfw_reload(private_ds->cfw_p, - (void *)fw->data, fw->size); - if (ret < 0) { /* reload failed */ + ret = aic3xxx_cfw_reload(private_ds->cfw_p, (void *)fw->data, + fw->size); + if (ret < 0) { /* reload failed */ dev_err(codec->dev, "Firmware binary load failed\n"); release_firmware(private_ds->cur_fw); private_ds->cur_fw = NULL; fw = NULL; - } else - private_ds->isdefault_fw = 0; + } + } else { + /* request_firmware failed*/ + /* could not locate file tlv320aic3262_fw_v1.bin + under /vendor/firmare + */ + dev_err(codec->dev, "request_firmware failed\n"); + ret = -1; } - if (fw == NULL) { - /* either request_firmware or reload failed */ - dev_dbg(codec->dev, "Default firmware load\n"); - ret = aic3xxx_cfw_reload(private_ds->cfw_p, default_firmware, - sizeof(default_firmware)); - if (ret < 0) - dev_err(codec->dev, "Default firmware load failed\n"); - else - private_ds->isdefault_fw = 1; - } aic3xxx_cfw_lock(private_ds->cfw_p, 0); if (ret >= 0) { - /* init function for transition */ + /*init function for transition */ aic3xxx_cfw_transition(private_ds->cfw_p, "INIT"); - if (!private_ds->isdefault_fw) { - aic3xxx_cfw_add_modes(codec, private_ds->cfw_p); - aic3xxx_cfw_add_controls(codec, private_ds->cfw_p); - } + /* add firmware modes */ + aic3xxx_cfw_add_modes(codec, private_ds->cfw_p); + /* add runtime controls */ + aic3xxx_cfw_add_controls(codec, private_ds->cfw_p); + /* set the default firmware mode */ aic3xxx_cfw_setmode_cfg(private_ds->cfw_p, 0, 0); } + } /*========================================================= @@ -1608,6 +1592,12 @@ void aic3262_firmware_load(const struct firmware *fw, void *context) ========================================================*/ +enum headset_accessory_state { + BIT_NO_ACCESSORY = 0, + BIT_HEADSET = (1 << 0), + BIT_HEADPHONE = (1 << 1), +}; + /** * aic3262_hs_jack_report: Report jack notication to upper layor * @codec: pointer variable to codec having information related to codec @@ -1620,28 +1610,30 @@ static void aic3262_hs_jack_report(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int report) { struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - int status, state = 0; + int status, state = 0, switch_state = BIT_NO_ACCESSORY; mutex_lock(&aic3262->mutex); /* Sync status */ status = snd_soc_read(codec, AIC3262_DAC_FLAG); - + /* We will check only stereo MIC and headphone */ switch (status & AIC3262_JACK_TYPE_MASK) { case AIC3262_JACK_WITH_MIC: state |= SND_JACK_HEADSET; break; case AIC3262_JACK_WITHOUT_MIC: state |= SND_JACK_HEADPHONE; - break; - default: - break; } mutex_unlock(&aic3262->mutex); snd_soc_jack_report(jack, state, report); + if ((state & SND_JACK_HEADSET) == SND_JACK_HEADSET) + switch_state |= BIT_HEADSET; + else if (state & SND_JACK_HEADPHONE) + switch_state |= BIT_HEADPHONE; + } /** @@ -1697,18 +1689,336 @@ static irqreturn_t aic3262_audio_handler(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t aic3262_button_handler(int irq, void *data) +/** + * Methods for CFW Operations + * + * Due to incompatibilites between structures used by MFD and CFW + * we need to transform the register format before linking to + * CFW operations. + */ +static inline unsigned int aic3262_ops_cfw2reg(unsigned int reg) +{ + union cfw_register *c = (union cfw_register *) ® + union aic3xxx_reg_union mreg; + + mreg.aic3xxx_register.offset = c->offset; + mreg.aic3xxx_register.page = c->page; + mreg.aic3xxx_register.book = c->book; + mreg.aic3xxx_register.reserved = 0; + + return mreg.aic3xxx_register_int; +} +static int aic3262_ops_reg_read(struct snd_soc_codec *codec, unsigned int reg) +{ + return aic3xxx_reg_read(codec->control_data, aic3262_ops_cfw2reg(reg)); +} + +static int aic3262_ops_reg_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned char val) { - struct snd_soc_codec *codec = data; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - input_report_key(aic3262->idev, KEY_MEDIA, 1); - mdelay(50); - input_report_key(aic3262->idev, KEY_MEDIA, 0); - input_sync(aic3262->idev); + return aic3xxx_reg_write(codec->control_data, + aic3262_ops_cfw2reg(reg), val); +} - return IRQ_HANDLED; +static int aic3262_ops_set_bits(struct snd_soc_codec *codec, unsigned int reg, + unsigned char mask, unsigned char val) +{ + return aic3xxx_set_bits(codec->control_data, + aic3262_ops_cfw2reg(reg), mask, val); + +} + +static int aic3262_ops_bulk_read(struct snd_soc_codec *codec, unsigned int reg, + int count, u8 *buf) +{ + return aic3xxx_bulk_read(codec->control_data, + aic3262_ops_cfw2reg(reg), count, buf); +} + +static int aic3262_ops_bulk_write(struct snd_soc_codec *codec, unsigned int reg, + int count, const u8 *buf) +{ + return aic3xxx_bulk_write(codec->control_data, + aic3262_ops_cfw2reg(reg), count, buf); } +/** + * aic3262_ops_dlock_lock: To Read the run state of the DAC and ADC + * by reading the codec and returning the run state + * @pv: pointer argument to the codec + * + * Run state Bit format + * + * ------------------------------------------------------ + * D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 | + * R R R LADC RADC R R LDAC RDAC + * ------------------------------------------------------ + * + * R- Reserved + * LDAC- Left DAC + * RDAC- Right DAC + * + * Return value : Integer + */ +static int aic3262_ops_lock(struct snd_soc_codec *codec) +{ + mutex_lock(&codec->mutex); + + /* Reading the run state of adc and dac */ + return aic3262_get_runstate(codec); + +} + +/** + * aic3262_ops_dlock_unlock: To unlock the mutex acqiured for reading + * run state of the codec + * @pv: pointer argument to the codec + * + * Return Value: integer returning 0 + */ +static int aic3262_ops_unlock(struct snd_soc_codec *codec) +{ + /*Releasing the lock of mutex */ + mutex_unlock(&codec->mutex); + return 0; +} + +/** + * aic3262_ops_dlock_stop: + * @pv: pointer Argument to the codec + * @mask: tells us the bit format of the codec running state + * + * Bit Format: + * ------------------------------------------------------ + * D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 | + * R R R AL AR R R DL DR + * ------------------------------------------------------ + * R - Reserved + * A - minidsp_A + * D - minidsp_D + * + * Return: return run state + */ +static int aic3262_ops_stop(struct snd_soc_codec *codec, int mask) +{ + int run_state = 0; + + run_state = aic3262_get_runstate(codec); + + if (mask & AIC3XXX_COPS_MDSP_A) + aic3xxx_set_bits(codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0xC0, 0); + + if (mask & AIC3XXX_COPS_MDSP_D) + aic3xxx_set_bits(codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0xC0, 0); + + if ((mask & AIC3XXX_COPS_MDSP_A) && + !aic3xxx_wait_bits(codec->control_data, + AIC3262_ADC_FLAG, AIC3262_ADC_POWER_MASK, + 0, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER)) + goto err; + + if ((mask & AIC3XXX_COPS_MDSP_D) && + !aic3xxx_wait_bits(codec->control_data, + AIC3262_DAC_FLAG, AIC3262_DAC_POWER_MASK, + 0, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER)) + goto err; + + return run_state; +err: + dev_err(codec->dev, "Unable to turn off ADCs or DACs at [%s:%d]", + __FILE__, __LINE__); + return -EINVAL; +} + +/** + * aic3262_ops_dlock_restore: To unlock the mutex acqiured for reading + * @pv: pointer argument to the codec,run_state + * @run_state: run state of the codec and to restore the states of the dsp + * + * Return Value : integer returning 0 + */ + +static int aic3262_ops_restore(struct snd_soc_codec *codec, int run_state) +{ + int sync_state; + + /* This is for read the sync mode register state */ + sync_state = aic3xxx_reg_read(codec->control_data, AIC3262_DAC_PRB); + + /*checking whether the sync mode has been set or + not and checking the current state */ + if (((run_state & 0x30) && (run_state & 0x03)) && (sync_state & 0x80)) + aic3262_restart_dsps_sync(codec, run_state); + else + aic3262_dsp_pwrup(codec, run_state); + + return 0; +} + +/** + * aic3262_ops_adaptivebuffer_swap: To swap the coefficient buffers + * of minidsp according to mask + * @pv: pointer argument to the codec, + * @mask: tells us which dsp has to be chosen for swapping + * + * Return Value : returning 0 on success + */ +int aic3262_ops_adaptivebuffer_swap(struct snd_soc_codec *codec, int mask) +{ + const int sbuf[][2] = { + { AIC3XXX_ABUF_MDSP_A, AIC3262_ADC_ADAPTIVE_CRAM_REG }, + { AIC3XXX_ABUF_MDSP_D1, AIC3262_DAC_ADAPTIVE_BANK1_REG }, + { AIC3XXX_ABUF_MDSP_D2, AIC3262_DAC_ADAPTIVE_BANK2_REG }, + }; + int i; + + for (i = 0; i < sizeof(sbuf)/sizeof(sbuf[0]); ++i) { + if (!(mask & sbuf[i][0])) + continue; + aic3xxx_set_bits(codec->control_data, sbuf[i][1], 0x1, 0x1); + if (!aic3xxx_wait_bits(codec->control_data, + sbuf[i][1], 0x1, 0, 15, 1)) + goto err; + } + return 0; +err: + dev_err(codec->dev, "miniDSP buffer swap failure at [%s:%d]", + __FILE__, __LINE__); + return -EINVAL; +} + +/** + * get_runstate: To read the current state of the dac's and adc's + * @ps: pointer argument to the codec + * + * Return Value : returning the runstate + */ +static int aic3262_get_runstate(struct snd_soc_codec *codec) +{ + unsigned int dac, adc; + /* Read the run state */ + dac = aic3xxx_reg_read(codec->control_data, AIC3262_DAC_FLAG); + adc = aic3xxx_reg_read(codec->control_data, AIC3262_ADC_FLAG); + + return (((adc>>6)&1)<<5) | + (((adc>>2)&1)<<4) | + (((dac>>7)&1)<<1) | + (((dac>>3)&1)<<0); +} + +/** + * aic3262_dsp_pwrdwn_status: To read the status of dsp's + * @pv: pointer argument to the codec , cur_state of dac's and adc's + * + * Return Value : integer returning 0 + */ +static int aic3262_dsp_pwrdwn_status(struct snd_soc_codec *codec) +{ + + aic3xxx_set_bits(codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0XC0, 0); + aic3xxx_set_bits(codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0XC0, 0); + + if (!aic3xxx_wait_bits(codec->control_data, AIC3262_ADC_FLAG, + AIC3262_ADC_POWER_MASK, 0, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER)) + goto err; + if (!aic3xxx_wait_bits(codec->control_data, AIC3262_DAC_FLAG, + AIC3262_DAC_POWER_MASK, 0, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER)) + goto err; + + return 0; +err: + dev_err(codec->dev, "DAC/ADC Power down timedout at [%s:%d]", + __FILE__, __LINE__); + return -EINVAL; +} +static int aic3262_dsp_pwrup(struct snd_soc_codec *codec, int state) +{ + int adc_reg_mask = 0; + int adc_power_mask = 0; + int dac_reg_mask = 0; + int dac_power_mask = 0; + int ret_wbits; + + if (state & AIC3XXX_COPS_MDSP_A_L) { + adc_reg_mask |= 0x80; + adc_power_mask |= AIC3262_LADC_POWER_MASK; + } + if (state & AIC3XXX_COPS_MDSP_A_R) { + adc_reg_mask |= 0x40; + adc_power_mask |= AIC3262_RADC_POWER_MASK; + } + + if (state & AIC3XXX_COPS_MDSP_A) + aic3xxx_set_bits(codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0XC0, + adc_reg_mask); + + if (state & AIC3XXX_COPS_MDSP_D_L) { + dac_reg_mask |= 0x80; + dac_power_mask |= AIC3262_LDAC_POWER_STATUS_MASK; + } + if (state & AIC3XXX_COPS_MDSP_D_R) { + dac_reg_mask |= 0x40; + dac_power_mask |= AIC3262_RDAC_POWER_STATUS_MASK; + } + + if (state & AIC3XXX_COPS_MDSP_D) + aic3xxx_set_bits(codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0XC0, + dac_reg_mask); + + if (state & AIC3XXX_COPS_MDSP_A) { + ret_wbits = aic3xxx_wait_bits(codec->control_data, + AIC3262_ADC_FLAG, AIC3262_ADC_POWER_MASK, + adc_power_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); + if (!ret_wbits) + dev_err(codec->dev, "ADC Power down timedout\n"); + } + + if (state & AIC3XXX_COPS_MDSP_D) { + ret_wbits = aic3xxx_wait_bits(codec->control_data, + AIC3262_DAC_FLAG, AIC3262_DAC_POWER_MASK, + dac_power_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); + if (!ret_wbits) + dev_err(codec->dev, "ADC Power down timedout\n"); + } + + return 0; +} + +static int aic3262_restart_dsps_sync(struct snd_soc_codec *codec, int run_state) +{ + + aic3262_dsp_pwrdwn_status(codec); + aic3262_dsp_pwrup(codec, run_state); + + return 0; +} + +static const struct aic3xxx_codec_ops aic3262_cfw_codec_ops = { + .reg_read = aic3262_ops_reg_read, + .reg_write = aic3262_ops_reg_write, + .set_bits = aic3262_ops_set_bits, + .bulk_read = aic3262_ops_bulk_read, + .bulk_write = aic3262_ops_bulk_write, + .lock = aic3262_ops_lock, + .unlock = aic3262_ops_unlock, + .stop = aic3262_ops_stop, + .restore = aic3262_ops_restore, + .bswap = aic3262_ops_adaptivebuffer_swap, +}; + + /** * aic3262_codec_read: provide read api to read aic3262 registe space * @codec: pointer variable to codec having codec information, @@ -1721,11 +2031,11 @@ unsigned int aic3262_codec_read(struct snd_soc_codec *codec, unsigned int reg) u8 value; - union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) ® - value = aic3262_reg_read(codec->control_data, reg); + union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) ® + value = aic3xxx_reg_read(codec->control_data, reg); dev_dbg(codec->dev, "p %d , r 30 %x %x\n", - aic_reg->aic326x_register.page, - aic_reg->aic326x_register.offset, value); + aic_reg->aic3xxx_register.page, + aic_reg->aic3xxx_register.offset, value); return value; } @@ -1740,40 +2050,11 @@ unsigned int aic3262_codec_read(struct snd_soc_codec *codec, unsigned int reg) int aic3262_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) ® + union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) ® dev_dbg(codec->dev, "p %d, w 30 %x %x\n", - aic_reg->aic326x_register.page, - aic_reg->aic326x_register.offset, value); - return aic3262_reg_write(codec->control_data, reg, value); -} - -/** - * aic3262_add_widget: This function is to add the dapm widgets - * The following are the main widgets supported - * # Left DAC to Left Outputs - * # Right DAC to Right Outputs - * # Left Inputs to Left ADC - * # Right Inputs to Right ADC - * @codec: pointer variable to codec having informaton related to codec, - * - * Return: return 0 on success. - */ -static int aic3262_add_widgets(struct snd_soc_codec *codec) -{ - - snd_soc_dapm_new_controls(&codec->dapm, aic3262_dapm_widgets, - ARRAY_SIZE(aic3262_dapm_widgets)); - /* set up audio path interconnects */ - dev_dbg(codec->dev, "#Completed adding new dapm widget" - " controls size=%d\n", ARRAY_SIZE(aic3262_dapm_widgets)); - - snd_soc_dapm_add_routes(&codec->dapm, aic3262_dapm_routes, - ARRAY_SIZE(aic3262_dapm_routes)); - dev_dbg(codec->dev, "#Completed adding DAPM routes\n"); - snd_soc_dapm_new_widgets(&codec->dapm); - dev_dbg(codec->dev, "#Completed updating dapm\n"); - - return 0; + aic_reg->aic3xxx_register.page, + aic_reg->aic3xxx_register.offset, value); + return aic3xxx_reg_write(codec->control_data, reg, value); } /** @@ -1785,7 +2066,7 @@ static int aic3262_add_widgets(struct snd_soc_codec *codec) * Return: On success return 0. */ static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, - unsigned int channel) + unsigned int channel) { int aif_interface_reg; int aif_bclk_offset_reg; @@ -1816,19 +2097,14 @@ static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, iface_val = 0; break; case SND_SOC_DAIFMT_DSP_A: - dsp_a_val = 0x1; /* Intentionally falling back - to following case */ + dsp_a_val = 0x1; /* Intentionally falling through */ case SND_SOC_DAIFMT_DSP_B: - switch (channel) { - case 1: + if (channel == 1) iface_val = 0x80; /* Choose mono PCM */ - break; - case 2: - iface_val = 0x20; - break; - default: + else if (channel <= 8) + iface_val = 0x20; /* choose multichannel PCM */ + else return -EINVAL; - } break; case SND_SOC_DAIFMT_RIGHT_J: iface_val = 0x40; @@ -1841,9 +2117,9 @@ static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, return -EINVAL; } snd_soc_update_bits(codec, aif_interface_reg, - AIC3262_ASI_INTERFACE_MASK, iface_val); + AIC3262_ASI_INTERFACE_MASK, iface_val); snd_soc_update_bits(codec, aif_bclk_offset_reg, - AIC3262_BCLK_OFFSET_MASK, dsp_a_val); + AIC3262_BCLK_OFFSET_MASK, dsp_a_val); return 0; } @@ -1860,13 +2136,15 @@ static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, * Return: Return 0 on success. */ int aic3262_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - int asi_reg; - u8 data = 0; + int asi_reg, ret = 0; + u8 data = 0, value = 0, val = 0, wclk_div = 0, bclk_div = 0; + unsigned int channels = params_channels(params); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) aic3262->stream_status = 1; @@ -1902,11 +2180,52 @@ int aic3262_hw_params(struct snd_pcm_substream *substream, break; } + /* Configure TDM for multi chennels */ + switch (channels) { + case 4: + value = value | 0x40; + bclk_div = 0x03; + wclk_div = 0x40; + break; + case 6: + bclk_div = 0x02; + wclk_div = 0x60; + value = value | 0x80; + break; + case 8: + bclk_div = 0x01; + wclk_div = 0x00; + value = value | 0xC0; + break; + default: + bclk_div = 0x04; + wclk_div = 0x20; + } + + snd_soc_update_bits(codec, AIC3262_ASI1_CHNL_SETUP, + AIC3262_ASI1_CHNL_MASK, value); + + snd_soc_update_bits(codec, AIC3262_ASI1_BCLK_N, + AIC3262_ASI1_BCLK_N_MASK, bclk_div); + + snd_soc_update_bits(codec, AIC3262_ASI1_WCLK_N, + AIC3262_ASI1_WCLK_N_MASK, wclk_div); + + + val = snd_soc_read(codec, AIC3262_ASI1_BUS_FMT); + val = snd_soc_read(codec, AIC3262_ASI1_CHNL_SETUP); + /* configure the respective Registers for the above configuration */ snd_soc_update_bits(codec, asi_reg, AIC3262_ASI_DATA_WORD_LENGTH_MASK, data); - return aic3262_set_interface_fmt(dai, aic3262->asi_fmt[dai->id], - params_channels(params)); + ret = aic3262_set_interface_fmt(dai, aic3262->asi_fmt[dai->id], + channels); + if (ret < 0) { + dev_err(codec->dev, "failed to set hardware params for AIC3262\n"); + return ret; + } + + return 0; } /** @@ -1947,50 +2266,6 @@ static int aic3262_mute(struct snd_soc_dai *dai, int mute) return 0; } -/** - * aic3262_set_dai_sysclk: This function is to set the DAI system clock - * @codec_dai: ponter to dai Holds runtime data for a DAI, - * @freq: system clock to be set, - * @dir: integer dir, - * - * Return: return 0 on success. - */ -static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct aic3262_priv *aic3262; - struct snd_soc_codec *codec; - - codec = codec_dai->codec; - aic3262 = snd_soc_codec_get_drvdata(codec); - switch (freq) { - case AIC3262_FREQ_12000000: - aic3262->sysclk = freq; - return 0; - case AIC3262_FREQ_24000000: - aic3262->sysclk = freq; - return 0; - break; - case AIC3262_FREQ_19200000: - aic3262->sysclk = freq; - return 0; - break; - case AIC3262_FREQ_38400000: - aic3262->sysclk = freq; - dev_dbg(codec->dev, "codec: sysclk = %d\n", aic3262->sysclk); - return 0; - break; - case AIC3262_FREQ_12288000: - aic3262->sysclk = freq; - dev_dbg(codec->dev, "codec: sysclk = %d\n", aic3262->sysclk); - return 0; - break; - - } - dev_err(codec->dev, "Invalid frequency to set DAI system clock\n"); - - return -EINVAL; -} /** * aic3262_set_dai_fmt: This function is to set the DAI format @@ -2035,7 +2310,7 @@ static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) case SND_SOC_DAIFMT_CBS_CFS: aic3262->master = 0; break; - case SND_SOC_DAIFMT_CBS_CFM: /* new case..just for debugging */ + case SND_SOC_DAIFMT_CBS_CFM: /* new case..for debug purpose */ master |= (AIC3262_WCLK_OUT_MASK); aic3262->master = 0; break; @@ -2108,6 +2383,7 @@ static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, /* TODO: How to select low/high clock range? */ aic3xxx_cfw_set_pll(aic3262->cfw_p, dai->id); + return 0; } @@ -2144,6 +2420,7 @@ static int aic3262_set_bias_level(struct snd_soc_codec *codec, */ dev_dbg(codec->dev, "set_bias_stby\n"); if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + pm_runtime_get_sync(codec->dev); snd_soc_update_bits(codec, AIC3262_POWER_CONF, (AIC3262_AVDD_TO_DVDD_MASK | AIC3262_EXT_ANALOG_SUPPLY_MASK), @@ -2152,21 +2429,26 @@ static int aic3262_set_bias_level(struct snd_soc_codec *codec, AIC3262_CHIP_REF_PWR_ON_MASK, AIC3262_CHIP_REF_PWR_ON); mdelay(40); - } + snd_soc_update_bits(codec, AIC3262_CHARGE_PUMP_CNTL, + AIC3262_DYNAMIC_OFFSET_CALIB_MASK, + AIC3262_DYNAMIC_OFFSET_CALIB); + } break; /* Off, without power */ case SND_SOC_BIAS_OFF: dev_dbg(codec->dev, "set_bias_off\n"); + /* force all power off */ if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY, - AIC3262_CHIP_REF_PWR_ON_MASK, 0x0); + AIC3262_CHIP_REF_PWR_ON_MASK, 0x0); snd_soc_update_bits(codec, AIC3262_POWER_CONF, - (AIC3262_AVDD_TO_DVDD_MASK | - AIC3262_EXT_ANALOG_SUPPLY_MASK), - (AIC3262_AVDD_TO_DVDD | - AIC3262_EXT_ANALOG_SUPPLY_OFF)); + (AIC3262_AVDD_TO_DVDD_MASK | + AIC3262_EXT_ANALOG_SUPPLY_MASK), + (AIC3262_AVDD_TO_DVDD | + AIC3262_EXT_ANALOG_SUPPLY_OFF)); + pm_runtime_put(codec->dev); } break; } @@ -2175,25 +2457,25 @@ static int aic3262_set_bias_level(struct snd_soc_codec *codec, return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_suspend - * Purpose : This function is to suspend the AIC3262 driver. +/** * - *---------------------------------------------------------------------------- + * aic3262_suspend; This function is to suspend the AIC3262 driver. + * @codec: pointer variable to codec having informaton related to codec, + * + * Return: Return 0 on success. */ -static int aic3262_suspend(struct snd_soc_codec *codec, pm_message_t state) +static int aic3262_suspend(struct snd_soc_codec *codec) { aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_resume - * Purpose : This function is to resume the AIC3262 driver +/** + * aic3262_resume: This function is to resume the AIC3262 driver + * from off state to standby + * @codec: pointer variable to codec having informaton related to codec, * - *---------------------------------------------------------------------------- + * Return: Return 0 on success. */ static int aic3262_resume(struct snd_soc_codec *codec) { @@ -2202,20 +2484,17 @@ static int aic3262_resume(struct snd_soc_codec *codec) return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_probe - * Purpose : This is first driver function called by the SoC core driver. +/** + * aic3262_probe: This is first driver function called by the SoC core driver. + * @codec: pointer variable to codec having informaton related to codec, * - *---------------------------------------------------------------------------- + * Return: Return 0 on success. */ static int aic3262_codec_probe(struct snd_soc_codec *codec) { int ret = 0; - int ret_btn = 0; - struct aic3262 *control; + struct aic3xxx *control; struct aic3262_priv *aic3262; - struct aic3262_jack_data *jack; if (codec == NULL) dev_err(codec->dev, "codec pointer is NULL.\n"); @@ -2230,56 +2509,37 @@ static int aic3262_codec_probe(struct snd_soc_codec *codec) aic3262->pdata = dev_get_platdata(codec->dev->parent); aic3262->codec = codec; aic3262->cur_fw = NULL; - aic3262->isdefault_fw = 0; aic3262->cfw_p = &(aic3262->cfw_ps); - aic3xxx_cfw_init(aic3262->cfw_p, &aic3262_cfw_codec_ops, aic3262); + aic3xxx_cfw_init(aic3262->cfw_p, &aic3262_cfw_codec_ops, + aic3262->codec); aic3262->workqueue = create_singlethread_workqueue("aic3262-codec"); if (!aic3262->workqueue) { ret = -ENOMEM; goto work_err; } - ret = device_create_file(codec->dev, &dev_attr_debug_level); - if (ret) - dev_info(codec->dev, "Failed to add debug_level sysfs\n"); INIT_DELAYED_WORK(&aic3262->delayed_work, aic3262_accessory_work); mutex_init(&aic3262->mutex); mutex_init(&codec->mutex); mutex_init(&aic3262->cfw_mutex); - aic3262->dsp_runstate = 0; - /* use switch-class based headset reporting if platform requires it */ - jack = &aic3262->hs_jack; - aic3262->idev = input_allocate_device(); - if (aic3262->idev <= 0) - printk(KERN_ERR, "Allocate failed\n"); - - input_set_capability(aic3262->idev, EV_KEY, KEY_MEDIA); - ret = input_register_device(aic3262->idev); - if (ret < 0) { - dev_err(codec->dev, "register input dev fail\n"); - goto input_dev_err; - } + pm_runtime_enable(codec->dev); + pm_runtime_resume(codec->dev); + aic3262->dsp_runstate = 0; if (control->irq) { - ret = aic3262_request_irq(codec->control_data, - AIC3262_IRQ_HEADSET_DETECT, - aic3262_audio_handler, 0, - "aic3262_irq_headset", codec); + ret = aic3xxx_request_irq(codec->control_data, + AIC3262_IRQ_HEADSET_DETECT, + aic3262_audio_handler, + IRQF_NO_SUSPEND, + "aic3262_irq_headset", codec); - if (ret) { + if (ret) { dev_err(codec->dev, "HEADSET detect irq request" "failed: %d\n", ret); goto irq_err; - } - - ret = aic3262_request_irq(codec->control_data, - AIC3262_IRQ_BUTTON_PRESS, - aic3262_button_handler, 0, "aic3262_irq_button", - codec); - - if (ret) { - dev_err(codec->dev, "button press irq request" - "failed: %d\n", ret); - goto irq_err; + } else { + /* Dynamic Headset Detection Enabled */ + snd_soc_update_bits(codec, AIC3262_HP_DETECT, + AIC3262_HEADSET_IN_MASK, AIC3262_HEADSET_IN_MASK); } } /* Keep the reference voltage ON while in$ @@ -2289,74 +2549,63 @@ static int aic3262_codec_probe(struct snd_soc_codec *codec) AIC3262_CHIP_REF_PWR_ON_MASK, AIC3262_CHIP_REF_PWR_ON); mdelay(40); - aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = snd_soc_add_codec_controls(codec, aic3262_snd_controls, - ARRAY_SIZE(aic3262_snd_controls)); - if(ret) - { - printk(KERN_INFO "%s failed\n", __func__); - } + snd_soc_update_bits(codec, AIC3262_CHARGE_PUMP_CNTL, + AIC3262_DYNAMIC_OFFSET_CALIB_MASK, + AIC3262_DYNAMIC_OFFSET_CALIB); - aic3262->mute_asi = 0; + aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - aic3262_add_widgets(codec); + aic3262->mute_asi = 0; -#ifdef AIC3262_TiLoad - ret = aic3262_driver_init(codec); - if (ret < 0) - dev_err(codec->dev, "\nTiLoad Initialization failed\n"); -#endif - /* force loading the default firmware */ - aic3262_firmware_load(NULL, codec); - request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "tlv320aic3262_fw_v1.bin", codec->dev, GFP_KERNEL, codec, aic3262_firmware_load); + if (ret < 0) { + dev_err(codec->dev, "Firmware request failed\n"); + goto firm_err; + } return 0; +firm_err: + aic3xxx_free_irq(control, + AIC3262_IRQ_HEADSET_DETECT, codec); irq_err: - input_unregister_device(aic3262->idev); - input_free_device(aic3262->idev); -input_dev_err: -reg_err: + destroy_workqueue(aic3262->workqueue); work_err: kfree(aic3262); return 0; } /* -* aic3262_remove: Cleans up and Remove aic3262 soc device -* @codec: pointer variable to codec having informaton related to codec, -* -* Return: Return 0 on success. -*/ + * aic3262_remove: Cleans up and Remove aic3262 soc device + * @codec: pointer variable to codec having informaton related to codec, + * + * Return: Return 0 on success. + */ static int aic3262_codec_remove(struct snd_soc_codec *codec) { /* power down chip */ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - struct aic3262 *control = codec->control_data; - struct aic3262_jack_data *jack = &aic3262->hs_jack; + struct aic3xxx *control = codec->control_data; aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF); /* free_irq if any */ switch (control->type) { case TLV320AIC3262: - if (control->irq) { - aic3262_free_irq(control, AIC3262_IRQ_HEADSET_DETECT, - codec); - aic3262_free_irq(control, AIC3262_IRQ_BUTTON_PRESS, - codec); - } + if (control->irq) + aic3xxx_free_irq(control, + AIC3262_IRQ_HEADSET_DETECT, codec); break; + default: + dev_info(codec->dev, "Coded is not TLV320AIC3262\n"); } /* release firmware if any */ if (aic3262->cur_fw != NULL) release_firmware(aic3262->cur_fw); /* destroy workqueue for jac dev */ destroy_workqueue(aic3262->workqueue); - input_unregister_device(aic3262->idev); - input_free_device(aic3262->idev); kfree(aic3262); @@ -2370,6 +2619,12 @@ static struct snd_soc_codec_driver soc_codec_driver_aic326x = { .resume = aic3262_resume, .read = aic3262_codec_read, .write = aic3262_codec_write, + .controls = aic3262_snd_controls, + .num_controls = ARRAY_SIZE(aic3262_snd_controls), + .dapm_widgets = aic3262_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aic3262_dapm_widgets), + .dapm_routes = aic3262_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(aic3262_dapm_routes), .set_bias_level = aic3262_set_bias_level, .reg_cache_size = 0, .reg_word_size = sizeof(u8), @@ -2390,42 +2645,31 @@ static int aic326x_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id aic3262_of_match[] = { + { .compatible = "ti,aic3262", }, + { }, +}; +MODULE_DEVICE_TABLE(of, aic3262_of_match); + +static const struct platform_device_id aic3262_i2c_id[] = { + { "tlv320aic3262-codec", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aic3262_i2c_id); + static struct platform_driver aic326x_codec_driver = { .driver = { - .name = "tlv320aic3262-codec", - .owner = THIS_MODULE, - }, + .name = "tlv320aic3262-codec", + .owner = THIS_MODULE, + .of_match_table = aic3262_of_match, + }, .probe = aic326x_probe, .remove = __devexit_p(aic326x_remove), + .id_table = aic3262_i2c_id, }; -/* -*---------------------------------------------------------------------------- -* Function : tlv320aic3262_modinit -* Purpose : module init function. First function to run. -* -*---------------------------------------------------------------------------- -*/ -static int __init tlv320aic3262_modinit(void) -{ - return platform_driver_register(&aic326x_codec_driver); -} -module_init(tlv320aic3262_modinit); - -/* -*---------------------------------------------------------------------------- -* Function : tlv320aic3262_exit -* Purpose : module init function. First function to run. -* -*---------------------------------------------------------------------------- -*/ -static void __exit tlv320aic3262_exit(void) -{ - platform_driver_unregister(&aic326x_codec_driver); - -} +module_platform_driver(aic326x_codec_driver); -module_exit(tlv320aic3262_exit); MODULE_ALIAS("platform:tlv320aic3262-codec"); MODULE_DESCRIPTION("ASoC TLV320AIC3262 codec driver"); MODULE_AUTHOR("Y Preetam Sashank Reddy "); diff --git a/sound/soc/codecs/tlv320aic326x.h b/sound/soc/codecs/tlv320aic326x.h index 4a7d909cea74..de56bd9b396b 100644 --- a/sound/soc/codecs/tlv320aic326x.h +++ b/sound/soc/codecs/tlv320aic326x.h @@ -28,21 +28,16 @@ #ifndef _TLV320AIC3262_H #define _TLV320AIC3262_H -#include "aic3xxx_cfw.h" -#include "aic3xxx_cfw_ops.h" -#include +#include "aic3xxx/aic3xxx_cfw.h" +#include "aic3xxx/aic3xxx_cfw_ops.h" #define AUDIO_NAME "aic3262" #define AIC3262_VERSION "1.1" /* Macro to enable the inclusion of tiload kernel driver */ #define AIC3262_TiLoad #undef AIC3262_SYNC_MODE - -/* #define AIC3262_ASI1_MASTER */ #undef AIC3262_ASI1_MASTER -/* #define AIC3262_ASI2_MASTER */ #undef AIC3262_ASI2_MASTER -/* #define AIC3262_ASI3_MASTER */ #undef AIC3262_ASI3_MASTER /* Macro for McBsp master / slave configuration */ #define AIC3262_MCBSP_SLAVE /*3262 master */ @@ -63,7 +58,6 @@ #define AIC3262_FREQ_19200000 19200000 #define AIC3262_FREQ_24000000 24000000 #define AIC3262_FREQ_38400000 38400000 -#define AIC3262_FREQ_12288000 12288000 /* Audio data word length = 16-bits (default setting) */ #define AIC3262_WORD_LEN_16BITS 0x00 #define AIC3262_WORD_LEN_20BITS 0x01 @@ -103,19 +97,12 @@ /* Updated from 256 to support Page 3 registers */ #define AIC3262_CACHEREGNUM 1024 -#define DSP_NON_SYNC_MODE(state) (!((state & 0x03) && (state & 0x30))) - -#define TIME_DELAY 5 -#define DELAY_COUNTER 100 - -#ifdef AIC3262_TiLoad -int aic3262_driver_init(struct snd_soc_codec *codec); -#endif +#define AIC326X_TIME_DELAY 5 +#define AIC326X_DELAY_COUNTER 100 struct aic3262_jack_data { struct snd_soc_jack *jack; int report; - struct switch_dev sdev; }; struct aic3262_priv { @@ -139,60 +126,10 @@ struct aic3262_priv { int isdefault_fw; }; -/* - *---------------------------------------------------------------------------- - * @struct aic3262_rate_divs | - * Setting up the values to get different freqencies - * - * @field u32 | mclk | - * Master clock - * @field u32 | rate | - * sample rate - * @field u8 | p_val | - * value of p in PLL - * @field u32 | pll_j | - * value for pll_j - * @field u32 | pll_d | - * value for pll_d - * @field u32 | dosr | - * value to store dosr - * @field u32 | ndac | - * value for ndac - * @field u32 | mdac | - * value for mdac - * @field u32 | aosr | - * value for aosr - * @field u32 | nadc | - * value for nadc - * @field u32 | madc | - * value for madc - * @field u32 | blck_N | - * value for block N - *---------------------------------------------------------------------------- - */ -struct aic3262_rate_divs { - u32 mclk; - u32 rate; - u8 p_val; - u8 pll_j; - u16 pll_d; - u16 dosr; - u8 ndac; - u8 mdac; - u8 aosr; - u8 nadc; - u8 madc; - u8 blck_N; -}; - extern struct snd_soc_dai tlv320aic3262_dai; -extern struct snd_soc_codec_device soc_codec_dev_aic3262; -extern const struct aic3xxx_codec_ops aic3262_cfw_codec_ops; void aic3262_hs_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int report); -unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg); -int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value); + #endif /* _TLV320AIC3262_H */ -- cgit v1.2.3