88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Use is subject to license terms.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs Audio Driver
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This Audio Driver controls the Crystal CS4231 Codec used on many SPARC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * platforms. It does not support the CS4231 on Power PCs or x86 PCs. It
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * does support two different DMA engines, the APC and EB2. The code for
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * those DMA engines is split out and a well defined, but private, interface
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is used to control those DMA engines.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * For some reason setting the CS4231's registers doesn't always
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * succeed. Therefore every time we set a register we always read it
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * back to make sure it was set. If not we wait a little while and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * then try again. This is all taken care of in the routines
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_put_index() and audiocs_sel_index() and the macros ORIDX()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and ANDIDX(). We don't worry about the status register because it
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is cleared by writing anything to it. So it doesn't matter what
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the value written is.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This driver supports suspending and resuming. A suspend just stops playing
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and recording. The play DMA buffers end up getting thrown away, but when
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * you shut down the machine there is a break in the audio anyway, so they
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * won't be missed and it isn't worth the effort to save them. When we resume
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * we always start playing and recording. If they aren't needed they get
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * shut off by the mixer.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Power management is supported by this driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: This module depends on drv/audio being loaded first.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module linkage routines for the kernel
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_ddi_power(dev_info_t *, int, int);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Entry point routine prototypes
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic int audiocs_open(void *, int, unsigned *, caddr_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_close(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_start(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_stop(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_format(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_channels(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_rate(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_sync(void *, unsigned);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Control callbacks.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_get_value(void *, uint64_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_set_ogain(void *, uint64_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_set_igain(void *, uint64_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_set_mgain(void *, uint64_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_set_inputs(void *, uint64_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_set_outputs(void *, uint64_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_set_micboost(void *, uint64_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Local Routines */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_alloc_engine(CS_state_t *, int);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_free_engine(CS_engine_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_configure_input(CS_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_configure_output(CS_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic CS_ctrl_t *audiocs_alloc_ctrl(CS_state_t *, uint32_t, uint64_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiocs_add_controls(CS_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_del_controls(CS_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_power_down(CS_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_put_index(CS_state_t *, uint8_t, uint8_t, int);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_sel_index(CS_state_t *, uint8_t, int);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define SELIDX(s, idx) audiocs_sel_index(s, idx, __LINE__)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PUTIDX(s, val, mask) audiocs_put_index(s, val, mask, __LINE__)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_put_index(CS_state_t *, uint8_t, uint8_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiocs_sel_index(CS_state_t *, uint8_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define SELIDX(s, idx) audiocs_sel_index(s, idx)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PUTIDX(s, val, mask) audiocs_put_index(s, val, mask)
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore#define GETIDX(s) ddi_get8((handle), &CS4231_IDR)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (ddi_get8((handle), &CS4231_IDR) | (uint8_t)(val)), \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(s, (ddi_get8((handle), &CS4231_IDR) & (uint8_t)(val)), \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic audio_engine_ops_t audiocs_engine_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Global variables, but viewable only by this file.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* play gain array, converts linear gain to 64 steps of log10 gain */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, /* [000] -> [004] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x3a, 0x39, 0x38, 0x37, 0x36, /* [005] -> [009] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x35, 0x34, 0x33, 0x32, 0x31, /* [010] -> [014] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x30, 0x2f, 0x2e, 0x2d, 0x2c, /* [015] -> [019] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x2b, 0x2a, 0x29, 0x29, 0x28, /* [020] -> [024] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x28, 0x27, 0x27, 0x26, 0x26, /* [025] -> [029] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x25, 0x25, 0x24, 0x24, 0x23, /* [030] -> [034] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x23, 0x22, 0x22, 0x21, 0x21, /* [035] -> [039] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x20, 0x20, 0x1f, 0x1f, 0x1f, /* [040] -> [044] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x1e, 0x1e, 0x1e, 0x1d, 0x1d, /* [045] -> [049] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x1d, 0x1c, 0x1c, 0x1c, 0x1b, /* [050] -> [054] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x1b, 0x1b, 0x1a, 0x1a, 0x1a, /* [055] -> [059] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x1a, 0x19, 0x19, 0x19, 0x19, /* [060] -> [064] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x18, 0x18, 0x18, 0x18, 0x17, /* [065] -> [069] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x17, 0x17, 0x17, 0x16, 0x16, /* [070] -> [074] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x16, 0x16, 0x16, 0x15, 0x15, /* [075] -> [079] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x15, 0x15, 0x15, 0x14, 0x14, /* [080] -> [084] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x14, 0x14, 0x14, 0x13, 0x13, /* [085] -> [089] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x13, 0x13, 0x13, 0x12, 0x12, /* [090] -> [094] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x12, 0x12, 0x12, 0x12, 0x11, /* [095] -> [099] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x11, 0x11, 0x11, 0x11, 0x11, /* [100] -> [104] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x10, 0x10, 0x10, 0x10, 0x10, /* [105] -> [109] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x10, 0x0f, 0x0f, 0x0f, 0x0f, /* [110] -> [114] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, /* [114] -> [119] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, /* [120] -> [124] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, /* [125] -> [129] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, /* [130] -> [134] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, /* [135] -> [139] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, /* [140] -> [144] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, /* [145] -> [149] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0a, 0x0a, 0x0a, 0x0a, 0x09, /* [150] -> [154] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x09, 0x09, 0x09, 0x09, 0x09, /* [155] -> [159] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x09, 0x09, 0x08, 0x08, 0x08, /* [160] -> [164] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x08, 0x08, 0x08, 0x08, 0x08, /* [165] -> [169] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x08, 0x07, 0x07, 0x07, 0x07, /* [170] -> [174] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x07, 0x07, 0x07, 0x07, 0x07, /* [175] -> [179] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x06, 0x06, 0x06, 0x06, 0x06, /* [180] -> [184] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x06, 0x06, 0x06, 0x06, 0x05, /* [185] -> [189] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x05, 0x05, 0x05, 0x05, 0x05, /* [190] -> [194] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x05, 0x05, 0x05, 0x05, 0x04, /* [195] -> [199] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x04, 0x04, 0x04, 0x04, 0x04, /* [200] -> [204] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x04, 0x04, 0x04, 0x04, 0x03, /* [205] -> [209] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x03, 0x03, 0x03, 0x03, 0x03, /* [210] -> [214] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x03, 0x03, 0x03, 0x03, 0x03, /* [215] -> [219] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x02, 0x02, 0x02, 0x02, 0x02, /* [220] -> [224] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x02, 0x02, 0x02, 0x02, 0x02, /* [225] -> [229] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x02, 0x01, 0x01, 0x01, 0x01, /* [230] -> [234] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x01, 0x01, 0x01, 0x01, 0x01, /* [235] -> [239] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x01, 0x01, 0x01, 0x00, 0x00, /* [240] -> [244] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00, 0x00, 0x00, 0x00, 0x00, /* [245] -> [249] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00, 0x00, 0x00, 0x00, 0x00, /* [250] -> [254] */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * STREAMS Structures
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI Structures
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Device operations structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* devo_refcnt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_quiesce_not_supported, /* devo_quiesce */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Linkage structure for loadable drivers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Module linkage structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modlinkage audiocs_modlinkage = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* ******* Loadable Module Configuration Entry Points ********************* */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implements _init(9E).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_install() status, see mod_install(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_init_ops(&audiocs_dev_ops, CS4231_NAME);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((rv = mod_install(&audiocs_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implements _fini(9E).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_remove() status, see mod_remove(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((rv = mod_remove(&audiocs_modlinkage)) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implements _info(9E).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * modinfo *modinfop Pointer to the opaque modinfo structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_info() status, see mod_info(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (mod_info(&audiocs_modlinkage, modinfop));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* ******* Driver Entry Points ******************************************** */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_ddi_attach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implement attach(9e).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_attach_cmd_t cmd Attach command
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_ddi_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implement detach(9e).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_detach_cmd_t cmd Detach command
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Success.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Failure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_ddi_power()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implements power(9E).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * def_info_t *dip Ptr to the device's dev_info structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int component Which component to power up/down
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int level The power level for the component
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Power level changed, we always succeed
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_ddi_power(dev_info_t *dip, int component, int level)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure we have some work to do */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We don't do anything if we're suspended. Suspend/resume diddles
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * with power anyway.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* check the level change to see what we need to do */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (level == CS4231_PWR_OFF && state->cs_powered) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power down and save the state */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else if (level == CS4231_PWR_ON && !state->cs_powered) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power up */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* ******* Local Routines *************************************************** */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = CS4231_PLAY; i <= CS4231_REC; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* unmap the registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* destroy the state mutex */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_attach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Attach an instance of the CS4231 driver. This routine does the device
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dependent attach tasks. When it is complete it calls
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio_dev_register() to register with the framework.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate the state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state = kmem_zalloc(sizeof (*state), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now fill it in, initialize the state mutexs first */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_init(&state->cs_lock, NULL, MUTEX_DRIVER, NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio state initialization... should always succeed,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * framework will message failure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((state->cs_adev = audio_dev_alloc(dip, 0)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_description(adev, CS_DEV_CONFIG_ONBRD1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_add_info(adev, "Legacy codec: Crystal Semiconductor CS4231");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize the audio state structures */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((audiocs_init_state(state)) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "init_state() failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize the audio chip */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((audiocs_chip_init(state)) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* chip init will have powered us up */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* finally register with framework to kick everything off */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_register(state->cs_adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->cs_adev, "unable to register audio dev");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* everything worked out, so report the device */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_resume()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Resume a suspended device instance.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* we've already allocated the state structure so get ptr */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* mark the Codec busy -- this should keep power(9e) away */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) pm_busy_component(state->cs_dip, CS4231_COMPONENT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power it up */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize the audio chip */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((audiocs_chip_init(state)) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) pm_idle_component(state->cs_dip, CS4231_COMPONENT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We have already powered up the chip, but this alerts the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * framework to the fact.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) pm_raise_power(dip, CS4231_COMPONENT, CS4231_PWR_ON);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) pm_idle_component(state->cs_dip, CS4231_COMPONENT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Detach an instance of the CS4231 driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be detached (busy)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* don't detach if still in use */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_unregister(adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Make sure the Codec and DMA engine are off.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ANDIDX(state, ~(INTC_PEN|INTC_CEN), INTC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure the DMA engine isn't going to do anything */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * power down the device, no reason to waste power without
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) pm_lower_power(dip, CS4231_COMPONENT, CS4231_PWR_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_suspend()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Suspend an instance of the CS4231 driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now we can power down the Codec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->cs_suspended = B_TRUE; /* stop new ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define MONVOL (MONCTL | AUDIO_CTRL_FLAG_MONVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_alloc_ctrl
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocates a control structure for the audio mixer.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state Device soft state.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint32_t num Control number to allocate.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint64_t val Initial value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Pointer to newly allocated CS_ctrl_t structure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_alloc_ctrl(CS_state_t *state, uint32_t num, uint64_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; audiocs_inputs[i]; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc.acd_flags = PLAYCTL | AUDIO_CTRL_FLAG_MULTI;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; audiocs_outputs[i]; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cc->cc_ctrl = audio_dev_add_control(state->cs_adev, &desc,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_free_ctrl
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Frees a control and all resources associated with it.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_ctrl_t *cc Pointer to control structure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_add_controls
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocates and registers all controls for this device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state Device soft state.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS All controls added and registered
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE At least one control was not added or registered.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->cs_##CTL = audiocs_alloc_ctrl(state, ID, VAL); \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ADD_CTRL(outputs, CTL_OUTPUTS, (state->cs_omask & ~state->cs_omod) |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ADD_CTRL(inputs, CTL_INPUTS, (1U << INPUT_MIC));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_del_controls
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Unregisters and frees all controls for this device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state Device soft state.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_chip_init()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Power up the audio core, initialize the audio Codec, prepare the chip
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Chip initialized and ready to use
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Chip not initialized and not ready
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure we are powered up */
f275d02f08c70e13825071e2577d1481e8bba78eGarrett D'Amore /* wait for the Codec before we continue */
f275d02f08c70e13825071e2577d1481e8bba78eGarrett D'Amore if (audiocs_poll_ready(state) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* activate registers 16 -> 31 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now figure out what version we have */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_get8(handle, &CS4231_IDR) & VID_A) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get rid of annoying popping by muting the output channels */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, LDACO_LDM | LDACO_MID_GAIN, LDAC0_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, RDACO_RDM | RDACO_MID_GAIN, RDAC0_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize aux input channels to known gain values & muted */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, LAUX1_LX1M | LAUX1_UNITY_GAIN, LAUX1_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, RAUX1_RX1M | RAUX1_UNITY_GAIN, RAUX1_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, LAUX2_LX2M | LAUX2_UNITY_GAIN, LAUX2_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, RAUX2_RX2M | RAUX2_UNITY_GAIN, RAUX2_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize aux input channels to known gain values & muted */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, LLIC_LLM | LLIC_UNITY_GAIN, LLIC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, RLIC_RLM | RLIC_UNITY_GAIN, RLIC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* program the sample rate, play and capture must be the same */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, FS_48000 | PDF_LINEAR16NE | PDF_STEREO, FSDF_VALID_MASK);
f275d02f08c70e13825071e2577d1481e8bba78eGarrett D'Amore if (audiocs_poll_ready(state) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, CDF_LINEAR16NE | CDF_STEREO, CDF_VALID_MASK);
f275d02f08c70e13825071e2577d1481e8bba78eGarrett D'Amore if (audiocs_poll_ready(state) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set up the Codec for playback and capture disabled, dual DMA, and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * playback and capture DMA.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, INTC_DDC | INTC_PDMA | INTC_CDMA, INTC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audiocs_poll_ready(state) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Turn on the output level bit to be 2.8 Vpp. Also, don't go to 0 on
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* turn on the high pass filter if Rev A */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* clear the play and capture interrupt flags */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put8(handle, &CS4231_STATUS, (AFS_RESET_STATUS));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* the play and record gains will be set by the audio mixer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* unmute the output */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ANDIDX(state, ~LDACO_LDM, LDAC0_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ANDIDX(state, ~RDACO_RDM, RDAC0_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* unmute the mono speaker and mute mono in */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_init_state()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine initializes the audio driver's state structure and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * maps in the registers. This also includes reading the properties.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CAUTION: This routine maps the registers and initializes a mutex.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Failure cleanup is handled by cs4231_attach(). It is not
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * handled locally by this routine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS State structure initialized
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE State structure not initialized
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "NAME=audiocs audio device",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set up the pm-components */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "pm-components", pm_comp, 3) != DDI_PROP_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "couldn't create pm-components property");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* figure out which DMA engine hardware we have */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "dma-model", &prop_str) == DDI_PROP_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* cs_regs, cs_eb2_regs and cs_handles filled in later */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* most of what's left is filled in when the registers are mapped */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Allocate engines, must be done before register mapping called */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((audiocs_alloc_engine(state, CS4231_PLAY) != DDI_SUCCESS) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (audiocs_alloc_engine(state, CS4231_REC) != DDI_SUCCESS)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Map in the registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (CS4231_DMA_MAP_REGS(state) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Allocate and add controls, must be done *after* registers mapped */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audiocs_add_controls(state) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_get_ports()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Get which audiocs h/w version we have and use this to
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * determine the input and output ports as well whether or not
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the hardware has internal loopbacks or not. We also have three
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * different ways for the properties to be specified, which we
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * also need to worry about.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Vers Platform(s) DMA eng. audio-module** loopback
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a SS-4+/SS-5+ apcdma no no
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * b Ultra-1&2 apcdma no yes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * c positron apcdma no yes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * d PPC - retired
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * e x86 - retired
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * f tazmo eb2dma Perigee no
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * g tazmo eb2dma Quark yes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * h darwin+ eb2dma no N/A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Vers model~ aux1* aux2*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a N/A N/A N/A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * b N/A N/A N/A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * c N/A N/A N/A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * f SUNW,CS4231f N/A N/A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * g SUNW,CS4231g N/A N/A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * h SUNW,CS4231h cdrom none
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * * = Replaces internal-loopback for latest property type, can be
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * set to "cdrom", "loopback", or "none".
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ** = For plugin audio modules only. Starting with darwin, this
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * property is replaces by the model property.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ~ = Replaces audio-module.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * + = Has the capability of having a cable run from the internal
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CD-ROM to the audio device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * N/A = Not applicable, the property wasn't created for early
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * platforms, or the property has been retired.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: Older tazmo and quark machines don't have the model property.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* First we set the common ports, etc. */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now we try the new "model" property */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (strcmp(prop_str, "SUNW,CS4231h") == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(adev, CS_DEV_VERSION_H);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else if (strcmp(prop_str, "SUNW,CS4231g") == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* quark audio module */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(adev, CS_DEV_VERSION_G);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NB: This could do SUNVTS LOOPBACK, but we
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * don't support it for now... owing to no
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * support in framework.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else if (strcmp(prop_str, "SUNW,CS4231f") == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(adev, CS_DEV_VERSION_F);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "unknown audio model: %s, some parts of "
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_prop_free(prop_str); /* done with the property */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else { /* now try the older "audio-module" property */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_PROP_DONTPASS, "audio-module", &prop_str) ==
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(adev, CS_DEV_VERSION_G);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* See quark comment above about SunVTS */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(adev, CS_DEV_VERSION_F);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "unknown audio module: %s, some "
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "parts of audio may not work correctly",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_prop_free(prop_str); /* done with the prop */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else { /* now try heuristics, ;-( */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_PROP_DONTPASS, "internal-loopback", B_FALSE)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Again, we don't support SunVTS for these
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * boards, although we potentially could.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(adev, CS_DEV_VERSION_A);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_power_up()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Power up the Codec and restore the codec's registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: We don't worry about locking since the only routines
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * that may call us are attach() and power() Both of
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * which should be the only threads in the driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* turn on the Codec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* reset the DMA engine(s) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Reload the Codec's registers, the DMA engines will be
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * taken care of when play and record start up again. But
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * first enable registers 16 -> 31.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, state->cs_save[MID_REG], MID_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < CS4231_REGS; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* restore Codec registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put8(handle, &CS4231_IDR, state->cs_save[i]);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* clear MCE bit */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_power_down()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Power down the Codec and save the codec's registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: See the note in cs4231_power_up() about locking.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We are powering down, so we don't need to do a thing with
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the DMA engines. However, we do need to save the Codec
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < CS4231_REGS; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* save Codec regs */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->cs_save[i] = ddi_get8(handle, &CS4231_IDR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* turn off the Codec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* cs4231_power_down() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_configure_input()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Configure input properties of the mixer (e.g. igain, ports).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore l = ((state->cs_igain->cc_val & 0xff00) >> 8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* rescale these for our atten array */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* we downshift by 4 bits -- igain only has 16 possible values */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* NB: that we do not scale here! The SADA driver didn't do so. */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* note that SunVTS also uses this */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_configure_output()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Configure output properties of the mixer (e.g. ogain, mgain).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* port selection */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ANDIDX(state, ~MIOC_MONO_SPKR_MUTE, MIOC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ORIDX(state, MIOC_MONO_SPKR_MUTE, MIOC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ANDIDX(state, ~PC_HEADPHONE_MUTE, PC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ORIDX(state, PC_HEADPHONE_MUTE, PC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ANDIDX(state, ~PC_LINE_OUT_MUTE, PC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ORIDX(state, PC_LINE_OUT_MUTE, PC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* monitor gain */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mgain = cs4231_atten[((state->cs_mgain->cc_val * 255) / 100) & 0xff];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* disable loopbacks when gain == 0 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* we use cs4231_atten[] to linearize attenuation */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUTIDX(state, (mgain << 2) | LC_LBE, LC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* output gain */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore l = ((state->cs_ogain->cc_val >> 8) & 0xff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (l == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (r == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* rescale these for our atten array */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore l = cs4231_atten[(((uint32_t)l * 255) / 100) & 0xff] | lmute;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore r = cs4231_atten[(((uint32_t)r * 255) / 100) & 0xff] | rmute;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_get_value()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Get a control value
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint64_t *valp Pointer to store value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 The Codec parameter has been retrieved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_set_ogain()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the play gain.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint64_t val The gain to set (both left and right)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 The Codec parameter has been set
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_set_micboost()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the 20 dB microphone boost.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint64_t val The 1 to enable, 0 to disable.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 The Codec parameter has been set
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_set_micboost(void *arg, uint64_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_set_igain()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the record gain.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint64_t val The gain to set (both left and right)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 The Codec parameter has been set
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_set_inputs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the input ports.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint64_t val The mask of output ports.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 The Codec parameter has been set
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_set_outputs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the output ports.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint64_t val The mask of input ports.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 The Codec parameter has been set
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_set_mgain()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the monitor gain.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint64_t val The gain to set (monoaural).)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 The Codec parameter has been set
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_open()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Opens a DMA engine for use.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to set up
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int flag Open flags
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * unsigned *nframesp Receives number of frames
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * caddr_t *bufp Receives kernel data buffer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 on success
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * errno on failure
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudiocs_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) pm_busy_component(dip, CS4231_COMPONENT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (pm_raise_power(dip, CS4231_COMPONENT, CS4231_PWR_ON) ==
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* match the busy call above */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) pm_idle_component(dip, CS4231_COMPONENT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->cs_adev, "power up failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_close()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Closes an audio DMA engine that was previously opened. Since
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * nobody is using it, we take this opportunity to possibly power
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * down the entire device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to shut down
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) pm_idle_component(state->cs_dip, CS4231_COMPONENT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_stop()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to stop an engine that is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * transferring data.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to stop
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Stop the DMA engine.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Stop the codec.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ANDIDX(state, ~(eng->ce_codec_en), INTC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_start()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to start an engine transferring data.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to start
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 on success, an errno otherwise
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* sample rate only set on play side */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore value = FS_48000 | PDF_STEREO | PDF_LINEAR16NE;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (audiocs_poll_ready(state) != DDI_SUCCESS) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore } else if (CS4231_DMA_START(state, eng) != DDI_SUCCESS) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Start the codec.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ORIDX(state, eng->ce_codec_en, INTC_VALID_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_format()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Called by the framework to query the format of the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_FORMAT_S16_NE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_channels()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Called by the framework to query the channels of the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_rates()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Called by the framework to query the sample rate of the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (48000);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_count()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to get the engine's frame counter
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * frame count for current engine
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Every now and then, we get a value that is just a wee bit
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * too large. This seems to be a small value related to
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * prefetch. Rather than believe it, we just assume the last
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * offset in the buffer. This should allow us to handle
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * wraps, but without inserting bogus sample counts.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* while here, possibly reload the next address */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_sync()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to synchronize DMA caches.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to sync
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_sync(eng->ce_dmah, 0, 0, eng->ce_syncdir);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_alloc_engine()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocates the DMA handles and the memory for the DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *dip Pointer to the device's soft state
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int num Engine number, CS4231_PLAY or CS4231_REC.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Engine initialized.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Engine not initialized.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_alloc_engine(CS_state_t *state, int num)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "bad engine number (%d)!", num);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate dma handle */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_alloc_handle(dip, CS4231_DMA_ATTR(state), DDI_DMA_SLEEP,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "ddi_dma_alloc_handle failed: %d", rc);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate DMA buffer */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore rc = ddi_dma_mem_alloc(eng->ce_dmah, CS4231_BUFSZ, &buf_attr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &eng->ce_kaddr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "dma_mem_alloc failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* bind DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_addr_bind_handle(eng->ce_dmah, NULL,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore eng->ce_kaddr, CS4231_BUFSZ, dir | DDI_DMA_CONSISTENT,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((rc != DDI_DMA_MAPPED) || (ccnt != 1)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore eng->ce_engine = audio_engine_alloc(&audiocs_engine_ops, caps);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "audio_engine_alloc failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_set_private(eng->ce_engine, eng);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_free_engine()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine fress the engine and all associated resources.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_engine_t *eng Engine to free.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_remove_engine(adev, eng->ce_engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_poll_ready()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine waits for the Codec to complete its initialization
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * sequence and is done with its autocalibration.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Early versions of the Codec have a bug that can take as long as
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 15 seconds to complete its initialization. For these cases we
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * use a timeout mechanism so we don't keep the machine locked up.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The Codec is ready to continue
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The Codec isn't ready to continue
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for the chip to initialize itself */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore while ((iar & IAR_INIT) && x++ < CS4231_TIMEOUT) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Now wait for the chip to complete its autocalibration.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the test register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore while ((idr & ESI_ACI) && x++ < CS4231_TIMEOUT) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_sel_index()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Select a cs4231 register. The cs4231 has a hardware bug where a
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * register is not always selected the first time. We try and try
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * again until the proper register is selected or we time out and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * print an error message.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiohdl_t ahandle Handle to this device
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_acc_handle_t handle A handle to the device's registers
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint8_t addr The register address to program
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int reg The register to select
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_sel_index(CS_state_t *state, uint8_t reg, int n)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_sel_index(CS_state_t *state, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (x = 0; x < CS4231_RETRIES; x++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "line %d: Couldn't select index (0x%02x 0x%02x)", n,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Couldn't select index (0x%02x 0x%02x)",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "audio may not work correctly until it is stopped and "
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "restarted");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiocs_put_index()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Program a cs4231 register. The cs4231 has a hardware bug where a
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * register is not programmed properly the first time. We program a value,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * then immediately read back the value and reprogram if nescessary.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We do this until the register is properly programmed or we time out and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * print an error message.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t state Handle to this device
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint8_t mask Mask to not set reserved register bits
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int val The value to program
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_put_index(CS_state_t *state, uint8_t val, uint8_t mask, int n)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiocs_put_index(CS_state_t *state, uint8_t val, uint8_t mask)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (x = 0; x < CS4231_RETRIES; x++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "line %d: Couldn't set value (0x%02x 0x%02x)", n, T, val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Couldn't set value (0x%02x 0x%02x)", T, val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "audio may not work correctly until it is stopped and "
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "restarted");