summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorManoj Gangwal <mgangwal@nvidia.com>2012-11-22 11:42:15 +0530
committerSimone Willett <swillett@nvidia.com>2012-11-29 16:26:05 -0800
commit3ec0b02088b6a46a0c29515b81ac05ed620721a0 (patch)
treebfa008acae9117bfe7b7d4f4c85ceaf2eafe31d3 /sound
parent9ec138ea7ed1129deac05cc1138389b973e4056a (diff)
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 <mgangwal@nvidia.com> Reviewed-on: http://git-master/r/165611 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Vijay Mali <vmali@nvidia.com> Reviewed-by: Scott Peterson <speterson@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/Kconfig1
-rw-r--r--sound/soc/codecs/Makefile3
-rw-r--r--sound/soc/codecs/aic3xxx/aic3xxx_cfw.h529
-rw-r--r--sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.c1133
-rw-r--r--sound/soc/codecs/aic3xxx/aic3xxx_cfw_ops.h95
-rw-r--r--sound/soc/codecs/aic3xxx_cfw.h427
-rw-r--r--sound/soc/codecs/aic3xxx_cfw_ops.c918
-rw-r--r--sound/soc/codecs/aic3xxx_cfw_ops.h76
-rw-r--r--sound/soc/codecs/tlv320aic326x.c1494
-rw-r--r--sound/soc/codecs/tlv320aic326x.h73
10 files changed, 2633 insertions, 2116 deletions
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) /**<Max length of string identifies*/
+# define CFW_MAX_VARS (256) /**<Number of "variables" alive at the*/
+ /**<same time in an acx file*/
+#endif
+
+/* @} */
+
+
+
+/** \defgroup st Enums, Flags, Macros and Supporting Types */
+/* @{ */
+
+
+/**
+ * Device Family Identifier
+ *
+ */
+enum __attribute__ ((__packed__)) cfw_dfamily {
+ CFW_DFM_TYPE_A,
+ CFW_DFM_TYPE_B,
+ CFW_DFM_TYPE_C
+};
+
+/**
+ * Device Identifier
+ *
+ */
+enum __attribute__ ((__packed__)) cfw_device {
+ CFW_DEV_DAC3120,
+ CFW_DEV_DAC3100,
+ CFW_DEV_AIC3120,
+ CFW_DEV_AIC3100,
+ CFW_DEV_AIC3110,
+ CFW_DEV_AIC3111,
+ CFW_DEV_AIC36,
+ CFW_DEV_AIC3206,
+ CFW_DEV_AIC3204,
+ CFW_DEV_AIC3254,
+ CFW_DEV_AIC3256,
+ CFW_DEV_AIC3253,
+ CFW_DEV_AIC3212,
+ CFW_DEV_AIC3262,
+ CFW_DEV_AIC3017,
+ CFW_DEV_AIC3008,
+
+ CFW_DEV_AIC3266,
+ CFW_DEV_AIC3285,
+};
+
+/**
+ * Transition Sequence Identifier
+ *
+ */
+enum cfw_transition_t {
+ CFW_TRN_INIT,
+ CFW_TRN_RESUME,
+ CFW_TRN_NEUTRAL,
+ CFW_TRN_A_MUTE,
+ CFW_TRN_D_MUTE,
+ CFW_TRN_AD_MUTE,
+ CFW_TRN_A_UNMUTE,
+ CFW_TRN_D_UNMUTE,
+ CFW_TRN_AD_UNMUTE,
+ CFW_TRN_SUSPEND,
+ CFW_TRN_EXIT,
+ CFW_TRN_N
+};
+
+#ifndef __cplusplus
+static const char *const cfw_transition_id[] = {
+ [CFW_TRN_INIT] "INIT",
+ [CFW_TRN_RESUME] "RESUME",
+ [CFW_TRN_NEUTRAL] "NEUTRAL",
+ [CFW_TRN_A_MUTE] "A_MUTE",
+ [CFW_TRN_D_MUTE] "D_MUTE",
+ [CFW_TRN_AD_MUTE] "AD_MUTE",
+ [CFW_TRN_A_UNMUTE] "A_UNMUTE",
+ [CFW_TRN_D_UNMUTE] "D_UNMUTE",
+ [CFW_TRN_AD_UNMUTE]"AD_UNMUTE",
+ [CFW_TRN_SUSPEND] "SUSPEND",
+ [CFW_TRN_EXIT] "EXIT",
+};
+#endif
+
+/* @} */
+
+/** \defgroup ds Data Structures */
+/* @{ */
+
+
+/**
+* CFW Command
+* These commands do not appear in the register
+* set of the device.
+*/
+enum __attribute__ ((__packed__)) cfw_cmd_id {
+ CFW_CMD_NOP = 0x80,
+ CFW_CMD_DELAY,
+ CFW_CMD_UPDTBITS,
+ CFW_CMD_WAITBITS,
+ CFW_CMD_LOCK,
+ CFW_CMD_BURST,
+ CFW_CMD_RBURST,
+ CFW_CMD_LOAD_VAR_IM,
+ CFW_CMD_LOAD_VAR_ID,
+ CFW_CMD_STORE_VAR,
+ CFW_CMD_COND,
+ CFW_CMD_BRANCH,
+ CFW_CMD_BRANCH_IM,
+ CFW_CMD_BRANCH_ID,
+ CFW_CMD_PRINT,
+ CFW_CMD_OP_ADD = 0xC0,
+ CFW_CMD_OP_SUB,
+ CFW_CMD_OP_MUL,
+ CFW_CMD_OP_DIV,
+ CFW_CMD_OP_AND,
+ CFW_CMD_OP_OR,
+ CFW_CMD_OP_SHL,
+ CFW_CMD_OP_SHR,
+ CFW_CMD_OP_RR,
+ CFW_CMD_OP_XOR,
+ CFW_CMD_OP_NOT,
+ CFW_CMD_OP_LNOT,
+};
+
+/**
+* CFW Delay
+* Used for the cmd command delay
+* Has one parameter of delay time in ms
+*/
+struct cfw_cmd_delay {
+ u16 delay;
+ enum cfw_cmd_id cid;
+ u8 delay_fine;
+};
+
+/**
+* CFW Lock
+* Take codec mutex to avoid clashing with DAPM operations
+*/
+struct cfw_cmd_lock {
+ u16 lock;
+ enum cfw_cmd_id cid;
+ u8 unused;
+};
+
+
+/**
+ * CFW UPDTBITS, WAITBITS, CHKBITS
+ * Both these cmd commands have same arguments
+ * cid will be used to specify which command it is
+ * has parameters of book, page, offset and mask
+ */
+struct cfw_cmd_bitop {
+ u16 unused1;
+ enum cfw_cmd_id cid;
+ u8 mask;
+};
+
+/**
+ * CFW CMD Burst header
+ * Burst writes inside command array
+ * Followed by burst address, first byte
+ */
+struct cfw_cmd_bhdr {
+ u16 len;
+ enum cfw_cmd_id cid;
+ u8 unused;
+};
+
+/**
+ * CFW CMD Burst
+ * Burst writes inside command array
+ * Followed by data to the extent indicated in previous len
+ * Can be safely cast to cfw_burst
+ */
+struct cfw_cmd_burst {
+ u8 book;
+ u8 page;
+ u8 offset;
+ u8 data[1];
+};
+#define CFW_CMD_BURST_LEN(n) (2 + ((n) - 1 + 3)/4)
+
+/**
+ * CFW CMD Scratch register
+ * For load
+ * if (svar != dvar)
+ * dvar = setbits(svar, mask) // Ignore reg
+ * else
+ * dvar = setbits(reg, mask)
+ * For store
+ * if (svar != dvar)
+ * reg = setbits(svar, dvar)
+ * else
+ * reg = setbits(svar, mask)
+ *
+ */
+struct cfw_cmd_ldst {
+ u8 dvar;
+ u8 svar;
+ enum cfw_cmd_id cid;
+ u8 mask;
+};
+
+/**
+ * CFW CMD Conditional
+ * May only precede branch. Followed by nmatch+1 jump
+ * instructions
+ * cond = svar&mask
+ * At each of the following nmatch+1 branch command
+ * if (cond == match)
+ * take the branch
+ */
+struct cfw_cmd_cond {
+ u8 svar;
+ u8 nmatch;
+ enum cfw_cmd_id cid;
+ u8 mask;
+};
+#define CFW_CMD_COND_LEN(nm) (1 + ((nm)+1))
+
+/**
+ * CFW CMD Goto
+ * For branch, break, continue and stop
+ */
+struct cfw_cmd_branch {
+ u16 address;
+ enum cfw_cmd_id cid;
+ u8 match;
+};
+
+/**
+ * CFW Debug print
+ * For diagnostics
+ */
+struct cfw_cmd_print {
+ u8 fmtlen;
+ u8 nargs;
+ enum cfw_cmd_id cid;
+ char fmt[1];
+};
+
+#define CFW_CMD_PRINT_LEN(p) (1 + ((p).fmtlen/4) + (((p).nargs + 3)/4))
+#define CFW_CMD_PRINT_ARG(p) (1 + ((p).fmtlen/4))
+
+/**
+ * CFW Arithmetic and logical operations
+ * Bit 5 indicates if op1 is indirect
+ * Bit 6 indicates if op2 is indirect
+ */
+struct cfw_cmd_op {
+ u8 op1;
+ u8 op2;
+ enum cfw_cmd_id cid;
+ u8 dst;
+};
+#define CFW_CMD_OP1_ID (1u<<5)
+#define CFW_CMD_OP2_ID (1u<<4)
+
+#define CFW_CMD_OP_START CFW_CMD_OP_ADD
+#define CFW_CMD_OP_END (CFW_CMD_OP_LNOT|CFW_CMD_OP1_ID|CFW_CMD_OP2_ID)
+#define CFW_CMD_OP_IS_UNARY(x) \
+ (((x) == CFW_CMD_OP_NOT) || ((x) == CFW_CMD_OP_LNOT))
+
+
+/**
+ * CFW Register
+ *
+ * A single reg write
+ *
+ */
+union cfw_register {
+ struct {
+ u8 book;
+ u8 page;
+ u8 offset;
+ u8 data;
+ };
+ u32 bpod;
+};
+
+
+
+/**
+ * CFW Command
+ *
+ * Can be a either a
+ * -# single register write, or
+ * -# command
+ *
+ */
+union cfw_cmd {
+ struct {
+ u16 unused1;
+ enum cfw_cmd_id cid;
+ u8 unused2;
+ };
+ union cfw_register reg;
+ struct cfw_cmd_delay delay;
+ struct cfw_cmd_lock lock;
+ struct cfw_cmd_bitop bitop;
+ struct cfw_cmd_bhdr bhdr;
+ struct cfw_cmd_burst burst;
+ struct cfw_cmd_ldst ldst;
+ struct cfw_cmd_cond cond;
+ struct cfw_cmd_branch branch;
+ struct cfw_cmd_print print;
+ u8 print_arg[4];
+ struct cfw_cmd_op op;
+};
+
+#define CFW_REG_IS_CMD(x) ((x).cid >= 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 <linux/module.h>
+#include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/slab.h>
+#include <sound/tlv.h>
+
+/* 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 <harik@ti.com>");
+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 <linux/mutex.h>
+#include <sound/soc.h>
+#include <linux/cdev.h>
+
+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 <asm-generic/int-ll64.h>
-#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
-/* <Max number of overlays per PFW */
-#ifndef CFW_MAX_NOVLY
-#define CFW_MAX_NOVLY (4)
-#endif
-
-#ifndef CFW_MAX_NCFG
-#define CFW_MAX_NCFG (16) /* Max number of configurations per PFW */
-#endif
-
-#ifndef CFW_MAX_TRANSITIONS
-#define CFW_MAX_TRANSITIONS (32) /* max number of pre-defined transition */
-#endif
-
-#ifndef CFW_MAX_NPFW
-#define CFW_MAX_NPFW (16) /* Max number fo process flows */
-#endif
-
-#ifndef CFW_MAX_MODES
-#define CFW_MAX_MODES (32) /* Max number of modes */
-#endif
-
-#ifndef CFW_MAX_ASI
-#define CFW_MAX_ASI (4) /* Max number ASIs in a single device */
-#endif
-
-
-#ifndef CFW_MAX_CTRL
-#define CFW_MAX_CTRL (16) /* Max number of control per pfw */
-#endif
-
-/** defgroup st Enums, Flags, Macros and Supporting Types */
-
-/**
- * Sample rate bitmask
- *
- */
-enum cfw_fs {
- CFW_FS_8KHZ = 0x0001u,
- CFW_FS_11KHZ = 0x0002u,
- CFW_FS_16KHZ = 0x0004u,
- CFW_FS_22KHZ = 0x0008u,
- CFW_FS_24KHZ = 0x0010u,
- CFW_FS_32KHZ = 0x0020u,
- CFW_FS_44KHZ = 0x0040u,
- CFW_FS_48KHZ = 0x0080u,
- CFW_FS_88KHZ = 0x0100u,
- CFW_FS_96KHZ = 0x0200u,
- CFW_FS_176KHZ = 0x0400u,
- CFW_FS_192KHZ = 0x0800u,
- CFW_FS_ANY = 0x8000u,
- CFW_FS_ALL = 0x0FFFu,
-};
-
-/**
- * Sample rate index
- *
- */
-enum cfw_fsi {
- CFW_FSI_8KHZ,
- CFW_FSI_11KHZ,
- CFW_FSI_16KHZ,
- CFW_FSI_22KHZ,
- CFW_FSI_24KHZ,
- CFW_FSI_32KHZ,
- CFW_FSI_44KHZ,
- CFW_FSI_48KHZ,
- CFW_FSI_88KHZ,
- CFW_FSI_96KHZ,
- CFW_FSI_176KHZ,
- CFW_FSI_192KHZ,
- CFW_FSI_ANY = 15,
-};
-
-/**
- * Device Family Identifier
- *
- */
-enum __attribute__ ((__packed__)) cfw_dfamily {
- CFW_DFM_TYPE_A,
- CFW_DFM_TYPE_B,
- CFW_DFM_TYPE_C
-};
-
-/**
- * Device Identifier
- *
- */
-enum __attribute__ ((__packed__)) cfw_device {
- CFW_DEV_DAC3120,
- CFW_DEV_DAC3100,
-
- CFW_DEV_AIC3120,
- CFW_DEV_AIC3100,
- CFW_DEV_AIC3110,
- CFW_DEV_AIC3111,
-
- CFW_DEV_AIC36,
-
- CFW_DEV_AIC3206,
- CFW_DEV_AIC3204,
- CFW_DEV_AIC3254,
- CFW_DEV_AIC3256,
- CFW_DEV_AIC3253,
-
- CFW_DEV_AIC3212,
- CFW_DEV_AIC3262,
- CFW_DEV_AIC3017,
- CFW_DEV_AIC3008,
-
-};
-
-/**
- * Transition Sequence Identifier
- *
- */
-enum cfw_transition_t {
- CFW_TRN_INIT,
- CFW_TRN_RESUME,
- CFW_TRN_NEUTRAL,
- CFW_TRN_A_MUTE,
- CFW_TRN_D_MUTE,
- CFW_TRN_AD_MUTE,
- CFW_TRN_A_UNMUTE,
- CFW_TRN_D_UNMUTE,
- CFW_TRN_AD_UNMUTE,
- CFW_TRN_SUSPEND,
- CFW_TRN_EXIT,
- CFW_TRN_N
-};
-
-static const char * const cfw_transition_id[] = {
- [CFW_TRN_INIT] "INIT",
- [CFW_TRN_RESUME] "RESUME",
- [CFW_TRN_NEUTRAL] "NEUTRAL",
- [CFW_TRN_A_MUTE] "A_MUTE",
- [CFW_TRN_D_MUTE] "D_MUTE",
- [CFW_TRN_AD_MUTE] "AD_MUTE",
- [CFW_TRN_A_UNMUTE] "A_UNMUTE",
- [CFW_TRN_D_UNMUTE] "D_UNMUTE",
- [CFW_TRN_AD_UNMUTE] "AD_UNMUTE",
- [CFW_TRN_SUSPEND] "SUSPEND",
- [CFW_TRN_EXIT] "EXIT",
-};
-
-/** defgroup ds Data Structures */
-
-/**
-* CFW Meta Command
-* These commands do not appear in the register
-* set of the device.
-* Mainly delay, wait and set_bits.
-*/
-enum __attribute__ ((__packed__)) cfw_meta_cmd {
- CFW_META_DELAY = 0x80,
- CFW_META_UPDTBITS,
- CFW_META_WAITBITS,
- CFW_META_LOCK,
-};
-
-/**
-* CFW Delay
-* Used for the meta command delay
-* Has one parameter of delay time in ms
-*/
-struct cfw_meta_delay {
- u16 delay;
- enum cfw_meta_cmd mcmd;
- u8 unused1;
-};
-
-/**
-* CFW set_bits or wait
-* Both these meta commands have same arguments
-* mcmd will be used to specify which command it is
-* has parameters of book, page, offset and mask
-*/
-struct cfw_meta_bitop {
- u16 unused1;
- enum cfw_meta_cmd mcmd;
- u8 mask;
-};
-
-/**
-* CFW meta register
-* Contains the data structures for the meta commands
-*/
-union cfw_meta_register {
- struct {
- u16 unused1;
- enum cfw_meta_cmd mcmd;
- u8 unused2;
- };
- struct cfw_meta_delay delay;
- struct cfw_meta_bitop bitop;
-};
-
-/**
- * CFW Register
- *
- * A single reg write
- *
- */
-union cfw_register {
- struct {
- u8 book;
- u8 page;
- u8 offset;
- u8 data;
- };
- u32 bpod;
- union cfw_meta_register meta;
-};
-
-/**
- * CFW Burst
- *
- * A single I2C/SPI burst write sequence
- *
- */
-struct cfw_burst {
- u32 length;
- union {
- union cfw_register reg;
- struct {
- u8 bpo[3];
- u8 data[1];
- };
- };
-};
-
-/**
- * CFW Command
- *
- * Can be a either a
- * -# single register write,
- * -# a burst write, or
- * -# meta-command
- *
- */
-union cfw_cmd {
- union cfw_register reg;
- struct cfw_burst *burst;
-};
-
-/**
- * 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,
- CFW_BLOCK_BURSTS = 0x80
-};
-#define CFW_BLOCK_BURSTS(x) ((x)&CFW_BLOCK_BURSTS)
-#define CFW_BLOCK_TYPE(x) ((x)&(~CFW_BLOCK_BURSTS))
-#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/meta-commands
- *
- */
-struct cfw_block {
- enum cfw_block_t type;
- int ncmds;
- union cfw_cmd cmd[];
-};
-
-/**
- * CFW Image
- *
- * A downloadable image
- */
-struct cfw_image {
- char name[CFW_MAX_ID]; /* Name of the pfw/overlay/configuration */
- char desc[CFW_MAX_DESC]; /* User string */
- int mute_flags;
- struct cfw_block *block[CFW_BLOCK_N];
-};
-
-struct cfw_control {
- char name[CFW_MAX_ID]; /* Control identifier */
- char desc[CFW_MAX_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[CFW_MAX_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_block *pll;
- struct cfw_image *base; /* Base sequence */
- /* Overlay and cfg */
- struct cfw_image *ovly_cfg[CFW_MAX_NOVLY][CFW_MAX_NCFG];
- /* Array of run-time controls */
- struct cfw_control *ctrl[CFW_MAX_CTRL];
-};
-
-/**
- * Process transition
- *
- * Sequence for specific state transisitions within the driver
- *
- */
-struct cfw_transition {
- char name[CFW_MAX_ID]; /* Name of the transition */
- char desc[CFW_MAX_DESC]; /* User string */
- struct cfw_block *block;
-};
-
-/**
- * Device audio mode
- *
- * Structure linking various operating modes to process flows,
- * configurations and sequences
- *
- */
-struct cfw_mode {
- char name[CFW_MAX_ID];
- char desc[CFW_MAX_DESC]; /* User string */
- u32 flags;
- u8 pfw;
- u8 ovly;
- u8 cfg;
- 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;
- u32 bmagic;
- u32 size;
- u32 cksum;
- u32 version;
- u32 tstamp;
- char name[CFW_MAX_ID]; /* Project name */
- char desc[CFW_MAX_DESC]; /* User string */
- enum cfw_dfamily dfamily;
- enum cfw_device device;
- u32 flags;
- struct cfw_transition *transition[CFW_MAX_TRANSITIONS];
- u16 npfw; /* Number of process flows */
- u16 nmode; /* Number of operating modes */
- struct cfw_pfw *pfw[CFW_MAX_NPFW]; /* Indices to PFW locations */
- struct cfw_mode *mode[CFW_MAX_MODES];
- struct cfw_asoc_toc *asoc_toc;
-};
-
-#endif /* CFW_FIRMWARE_H_ */
diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.c b/sound/soc/codecs/aic3xxx_cfw_ops.c
deleted file mode 100644
index 4f8e3a533a08..000000000000
--- a/sound/soc/codecs/aic3xxx_cfw_ops.c
+++ /dev/null
@@ -1,918 +0,0 @@
-#ifndef AIC3XXX_CFW_HOST_BLD
-# include <linux/module.h>
-# include <linux/delay.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <linux/slab.h>
-#include <sound/tlv.h>
-# define warn(fmt, ...) printk(fmt "\n", ##__VA_ARGS__)
-# define error(fmt, ...) printk(fmt "\n", ##__VA_ARGS__)
-
-#else
-# define _GNU_SOURCE
-# include <stdlib.h>
-# include "utils.h"
-# include <string.h>
-# include <assert.h>
-# define EINVAL 1
-
-#endif
-
-#include "aic3xxx_cfw.h"
-#include "aic3xxx_cfw_ops.h"
-#ifndef AIC3XXX_CFW_HOST_BLD
-static struct cfw_project *aic3xxx_cfw_unpickle(void *pcfw, int n);
-#endif
-
-
-/*
- * Firmware version numbers are used to make sure that the
- * host and target code stay in sync. It is _not_ recommended
- * to provide this number from the outside (E.g., from a makefile)
- * Instead, a set of automated tools are relied upon to keep the numbers
- * in sync at the time of host testing.
- */
-#define CFW_FW_VERSION 0x000100B3
-
-static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim);
-static int aic3xxx_cfw_dlcfg(struct cfw_state *ps, struct cfw_image *pim);
-static int aic3xxx_cfw_dlctl(struct cfw_state *ps, struct cfw_block *pb,
- u32 mute_flags);
-static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb);
-static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask,
- u8 data);
-static int aic3xxx_cfw_set_mode_id(struct cfw_state *ps);
-static int aic3xxx_cfw_mute(struct cfw_state *ps, int mute, u32 flags);
-static int aic3xxx_cfw_setmode_cfg_u(struct cfw_state *ps, int mode, int cfg);
-static int aic3xxx_cfw_setcfg_u(struct cfw_state *ps, int cfg);
-static int aic3xxx_cfw_transition_u(struct cfw_state *ps, char *ttype);
-static int aic3xxx_cfw_set_pll_u(struct cfw_state *ps, int asi);
-static int aic3xxx_cfw_control_u(struct cfw_state *ps, char *cname, int param);
-
-
-#if defined(AIC3XXX_CFW_HOST_BLD)
-
-static int mutex_init(struct mutex *m)
-{
- m->lock = 0;
- return 0;
-}
-
-static int mutex_lock(struct mutex *m)
-{
- assert(m->lock == 0);
- m->lock = 1;
- return 0;
-}
-
-static int mutex_unlock(struct mutex *m)
-{
- assert(m->lock == 1);
- m->lock = 0;
- return 0;
-}
-/*
-static void mdelay(int val)
-{
- int i;
- for (i = 0; i < (val * 10); i++);
-}
-*/
-#endif
-
-int aic3xxx_cfw_init(struct cfw_state *ps, struct aic3xxx_codec_ops const *ops,
- void *ops_obj)
-{
- ps->ops = ops;
- ps->ops_obj = ops_obj;
- ps->pjt = NULL;
- mutex_init(&ps->mutex);
- return 0;
-}
-
-int aic3xxx_cfw_lock(struct cfw_state *ps, int lock)
-{
- if (lock)
- mutex_lock(&ps->mutex);
- else
- mutex_unlock(&ps->mutex);
- return 0;
-}
-
-int aic3xxx_cfw_reload(struct cfw_state *ps, void *pcfw, int n)
-{
- ps->pjt = aic3xxx_cfw_unpickle(pcfw, n);
- ps->cur_mode_id =
- ps->cur_mode = ps->cur_pfw = ps->cur_ovly = ps->cur_cfg = -1;
- if (ps->pjt == NULL)
- return -1;
- return 0;
-}
-
-int aic3xxx_cfw_setmode(struct cfw_state *ps, int mode)
-{
- struct cfw_project *pjt;
- int ret;
-
- aic3xxx_cfw_lock(ps, 1);
- pjt = ps->pjt;
- if (pjt == NULL) {
- aic3xxx_cfw_lock(ps, 0);
- return -1;
- }
- ret = aic3xxx_cfw_setmode_cfg_u(ps, mode, pjt->mode[mode]->cfg);
- aic3xxx_cfw_lock(ps, 0);
- return ret;
-}
-
-int aic3xxx_cfw_setcfg(struct cfw_state *ps, int cfg)
-{
- int ret;
-
- aic3xxx_cfw_lock(ps, 1);
- ret = aic3xxx_cfw_setcfg_u(ps, cfg);
- aic3xxx_cfw_lock(ps, 0);
- return ret;
-}
-
-static int aic3xxx_cfw_setcfg_u(struct cfw_state *ps, int cfg)
-{
- struct cfw_project *pjt = ps->pjt;
- struct cfw_pfw *pfw;
-
- if (pjt == NULL)
- return -1;
- if (ps->cur_pfw < 0 || ps->cur_pfw >= pjt->npfw)
- return -1;
- if (ps->cur_cfg == cfg)
- return 0;
- pfw = pjt->pfw[ps->cur_pfw];
- if (pfw->ncfg == 0 && cfg != 0)
- return -1;
- if (cfg > 0 && cfg >= pfw->ncfg)
- return -1;
- ps->cur_cfg = cfg;
- aic3xxx_cfw_set_mode_id(ps);
- if (pfw->ncfg != 0)
- return aic3xxx_cfw_dlcfg(ps,
- pfw->ovly_cfg[ps->cur_ovly][ps->
- cur_cfg]);
- return 0;
-}
-
-int aic3xxx_cfw_setmode_cfg(struct cfw_state *ps, int mode, int cfg)
-{
- int ret;
-
- aic3xxx_cfw_lock(ps, 1);
- ret = aic3xxx_cfw_setmode_cfg_u(ps, mode, cfg);
- aic3xxx_cfw_lock(ps, 0);
- return ret;
-}
-
-static int aic3xxx_cfw_setmode_cfg_u(struct cfw_state *ps, int mode, int cfg)
-{
- struct cfw_project *pjt = ps->pjt;
- int which = 0;
- struct cfw_pfw *pfw;
- struct cfw_image *im;
-
- if (pjt == NULL)
- return -1;
- if ((mode < 0) || (mode >= pjt->nmode))
- return -1;
- if (cfg < 0)
- return -1;
- if (mode == ps->cur_mode)
- return aic3xxx_cfw_setcfg_u(ps, cfg);
-
- /* Apply exit sequence for previous mode if present */
- if (ps->cur_mode >= 0 && pjt->mode[ps->cur_mode]->exit)
- aic3xxx_cfw_dlcmds(ps, pjt->mode[ps->cur_mode]->exit);
-
- if (pjt->mode[mode]->pfw < pjt->npfw) {
- /* New mode uses miniDSP */
- pfw = pjt->pfw[pjt->mode[mode]->pfw];
- /* Make sure cfg is valid and supported in this mode */
- if (pfw->ncfg == 0 && cfg != 0)
- return -1;
- if (cfg > 0 && cfg >= pfw->ncfg)
- return -1;
- /*
- * Decisions about which miniDSP to stop/restart are taken
- * on the basis of sections present in the _base_ image
- * This allows for correct sync mode operation even in cases
- * where the base PFW uses both miniDSPs where a particular
- * overlay applies only to one
- */
- im = pfw->base;
- if (im->block[CFW_BLOCK_A_INST])
- which |= AIC3XX_COPS_MDSP_A;
- if (im->block[CFW_BLOCK_D_INST])
- which |= AIC3XX_COPS_MDSP_D;
-
- /* New mode requires different PFW */
- if (pjt->mode[mode]->pfw != ps->cur_pfw) {
- ps->cur_pfw = pjt->mode[mode]->pfw;
- ps->cur_ovly = 0;
- ps->cur_cfg = 0;
-
- which = ps->ops->stop(ps->ops_obj, which);
- aic3xxx_cfw_dlimage(ps, im);
- if (pjt->mode[mode]->ovly
- && pjt->mode[mode]->ovly < pfw->novly) {
- /* New mode uses ovly */
- if (pfw->ovly_cfg[pjt->mode[mode]
- ->ovly][cfg] != NULL)
- aic3xxx_cfw_dlimage(ps,
- pfw->ovly_cfg[pjt->
- mode[mode]->
- ovly][cfg]);
- } else if (pfw->ncfg > 0) {
- /* new mode needs only a cfg change */
- aic3xxx_cfw_dlimage(ps, pfw->ovly_cfg[0][cfg]);
- }
- ps->ops->restore(ps->ops_obj, which);
-
- } else if (pjt->mode[mode]->ovly != ps->cur_ovly) {
- /* New mode requires only an ovly change */
- which = ps->ops->stop(ps->ops_obj, which);
- aic3xxx_cfw_dlimage(ps,
- pfw->ovly_cfg[pjt->mode[mode]->
- ovly][cfg]);
- ps->ops->restore(ps->ops_obj, which);
- } else if (pfw->ncfg > 0 && cfg != ps->cur_cfg) {
- /* New mode requires only a cfg change */
- aic3xxx_cfw_dlcfg(ps,
- pfw->ovly_cfg[pjt->mode[mode]->
- ovly][cfg]);
- }
- ps->cur_ovly = pjt->mode[mode]->ovly;
- ps->cur_cfg = cfg;
-
- ps->cur_mode = mode;
- aic3xxx_cfw_set_pll_u(ps, 0);
-
- } else if (pjt->mode[mode]->pfw != 0xFF) {
- warn("Bad pfw setting detected (%d). Max pfw=%d",
- pjt->mode[mode]->pfw, pjt->npfw);
- }
- ps->cur_mode = mode;
- aic3xxx_cfw_set_mode_id(ps);
- /* Transition to netural mode */
- aic3xxx_cfw_transition_u(ps, "NEUTRAL");
- /* Apply entry sequence if present */
- if (pjt->mode[mode]->entry)
- aic3xxx_cfw_dlcmds(ps, pjt->mode[mode]->entry);
- DBG("setmode_cfg: DONE (mode=%d pfw=%d ovly=%d cfg=%d)", ps->cur_mode,
- ps->cur_pfw, ps->cur_ovly, ps->cur_cfg);
- return 0;
-}
-
-int aic3xxx_cfw_transition(struct cfw_state *ps, char *ttype)
-{
- int ret;
-
- aic3xxx_cfw_lock(ps, 1);
- ret = aic3xxx_cfw_transition_u(ps, ttype);
- aic3xxx_cfw_lock(ps, 0);
- return ret;
-}
-
-static int aic3xxx_cfw_transition_u(struct cfw_state *ps, char *ttype)
-{
- int i;
-
- if (ps->pjt == NULL)
- return -1;
- for (i = 0; i < CFW_TRN_N; ++i) {
- if (!strcasecmp(ttype, cfw_transition_id[i])) {
- DBG("Sending transition %s[%d]", ttype, i);
- if (ps->pjt->transition[i]) {
- aic3xxx_cfw_dlcmds(ps,
- ps->pjt->transition[i]->
- block);
- }
- return 0;
- }
- }
- warn("Transition %s not present or invalid", ttype);
- return 0;
-}
-
-int aic3xxx_cfw_set_pll(struct cfw_state *ps, int asi)
-{
- int ret;
-
- aic3xxx_cfw_lock(ps, 1);
- ret = aic3xxx_cfw_set_pll_u(ps, asi);
- aic3xxx_cfw_lock(ps, 0);
- return ret;
-}
-
-static int aic3xxx_cfw_set_pll_u(struct cfw_state *ps, int asi)
-{
- struct cfw_project *pjt = ps->pjt;
- struct cfw_pfw *pfw;
-
- if (pjt == NULL)
- return -1;
- if (ps->cur_mode < 0)
- return -EINVAL;
- pfw = pjt->pfw[pjt->mode[ps->cur_mode]->pfw];
- if (pfw->pll) {
- DBG("Configuring PLL for ASI%d using PFW%d", asi,
- pjt->mode[ps->cur_mode]->pfw);
- aic3xxx_cfw_dlcmds(ps, pfw->pll);
- }
- return 0;
-}
-
-int aic3xxx_cfw_control(struct cfw_state *ps, char *cname, int param)
-{
- int ret;
-
- aic3xxx_cfw_lock(ps, 1);
- ret = aic3xxx_cfw_control_u(ps, cname, param);
- aic3xxx_cfw_lock(ps, 0);
- return ret;
-}
-
-static int aic3xxx_cfw_control_u(struct cfw_state *ps, char *cname, int param)
-{
- struct cfw_pfw *pfw;
- int i;
-
- if (ps->cur_pfw < 0 || ps->cur_pfw >= ps->pjt->npfw) {
- warn("Not in MiniDSP mode");
- return 0;
- }
- pfw = ps->pjt->pfw[ps->cur_pfw];
- for (i = 0; i < pfw->nctrl; ++i) {
- if (!strcasecmp(cname, pfw->ctrl[i]->name)) {
- struct cfw_control *pc = pfw->ctrl[i];
- if (param < 0 || param > pc->imax) {
- warn("Parameter out of range\n");
- return -EINVAL;
- }
- DBG("Sending control %s[%d]", cname, param);
- pc->icur = param;
- aic3xxx_cfw_dlctl(ps, pc->output[param],
- pc->mute_flags);
- return 0;
- }
- }
- warn("Control named %s nort found in pfw %s", cname, pfw->name);
-
- return 0;
-}
-
-static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb)
-{
- int i = 0, lock = 0;
-
- while (i < pb->ncmds) {
- if (CFW_BLOCK_BURSTS(pb->type))
- ps->ops->bulk_write(ps->ops_obj,
- pb->cmd[i].burst->reg.bpod,
- pb->cmd[i].burst->length,
- pb->cmd[i].burst->data);
- else {
- struct cfw_meta_delay d = pb->cmd[i].reg.meta.delay;
- struct cfw_meta_bitop b = pb->cmd[i].reg.meta.bitop;
- switch (pb->cmd[i].reg.meta.mcmd) {
- case CFW_META_DELAY:
- mdelay(d.delay);
- break;
- case CFW_META_UPDTBITS:
- ps->ops->set_bits(ps->ops_obj,
- pb->cmd[i + 1].reg.bpod,
- b.mask,
- pb->cmd[i + 1].reg.data);
- i++;
- break;
- case CFW_META_WAITBITS:
- aic3xxx_wait(ps, pb->cmd[i + 1].reg.bpod,
- b.mask, pb->cmd[i + 1].reg.data);
- i++;
- break;
- case CFW_META_LOCK:
- if (d.delay) {
- ps->ops->lock(ps->ops_obj);
- lock = 1;
- } else {
- if (!lock)
- error("already lock\n");
- ps->ops->unlock(ps->ops_obj);
- lock = 0;
- }
- break;
- default:
- ps->ops->reg_write(ps->ops_obj,
- pb->cmd[i].reg.bpod,
- pb->cmd[i].reg.data);
- }
- }
- ++i;
- }
- if (lock)
- error("exiting blkcmds with lock ON");
-}
-
-static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask,
- u8 data)
-{
- while ((ps->ops->reg_read(ps->ops_obj, reg) & mask) != data)
- mdelay(2);
-}
-
-static const struct {
- u32 mdsp;
- int buf_a, buf_b;
- u32 swap;
-} csecs[] = {
- {
- .mdsp = AIC3XX_COPS_MDSP_A,
- .swap = AIC3XX_ABUF_MDSP_A,
- .buf_a = CFW_BLOCK_A_A_COEF,
- .buf_b = CFW_BLOCK_A_B_COEF
- },
- {
- .mdsp = AIC3XX_COPS_MDSP_D,
- .swap = AIC3XX_ABUF_MDSP_D1,
- .buf_a = CFW_BLOCK_D_A1_COEF,
- .buf_b = CFW_BLOCK_D_B1_COEF
- },
- {
- .mdsp = AIC3XX_COPS_MDSP_D,
- .swap = AIC3XX_ABUF_MDSP_D2,
- .buf_a = CFW_BLOCK_D_A2_COEF,
- .buf_b = CFW_BLOCK_D_B2_COEF
- },
-};
-
-static int aic3xxx_cfw_dlctl(struct cfw_state *ps, struct cfw_block *pb,
- u32 mute_flags)
-{
- int i, btype = CFW_BLOCK_TYPE(pb->type);
- int run_state = ps->ops->lock(ps->ops_obj);
-
- DBG("Download CTL");
- for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) {
- if (csecs[i].buf_a == btype || csecs[i].buf_b == btype) {
- DBG("\tDownload once to %d", btype);
- aic3xxx_cfw_dlcmds(ps, pb);
- if (run_state & csecs[i].mdsp) {
- DBG("Download again %d", btype);
- aic3xxx_cfw_mute(ps, 1, run_state & mute_flags);
- ps->ops->bswap(ps->ops_obj, csecs[i].swap);
- aic3xxx_cfw_mute(ps, 0, run_state & mute_flags);
- aic3xxx_cfw_dlcmds(ps, pb);
- }
- break;
- }
- }
- ps->ops->unlock(ps->ops_obj);
- return 0;
-}
-
-static int aic3xxx_cfw_dlcfg(struct cfw_state *ps, struct cfw_image *pim)
-{
- int i, run_state, swap;
-
- DBG("Download CFG %s", pim->name);
- run_state = ps->ops->lock(ps->ops_obj);
- swap = 0;
- for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) {
- if (pim->block[csecs[i].buf_a]) {
- if (run_state & csecs[i].mdsp) {
- aic3xxx_cfw_dlcmds(ps,
- pim->block[csecs[i].buf_a]);
- swap |= csecs[i].swap;
- } else {
- aic3xxx_cfw_dlcmds(ps,
- pim->block[csecs[i].buf_a]);
- aic3xxx_cfw_dlcmds(ps,
- pim->block[csecs[i].buf_b]);
- }
- }
- }
- if (swap) {
- aic3xxx_cfw_mute(ps, 1, run_state & pim->mute_flags);
- ps->ops->bswap(ps->ops_obj, swap);
- aic3xxx_cfw_mute(ps, 0, run_state & pim->mute_flags);
- for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) {
- if (pim->block[csecs[i].buf_a]) {
- if (run_state & csecs[i].mdsp)
- aic3xxx_cfw_dlcmds(ps,
- pim->block[csecs[i].
- buf_a]);
- }
- }
- }
- ps->ops->unlock(ps->ops_obj);
- return 0;
-}
-
-static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim)
-{
- int i;
-
- DBG("Download IMAGE %s", pim->name);
- for (i = 0; i < CFW_BLOCK_N; ++i)
- if (pim->block[i])
- aic3xxx_cfw_dlcmds(ps, pim->block[i]);
- return 0;
-}
-
-static int aic3xxx_cfw_mute(struct cfw_state *ps, int mute, u32 flags)
-{
- if ((flags & AIC3XX_COPS_MDSP_D) && (flags & AIC3XX_COPS_MDSP_A))
- aic3xxx_cfw_transition_u(ps, mute ? "AD_MUTE" : "AD_UNMUTE");
- else if (flags & AIC3XX_COPS_MDSP_D)
- aic3xxx_cfw_transition_u(ps, mute ? "D_MUTE" : "D_UNMUTE");
- else if (flags & AIC3XX_COPS_MDSP_A)
- aic3xxx_cfw_transition_u(ps, mute ? "A_MUTE" : "A_UNMUTE");
- return 0;
-}
-
-#define FW_NDX2PTR(x, b) do { \
-x = (void *)((u8 *)(b) + ((int)(x))); \
-} while (0)
-
-static void aic3xxx_cfw_unpickle_block(struct cfw_block *pb, void *p)
-{
- int i;
-
- if (CFW_BLOCK_BURSTS(pb->type))
- for (i = 0; i < pb->ncmds; ++i)
- FW_NDX2PTR(pb->cmd[i].burst, p);
-}
-
-static void aic3xxx_cfw_unpickle_image(struct cfw_image *im, void *p)
-{
- int i;
- for (i = 0; i < CFW_BLOCK_N; ++i)
- if (im->block[i]) {
- FW_NDX2PTR(im->block[i], p);
- aic3xxx_cfw_unpickle_block(im->block[i], p);
- }
-}
-
-static void aic3xxx_cfw_unpickle_control(struct cfw_control *ct, void *p)
-{
- int i;
- FW_NDX2PTR(ct->output, p);
- for (i = 0; i <= ct->imax; ++i) {
- FW_NDX2PTR(ct->output[i], p);
- aic3xxx_cfw_unpickle_block(ct->output[i], p);
- }
-}
-#ifndef AIC3XXX_CFW_HOST_BLD
-static
-#endif
-unsigned int crc32(unsigned int *pdata, int n)
-{
- u32 crc = 0, i, crc_poly = 0x04C11DB7; /* CRC - 32 */
- u32 msb;
- u32 residue_value = 0;
- int bits;
-
- for (i = 0; i < (n >> 2); i++) {
- bits = 32;
- while (--bits >= 0) {
- msb = crc & 0x80000000;
- crc = (crc << 1) ^ ((*pdata >> bits) & 1);
- if (msb)
- crc = crc ^ crc_poly;
- }
- pdata++;
- }
-
- switch (n & 3) {
- case 0:
- break;
- case 1:
- residue_value = (*pdata & 0xFF);
- bits = 8;
- break;
- case 2:
- residue_value = (*pdata & 0xFFFF);
- bits = 16;
- break;
- case 3:
- residue_value = (*pdata & 0xFFFFFF);
- bits = 24;
- break;
- }
-
- if (n & 3) {
- while (--bits >= 0) {
- msb = crc & 0x80000000;
- crc = (crc << 1) ^ ((residue_value >> bits) & 1);
- if (msb)
- crc = crc ^ crc_poly;
- }
- }
- return crc;
-}
-
-static int crc_chk(void *p, int n)
-{
- struct cfw_project *pjt = (void *)p;
- u32 crc = pjt->cksum, crc_comp;
-
- pjt->cksum = 0;
- DBG("Entering crc %d", n);
- crc_comp = crc32(p, n);
- if (crc_comp != crc) {
- DBG("CRC mismatch 0x%08X != 0x%08X", crc, crc_comp);
- return 0;
- }
- DBG("CRC pass");
- pjt->cksum = crc;
- return 1;
-}
-#ifndef AIC3XXX_CFW_HOST_BLD
-static
-#endif
-struct cfw_project *aic3xxx_cfw_unpickle(void *p, int n)
-{
- struct cfw_project *pjt = p;
- int i, j, k;
-
- if (pjt->magic != CFW_FW_MAGIC ||
- pjt->size != n || pjt->bmagic != CFW_FW_VERSION ||
- !crc_chk(p, n)) {
- error
- ("magic:0x%08X!=0x%08X || size:%d!=%d ||version:0x%08X!=0x%08X",
- pjt->magic, CFW_FW_MAGIC, pjt->size, n, pjt->cksum,
- CFW_FW_VERSION);
-
- return NULL;
- }
- DBG("Loaded firmware inside unpickle\n");
-
- for (i = 0; i < CFW_MAX_TRANSITIONS; i++) {
- if (pjt->transition[i]) {
- FW_NDX2PTR(pjt->transition[i], p);
- FW_NDX2PTR(pjt->transition[i]->block, p);
- aic3xxx_cfw_unpickle_block(pjt->transition[i]->block,
- p);
- }
- }
-
- for (i = 0; i < pjt->npfw; i++) {
- DBG("loading pfw %d\n", i);
- FW_NDX2PTR(pjt->pfw[i], p);
- if (pjt->pfw[i]->base) {
- FW_NDX2PTR(pjt->pfw[i]->base, p);
- aic3xxx_cfw_unpickle_image(pjt->pfw[i]->base, p);
- }
- if (pjt->pfw[i]->pll) {
- FW_NDX2PTR(pjt->pfw[i]->pll, p);
- aic3xxx_cfw_unpickle_block(pjt->pfw[i]->pll, p);
- }
- for (j = 0; j < pjt->pfw[i]->novly; ++j)
- for (k = 0; k < pjt->pfw[i]->ncfg; ++k) {
- FW_NDX2PTR(pjt->pfw[i]->ovly_cfg[j][k], p);
- aic3xxx_cfw_unpickle_image(pjt->pfw[i]->
- ovly_cfg[j][k], p);
- }
- for (j = 0; j < pjt->pfw[i]->nctrl; ++j) {
- FW_NDX2PTR(pjt->pfw[i]->ctrl[j], p);
- aic3xxx_cfw_unpickle_control(pjt->pfw[i]->ctrl[j], p);
- }
- }
-
- DBG("loaded pfw's\n");
- for (i = 0; i < pjt->nmode; i++) {
- FW_NDX2PTR(pjt->mode[i], p);
- if (pjt->mode[i]->entry) {
- FW_NDX2PTR(pjt->mode[i]->entry, p);
- aic3xxx_cfw_unpickle_block(pjt->mode[i]->entry, p);
- }
- if (pjt->mode[i]->exit) {
- FW_NDX2PTR(pjt->mode[i]->exit, p);
- aic3xxx_cfw_unpickle_block(pjt->mode[i]->exit, p);
- }
- }
- if (pjt->asoc_toc)
- FW_NDX2PTR(pjt->asoc_toc, p);
- else {
- warn("asoc_toc not defined. FW version mismatch?");
- return NULL;
- }
- DBG("loaded modes");
- return pjt;
-}
-
-#ifndef AIC3XXX_CFW_HOST_BLD
-static int aic3xxx_get_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct cfw_state *ps =
- (struct cfw_state *) kcontrol->private_value;
- struct cfw_pfw *pfw;
- int i;
-
- if (ps->cur_pfw >= ps->pjt->npfw) {
- DBG("Not in MiniDSP mode");
- return 0;
- }
- pfw = ps->pjt->pfw[ps->cur_pfw];
- for (i = 0; i < pfw->nctrl; ++i) {
- if (!strcasecmp(kcontrol->id.name, pfw->ctrl[i]->name)) {
- struct cfw_control *pc = pfw->ctrl[i];
- ucontrol->value.integer.value[0] = pc->icur;
- return 0;
- }
- }
- return 0;
-}
-
-static int aic3xxx_put_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct cfw_state *ps =
- (struct cfw_state *) kcontrol->private_value;
-
- aic3xxx_cfw_control(ps, kcontrol->id.name,
- ucontrol->value.integer.value[0]);
- return 0;
-}
-
-static int aic3xxx_info_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *ucontrol)
-{
- struct cfw_state *ps =
- (struct cfw_state *) kcontrol->private_value;
- struct cfw_pfw *pfw;
- int i;
-
- if (ps->cur_pfw >= ps->pjt->npfw) {
- DBG("Not in MiniDSP mode");
- return 0;
- }
- pfw = ps->pjt->pfw[ps->cur_pfw];
- for (i = 0; i < pfw->nctrl; ++i) {
- if (!strcasecmp(kcontrol->id.name, pfw->ctrl[i]->name)) {
- struct cfw_control *pc = pfw->ctrl[i];
- ucontrol->value.integer.min = 0;
- ucontrol->value.integer.max = pc->imax;
- if (pc->imax == 1)
- ucontrol->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- else
- ucontrol->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- }
- }
-
- ucontrol->count = 1;
- return 0;
-}
-#endif
-int aic3xxx_cfw_add_controls(struct snd_soc_codec *codec, struct cfw_state *ps)
-{
- int i, j;
- struct cfw_pfw *pfw;
-
- for (j = 0; j < ps->pjt->npfw; ++j) {
- pfw = ps->pjt->pfw[j];
-
- for (i = 0; i < pfw->nctrl; ++i) {
- struct cfw_control *pc = pfw->ctrl[i];
-#ifndef AIC3XXX_CFW_HOST_BLD
- struct snd_kcontrol_new *generic_control =
- kzalloc(sizeof(struct snd_kcontrol_new),
- GFP_KERNEL);
- unsigned int *tlv_array =
- kzalloc(4 * sizeof(unsigned int), GFP_KERNEL);
-
- if (generic_control == NULL)
- return -ENOMEM;
- generic_control->access =
- SNDRV_CTL_ELEM_ACCESS_TLV_READ |
- SNDRV_CTL_ELEM_ACCESS_READWRITE;
- tlv_array[0] = SNDRV_CTL_TLVT_DB_SCALE;
- tlv_array[1] = 2 * sizeof(unsigned int);
- tlv_array[2] = pc->min;
- tlv_array[3] = ((pc->step) & TLV_DB_SCALE_MASK);
- if (pc->step > 0)
- generic_control->tlv.p = tlv_array;
- generic_control->name = pc->name;
- generic_control->private_value = (unsigned long) ps;
- generic_control->get = aic3xxx_get_control;
- generic_control->put = aic3xxx_put_control;
- generic_control->info = aic3xxx_info_control;
- generic_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-#endif
- DBG("Adding control %s", pc->name);
-#ifndef AIC3XXX_CFW_HOST_BLD
- snd_soc_add_codec_controls(codec, generic_control, 1);
-#endif
- }
- }
- return 0;
-
-}
-
-static int aic3xxx_cfw_set_mode_id(struct cfw_state *ps)
-{
- struct cfw_asoc_toc *toc = ps->pjt->asoc_toc;
- int i;
-
- for (i = 0; i < toc->nentries; ++i) {
- if (toc->entry[i].cfg == ps->cur_cfg &&
- toc->entry[i].mode == ps->cur_mode) {
- ps->cur_mode_id = i;
- return 0;
- }
- }
- DBG("Unknown mode, cfg combination [%d, %d]",
- ps->cur_mode, ps->cur_cfg);
- return -1;
-}
-#ifndef AIC3XXX_CFW_HOST_BLD
-static int aic3xxx_get_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- struct cfw_state *ps = (struct cfw_state *)e->mask;
-
- ucontrol->value.enumerated.item[0] = ps->cur_mode_id;
-
- return 0;
-}
-#endif
-#ifndef AIC3XXX_CFW_HOST_BLD
-static int aic3xxx_put_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- struct cfw_state *ps = (struct cfw_state *)e->mask;
- struct cfw_asoc_toc *toc;
- int index, ret;
-
- aic3xxx_cfw_lock(ps, 1);
- toc = ps->pjt->asoc_toc;
-
- index = ucontrol->value.enumerated.item[0];
- if (index < 0 || index >= toc->nentries) {
- aic3xxx_cfw_lock(ps, 0);
- return -EINVAL;
- }
- ret =
- aic3xxx_cfw_setmode_cfg_u(ps, toc->entry[index].mode,
- toc->entry[index].cfg);
- aic3xxx_cfw_lock(ps, 0);
- return ret;
-}
-#endif
-
-int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps)
-{
-#ifndef AIC3XXX_CFW_HOST_BLD
- int j;
- struct cfw_asoc_toc *toc = ps->pjt->asoc_toc;
- struct soc_enum *mode_cfg_enum =
- kzalloc(sizeof(struct soc_enum), GFP_KERNEL);
- struct snd_kcontrol_new *mode_cfg_control =
- kzalloc(sizeof(struct snd_kcontrol_new), GFP_KERNEL);
- char **enum_texts;
-
- if (mode_cfg_enum == NULL)
- goto mem_err;
- if (mode_cfg_control == NULL)
- goto mem_err;
-
- mode_cfg_enum->texts =
- kzalloc(toc->nentries * sizeof(char *), GFP_KERNEL);
- if (mode_cfg_enum->texts == NULL)
- goto mem_err;
- /* Hack to overwrite the const * const pointer */
- enum_texts = (char **)mode_cfg_enum->texts;
-
- for (j = 0; j < toc->nentries; j++)
- enum_texts[j] = toc->entry[j].etext;
- mode_cfg_enum->reg = j;
- mode_cfg_enum->max = toc->nentries;
- mode_cfg_enum->mask = (unsigned int)ps;
- mode_cfg_control->name = "Codec Firmware Setmode";
- mode_cfg_control->get = aic3xxx_get_mode;
- mode_cfg_control->put = aic3xxx_put_mode;
- mode_cfg_control->info = snd_soc_info_enum_ext;
- mode_cfg_control->private_value = (unsigned long)mode_cfg_enum;
- mode_cfg_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- snd_soc_add_codec_controls(codec, mode_cfg_control, 1);
- return 0;
-mem_err:
- kfree(mode_cfg_control);
- kfree(mode_cfg_enum);
- kfree(mode_cfg_enum->texts);
- return -ENOMEM;
-#else
- return 0;
-#endif
-
-}
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 <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/platform_device.h>
-#include <linux/switch.h>
#include <sound/jack.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -56,30 +56,29 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <linux/mfd/tlv320aic3262-registers.h>
-#include <linux/mfd/tlv320aic3262-core.h>
-#include "aic3xxx_cfw.h"
-#include "aic3xxx_cfw_ops.h"
+#include <linux/mfd/tlv320aic3xxx-core.h>
+#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<<mc->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,19 +1689,337 @@ 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 *) &reg;
+ 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,
* @reg: register address,
@@ -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 *) &reg;
- value = aic3262_reg_read(codec->control_data, reg);
+ union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) &reg;
+ 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 *) &reg;
+ union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) &reg;
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 <linux/switch.h>
+#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 */