audio_4231.c revision 11936:54dc8a89ba0d
1254721Semaste/*
2254721Semaste * CDDL HEADER START
3254721Semaste *
4254721Semaste * The contents of this file are subject to the terms of the
5254721Semaste * Common Development and Distribution License (the "License").
6254721Semaste * You may not use this file except in compliance with the License.
7254721Semaste *
8254721Semaste * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9254721Semaste * or http://www.opensolaris.org/os/licensing.
10254721Semaste * See the License for the specific language governing permissions
11254721Semaste * and limitations under the License.
12254721Semaste *
13254721Semaste * When distributing Covered Code, include this CDDL HEADER in each
14254721Semaste * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15254721Semaste * If applicable, add the following below this CDDL HEADER, with the
16254721Semaste * fields enclosed by brackets "[]" replaced with your own identifying
17254721Semaste * information: Portions Copyright [yyyy] [name of copyright owner]
18254721Semaste *
19254721Semaste * CDDL HEADER END
20254721Semaste */
21254721Semaste/*
22254721Semaste * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23254721Semaste * Use is subject to license terms.
24254721Semaste */
25254721Semaste
26254721Semaste
27254721Semaste/*
28254721Semaste * audiocs Audio Driver
29254721Semaste *
30254721Semaste * This Audio Driver controls the Crystal CS4231 Codec used on many SPARC
31254721Semaste * platforms. It does not support the CS4231 on Power PCs or x86 PCs. It
32254721Semaste * does support two different DMA engines, the APC and EB2. The code for
33254721Semaste * those DMA engines is split out and a well defined, but private, interface
34254721Semaste * is used to control those DMA engines.
35254721Semaste *
36254721Semaste * For some reason setting the CS4231's registers doesn't always
37254721Semaste * succeed.  Therefore every time we set a register we always read it
38254721Semaste * back to make sure it was set. If not we wait a little while and
39254721Semaste * then try again. This is all taken care of in the routines
40254721Semaste * audiocs_put_index() and audiocs_sel_index() and the macros ORIDX()
41254721Semaste * and ANDIDX(). We don't worry about the status register because it
42254721Semaste * is cleared by writing anything to it.  So it doesn't matter what
43254721Semaste * the value written is.
44254721Semaste *
45254721Semaste * This driver supports suspending and resuming. A suspend just stops playing
46254721Semaste * and recording. The play DMA buffers end up getting thrown away, but when
47254721Semaste * you shut down the machine there is a break in the audio anyway, so they
48254721Semaste * won't be missed and it isn't worth the effort to save them. When we resume
49254721Semaste * we always start playing and recording. If they aren't needed they get
50254721Semaste * shut off by the mixer.
51254721Semaste *
52254721Semaste * Power management is supported by this driver.
53254721Semaste *
54254721Semaste *	NOTE: This module depends on drv/audio being loaded first.
55254721Semaste */
56254721Semaste
57254721Semaste#include <sys/modctl.h>
58254721Semaste#include <sys/kmem.h>
59254721Semaste#include <sys/stropts.h>
60254721Semaste#include <sys/ddi.h>
61254721Semaste#include <sys/sunddi.h>
62254721Semaste#include <sys/note.h>
63254721Semaste#include <sys/audio/audio_driver.h>
64254721Semaste#include "audio_4231.h"
65254721Semaste
66254721Semaste/*
67254721Semaste * Module linkage routines for the kernel
68254721Semaste */
69254721Semastestatic int audiocs_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
70254721Semastestatic int audiocs_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
71254721Semastestatic int audiocs_ddi_power(dev_info_t *, int, int);
72254721Semaste
73254721Semaste/*
74254721Semaste * Entry point routine prototypes
75254721Semaste */
76254721Semastestatic int audiocs_open(void *, int, unsigned *, caddr_t *);
77254721Semastestatic void audiocs_close(void *);
78254721Semastestatic int audiocs_start(void *);
79254721Semastestatic void audiocs_stop(void *);
80254721Semastestatic int audiocs_format(void *);
81254721Semastestatic int audiocs_channels(void *);
82254721Semastestatic int audiocs_rate(void *);
83254721Semastestatic uint64_t audiocs_count(void *);
84254721Semastestatic void audiocs_sync(void *, unsigned);
85254721Semaste
86254721Semaste/*
87254721Semaste * Control callbacks.
88254721Semaste */
89254721Semastestatic int audiocs_get_value(void *, uint64_t *);
90254721Semastestatic int audiocs_set_ogain(void *, uint64_t);
91254721Semastestatic int audiocs_set_igain(void *, uint64_t);
92254721Semastestatic int audiocs_set_mgain(void *, uint64_t);
93254721Semastestatic int audiocs_set_inputs(void *, uint64_t);
94254721Semastestatic int audiocs_set_outputs(void *, uint64_t);
95254721Semastestatic int audiocs_set_micboost(void *, uint64_t);
96254721Semaste
97254721Semaste/* Local Routines */
98254721Semastestatic int audiocs_resume(dev_info_t *);
99254721Semastestatic int audiocs_attach(dev_info_t *);
100254721Semastestatic int audiocs_detach(dev_info_t *);
101254721Semastestatic int audiocs_suspend(dev_info_t *);
102254721Semaste
103254721Semastestatic void audiocs_destroy(CS_state_t *);
104254721Semastestatic int audiocs_init_state(CS_state_t *);
105254721Semastestatic int audiocs_chip_init(CS_state_t *);
106254721Semastestatic int audiocs_alloc_engine(CS_state_t *, int);
107254721Semastestatic void audiocs_free_engine(CS_engine_t *);
108254721Semastestatic void audiocs_get_ports(CS_state_t *);
109254721Semastestatic void audiocs_configure_input(CS_state_t *);
110254721Semastestatic void audiocs_configure_output(CS_state_t *);
111254721Semastestatic CS_ctrl_t *audiocs_alloc_ctrl(CS_state_t *, uint32_t, uint64_t);
112254721Semastestatic void audiocs_free_ctrl(CS_ctrl_t *);
113254721Semastestatic int audiocs_add_controls(CS_state_t *);
114254721Semastestatic void audiocs_del_controls(CS_state_t *);
115254721Semastestatic void audiocs_power_up(CS_state_t *);
116254721Semastestatic void audiocs_power_down(CS_state_t *);
117254721Semastestatic int audiocs_poll_ready(CS_state_t *);
118254721Semaste#ifdef	DEBUG
119254721Semastestatic void audiocs_put_index(CS_state_t *,  uint8_t, uint8_t, int);
120254721Semastestatic void audiocs_sel_index(CS_state_t *, uint8_t, int);
121254721Semaste#define	SELIDX(s, idx)		audiocs_sel_index(s, idx, __LINE__)
122254721Semaste#define	PUTIDX(s, val, mask)	audiocs_put_index(s, val, mask, __LINE__)
123254721Semaste#else
124254721Semastestatic void audiocs_put_index(CS_state_t *,  uint8_t, uint8_t);
125254721Semastestatic void audiocs_sel_index(CS_state_t *, uint8_t);
126254721Semaste#define	SELIDX(s, idx)		audiocs_sel_index(s, idx)
127254721Semaste#define	PUTIDX(s, val, mask)	audiocs_put_index(s, val, mask)
128254721Semaste#endif
129254721Semaste#define	GETIDX(s)		ddi_get8((handle), &CS4231_IDR)
130254721Semaste
131254721Semaste#define	ORIDX(s, val, mask)						\
132254721Semaste	PUTIDX(s,							\
133254721Semaste	    (ddi_get8((handle), &CS4231_IDR) | (uint8_t)(val)),		\
134254721Semaste	    (uint8_t)(mask))
135254721Semaste
136254721Semaste#define	ANDIDX(s, val, mask)						\
137254721Semaste	PUTIDX(s, (ddi_get8((handle), &CS4231_IDR) & (uint8_t)(val)),	\
138254721Semaste	    (uint8_t)(mask))
139254721Semaste
140254721Semastestatic audio_engine_ops_t audiocs_engine_ops = {
141254721Semaste	AUDIO_ENGINE_VERSION,
142254721Semaste	audiocs_open,
143254721Semaste	audiocs_close,
144254721Semaste	audiocs_start,
145254721Semaste	audiocs_stop,
146254721Semaste	audiocs_count,
147254721Semaste	audiocs_format,
148254721Semaste	audiocs_channels,
149254721Semaste	audiocs_rate,
150254721Semaste	audiocs_sync,
151254721Semaste	NULL,
152254721Semaste	NULL,
153254721Semaste	NULL,
154254721Semaste};
155254721Semaste
156254721Semaste#define	OUTPUT_SPEAKER		0
157254721Semaste#define	OUTPUT_HEADPHONES	1
158254721Semaste#define	OUTPUT_LINEOUT		2
159254721Semaste
160254721Semastestatic const char *audiocs_outputs[] = {
161254721Semaste	AUDIO_PORT_SPEAKER,
162254721Semaste	AUDIO_PORT_HEADPHONES,
163254721Semaste	AUDIO_PORT_LINEOUT,
164254721Semaste	NULL
165254721Semaste};
166254721Semaste
167254721Semaste#define	INPUT_MIC		0
168254721Semaste#define	INPUT_LINEIN		1
169254721Semaste#define	INPUT_STEREOMIX		2
170254721Semaste#define	INPUT_CD		3
171254721Semaste
172254721Semastestatic const char *audiocs_inputs[] = {
173254721Semaste	AUDIO_PORT_MIC,
174254721Semaste	AUDIO_PORT_LINEIN,
175254721Semaste	AUDIO_PORT_STEREOMIX,
176254721Semaste	AUDIO_PORT_CD,
177254721Semaste	NULL
178254721Semaste};
179254721Semaste
180254721Semaste/*
181254721Semaste * Global variables, but viewable only by this file.
182254721Semaste */
183254721Semaste
184254721Semaste/* play gain array, converts linear gain to 64 steps of log10 gain */
185254721Semastestatic uint8_t cs4231_atten[] = {
186254721Semaste	0x3f,	0x3e,	0x3d,	0x3c,	0x3b,	/* [000] -> [004] */
187254721Semaste	0x3a,	0x39,	0x38,	0x37,	0x36,	/* [005] -> [009] */
188254721Semaste	0x35,	0x34,	0x33,	0x32,	0x31,	/* [010] -> [014] */
189254721Semaste	0x30,	0x2f,	0x2e,	0x2d,	0x2c,	/* [015] -> [019] */
190254721Semaste	0x2b,	0x2a,	0x29,	0x29,	0x28,	/* [020] -> [024] */
191254721Semaste	0x28,	0x27,	0x27,	0x26,	0x26,	/* [025] -> [029] */
192254721Semaste	0x25,	0x25,	0x24,	0x24,	0x23,	/* [030] -> [034] */
193254721Semaste	0x23,	0x22,	0x22,	0x21,	0x21,	/* [035] -> [039] */
194254721Semaste	0x20,	0x20,	0x1f,	0x1f,	0x1f,	/* [040] -> [044] */
195254721Semaste	0x1e,	0x1e,	0x1e,	0x1d,	0x1d,	/* [045] -> [049] */
196254721Semaste	0x1d,	0x1c,	0x1c,	0x1c,	0x1b,	/* [050] -> [054] */
197254721Semaste	0x1b,	0x1b,	0x1a,	0x1a,	0x1a,	/* [055] -> [059] */
198254721Semaste	0x1a,	0x19,	0x19,	0x19,	0x19,	/* [060] -> [064] */
199254721Semaste	0x18,	0x18,	0x18,	0x18,	0x17,	/* [065] -> [069] */
200254721Semaste	0x17,	0x17,	0x17,	0x16,	0x16,	/* [070] -> [074] */
201254721Semaste	0x16,	0x16,	0x16,	0x15,	0x15,	/* [075] -> [079] */
202254721Semaste	0x15,	0x15,	0x15,	0x14,	0x14,	/* [080] -> [084] */
203254721Semaste	0x14,	0x14,	0x14,	0x13,	0x13,	/* [085] -> [089] */
204254721Semaste	0x13,	0x13,	0x13,	0x12,	0x12,	/* [090] -> [094] */
205254721Semaste	0x12,	0x12,	0x12,	0x12,	0x11,	/* [095] -> [099] */
206254721Semaste	0x11,	0x11,	0x11,	0x11,	0x11,	/* [100] -> [104] */
207254721Semaste	0x10,	0x10,	0x10,	0x10,	0x10,	/* [105] -> [109] */
208254721Semaste	0x10,	0x0f,	0x0f,	0x0f,	0x0f,	/* [110] -> [114] */
209254721Semaste	0x0f,	0x0f,	0x0e,	0x0e,	0x0e,	/* [114] -> [119] */
210254721Semaste	0x0e,	0x0e,	0x0e,	0x0e,	0x0d,	/* [120] -> [124] */
211254721Semaste	0x0d,	0x0d,	0x0d,	0x0d,	0x0d,	/* [125] -> [129] */
212254721Semaste	0x0d,	0x0c,	0x0c,	0x0c,	0x0c,	/* [130] -> [134] */
213254721Semaste	0x0c,	0x0c,	0x0c,	0x0b,	0x0b,	/* [135] -> [139] */
214254721Semaste	0x0b,	0x0b,	0x0b,	0x0b,	0x0b,	/* [140] -> [144] */
215254721Semaste	0x0b,	0x0a,	0x0a,	0x0a,	0x0a,	/* [145] -> [149] */
216254721Semaste	0x0a,	0x0a,	0x0a,	0x0a,	0x09,	/* [150] -> [154] */
217254721Semaste	0x09,	0x09,	0x09,	0x09,	0x09,	/* [155] -> [159] */
218254721Semaste	0x09,	0x09,	0x08,	0x08,	0x08,	/* [160] -> [164] */
219254721Semaste	0x08,	0x08,	0x08,	0x08,	0x08,	/* [165] -> [169] */
220254721Semaste	0x08,	0x07,	0x07,	0x07,	0x07,	/* [170] -> [174] */
221254721Semaste	0x07,	0x07,	0x07,	0x07,	0x07,	/* [175] -> [179] */
222254721Semaste	0x06,	0x06,	0x06,	0x06,	0x06,	/* [180] -> [184] */
223254721Semaste	0x06,	0x06,	0x06,	0x06,	0x05,	/* [185] -> [189] */
224254721Semaste	0x05,	0x05,	0x05,	0x05,	0x05,	/* [190] -> [194] */
225254721Semaste	0x05,	0x05,	0x05,	0x05,	0x04,	/* [195] -> [199] */
226254721Semaste	0x04,	0x04,	0x04,	0x04,	0x04,	/* [200] -> [204] */
227254721Semaste	0x04,	0x04,	0x04,	0x04,	0x03,	/* [205] -> [209] */
228254721Semaste	0x03,	0x03,	0x03,	0x03,	0x03,	/* [210] -> [214] */
229254721Semaste	0x03,	0x03,	0x03,	0x03,	0x03,	/* [215] -> [219] */
230254721Semaste	0x02,	0x02,	0x02,	0x02,	0x02,	/* [220] -> [224] */
231254721Semaste	0x02,	0x02,	0x02,	0x02,	0x02,	/* [225] -> [229] */
232254721Semaste	0x02,	0x01,	0x01,	0x01,	0x01,	/* [230] -> [234] */
233254721Semaste	0x01,	0x01,	0x01,	0x01,	0x01,	/* [235] -> [239] */
234254721Semaste	0x01,	0x01,	0x01,	0x00,	0x00,	/* [240] -> [244] */
235254721Semaste	0x00,	0x00,	0x00,	0x00,	0x00,	/* [245] -> [249] */
236254721Semaste	0x00,	0x00,	0x00,	0x00,	0x00,	/* [250] -> [254] */
237254721Semaste	0x00					/* [255] */
238254721Semaste};
239254721Semaste
240254721Semaste/*
241254721Semaste * STREAMS Structures
242254721Semaste */
243254721Semaste
244254721Semaste/*
245254721Semaste * DDI Structures
246254721Semaste */
247254721Semaste
248254721Semaste/* Device operations structure */
249254721Semastestatic struct dev_ops audiocs_dev_ops = {
250254721Semaste	DEVO_REV,			/* devo_rev */
251254721Semaste	0,				/* devo_refcnt */
252254721Semaste	NULL,				/* devo_getinfo */
253254721Semaste	nulldev,			/* devo_identify - obsolete */
254254721Semaste	nulldev,			/* devo_probe - not needed */
255254721Semaste	audiocs_ddi_attach,		/* devo_attach */
256254721Semaste	audiocs_ddi_detach,		/* devo_detach */
257254721Semaste	nodev,				/* devo_reset */
258254721Semaste	NULL,				/* devi_cb_ops */
259254721Semaste	NULL,				/* devo_bus_ops */
260254721Semaste	audiocs_ddi_power,		/* devo_power */
261254721Semaste	ddi_quiesce_not_supported,	/* devo_quiesce */
262254721Semaste};
263254721Semaste
264254721Semaste/* Linkage structure for loadable drivers */
265254721Semastestatic struct modldrv audiocs_modldrv = {
266254721Semaste	&mod_driverops,		/* drv_modops */
267254721Semaste	CS4231_MOD_NAME,	/* drv_linkinfo */
268254721Semaste	&audiocs_dev_ops	/* drv_dev_ops */
269254721Semaste};
270254721Semaste
271254721Semaste/* Module linkage structure */
272254721Semastestatic struct modlinkage audiocs_modlinkage = {
273254721Semaste	MODREV_1,			/* ml_rev */
274254721Semaste	(void *)&audiocs_modldrv,	/* ml_linkage */
275254721Semaste	NULL				/* NULL terminates the list */
276254721Semaste};
277254721Semaste
278254721Semaste
279254721Semaste/* *******  Loadable Module Configuration Entry Points  ********************* */
280254721Semaste
281254721Semaste/*
282254721Semaste * _init()
283254721Semaste *
284254721Semaste * Description:
285254721Semaste *	Implements _init(9E).
286254721Semaste *
287254721Semaste * Returns:
288254721Semaste *	mod_install() status, see mod_install(9f)
289254721Semaste */
290254721Semasteint
291254721Semaste_init(void)
292254721Semaste{
293254721Semaste	int	rv;
294254721Semaste
295254721Semaste	audio_init_ops(&audiocs_dev_ops, CS4231_NAME);
296254721Semaste
297254721Semaste	if ((rv = mod_install(&audiocs_modlinkage)) != 0) {
298254721Semaste		audio_fini_ops(&audiocs_dev_ops);
299254721Semaste	}
300254721Semaste
301254721Semaste	return (rv);
302254721Semaste}
303254721Semaste
304254721Semaste/*
305254721Semaste * _fini()
306254721Semaste *
307254721Semaste * Description:
308254721Semaste *	Implements _fini(9E).
309254721Semaste *
310254721Semaste * Returns:
311254721Semaste *	mod_remove() status, see mod_remove(9f)
312254721Semaste */
313254721Semasteint
314254721Semaste_fini(void)
315254721Semaste{
316254721Semaste	int	rv;
317254721Semaste
318254721Semaste	if ((rv = mod_remove(&audiocs_modlinkage)) == 0) {
319254721Semaste		audio_fini_ops(&audiocs_dev_ops);
320254721Semaste	}
321254721Semaste
322254721Semaste	return (rv);
323254721Semaste}
324254721Semaste
325254721Semaste/*
326254721Semaste * _info()
327254721Semaste *
328254721Semaste * Description:
329254721Semaste *	Implements _info(9E).
330254721Semaste *
331254721Semaste * Arguments:
332254721Semaste *	modinfo *modinfop	Pointer to the opaque modinfo structure
333254721Semaste *
334254721Semaste * Returns:
335254721Semaste *	mod_info() status, see mod_info(9f)
336254721Semaste */
337254721Semasteint
338254721Semaste_info(struct modinfo *modinfop)
339254721Semaste{
340254721Semaste	return (mod_info(&audiocs_modlinkage, modinfop));
341254721Semaste}
342254721Semaste
343254721Semaste
344254721Semaste/* *******  Driver Entry Points  ******************************************** */
345254721Semaste
346254721Semaste/*
347254721Semaste * audiocs_ddi_attach()
348254721Semaste *
349254721Semaste * Description:
350254721Semaste *	Implement attach(9e).
351254721Semaste *
352254721Semaste * Arguments:
353254721Semaste *	dev_info_t	*dip	Pointer to the device's dev_info struct
354254721Semaste *	ddi_attach_cmd_t cmd	Attach command
355254721Semaste *
356254721Semaste * Returns:
357254721Semaste *	DDI_SUCCESS		The driver was initialized properly
358254721Semaste *	DDI_FAILURE		The driver couldn't be initialized properly
359254721Semaste */
360254721Semastestatic int
361254721Semasteaudiocs_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
362254721Semaste{
363254721Semaste	switch (cmd) {
364254721Semaste	case DDI_ATTACH:
365254721Semaste		return (audiocs_attach(dip));
366254721Semaste
367254721Semaste	case DDI_RESUME:
368254721Semaste		return (audiocs_resume(dip));
369254721Semaste
370254721Semaste	default:
371254721Semaste		return (DDI_FAILURE);
372254721Semaste	}
373254721Semaste}
374254721Semaste
375254721Semaste/*
376254721Semaste * audiocs_ddi_detach()
377254721Semaste *
378254721Semaste * Description:
379254721Semaste *	Implement detach(9e).
380254721Semaste *
381254721Semaste * Arguments:
382254721Semaste *	dev_info_t	*dip	Pointer to the device's dev_info struct
383254721Semaste *	ddi_detach_cmd_t cmd	Detach command
384254721Semaste *
385254721Semaste * Returns:
386254721Semaste *	DDI_SUCCESS		Success.
387254721Semaste *	DDI_FAILURE		Failure.
388254721Semaste */
389254721Semastestatic int
390254721Semasteaudiocs_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
391254721Semaste{
392254721Semaste	switch (cmd) {
393254721Semaste	case DDI_DETACH:
394254721Semaste		return (audiocs_detach(dip));
395254721Semaste
396254721Semaste	case DDI_SUSPEND:
397254721Semaste		return (audiocs_suspend(dip));
398254721Semaste
399254721Semaste	default:
400254721Semaste		return (DDI_FAILURE);
401254721Semaste	}
402254721Semaste}
403254721Semaste
404254721Semaste/*
405254721Semaste * audiocs_ddi_power()
406254721Semaste *
407254721Semaste * Description:
408254721Semaste *	Implements power(9E).
409254721Semaste *
410254721Semaste * Arguments:
411254721Semaste *	def_info_t	*dip		Ptr to the device's dev_info structure
412254721Semaste *	int		component	Which component to power up/down
413254721Semaste *	int		level		The power level for the component
414254721Semaste *
415254721Semaste * Returns:
416254721Semaste *	DDI_SUCCESS		Power level changed, we always succeed
417254721Semaste */
418254721Semastestatic int
419254721Semasteaudiocs_ddi_power(dev_info_t *dip, int component, int level)
420254721Semaste{
421254721Semaste	CS_state_t		*state;
422254721Semaste
423254721Semaste	if (component != CS4231_COMPONENT)
424254721Semaste		return (DDI_FAILURE);
425254721Semaste
426254721Semaste	/* get the state structure */
427254721Semaste	state = ddi_get_driver_private(dip);
428254721Semaste
429254721Semaste	ASSERT(!mutex_owned(&state->cs_lock));
430254721Semaste
431254721Semaste	/* make sure we have some work to do */
432254721Semaste	mutex_enter(&state->cs_lock);
433254721Semaste
434254721Semaste	/*
435254721Semaste	 * We don't do anything if we're suspended.  Suspend/resume diddles
436254721Semaste	 * with power anyway.
437254721Semaste	 */
438254721Semaste	if (!state->cs_suspended) {
439254721Semaste
440254721Semaste		/* check the level change to see what we need to do */
441254721Semaste		if (level == CS4231_PWR_OFF && state->cs_powered) {
442254721Semaste
443254721Semaste			/* power down and save the state */
444254721Semaste			audiocs_power_down(state);
445254721Semaste			state->cs_powered = B_FALSE;
446254721Semaste
447254721Semaste		} else if (level == CS4231_PWR_ON && !state->cs_powered) {
448254721Semaste
449254721Semaste			/* power up */
450254721Semaste			audiocs_power_up(state);
451254721Semaste			state->cs_powered = B_TRUE;
452254721Semaste		}
453254721Semaste	}
454254721Semaste
455254721Semaste	mutex_exit(&state->cs_lock);
456254721Semaste
457254721Semaste	ASSERT(!mutex_owned(&state->cs_lock));
458254721Semaste
459254721Semaste	return (DDI_SUCCESS);
460254721Semaste}
461254721Semaste
462254721Semaste/* ******* Local Routines *************************************************** */
463254721Semaste
464254721Semastestatic void
465254721Semasteaudiocs_destroy(CS_state_t *state)
466254721Semaste{
467254721Semaste	if (state == NULL)
468254721Semaste		return;
469254721Semaste
470254721Semaste	for (int i = CS4231_PLAY; i <= CS4231_REC; i++) {
471254721Semaste		audiocs_free_engine(state->cs_engines[i]);
472254721Semaste	}
473254721Semaste	audiocs_del_controls(state);
474254721Semaste
475254721Semaste	if (state->cs_adev) {
476254721Semaste		audio_dev_free(state->cs_adev);
477254721Semaste	}
478254721Semaste
479254721Semaste	/* unmap the registers */
480254721Semaste	CS4231_DMA_UNMAP_REGS(state);
481254721Semaste
482254721Semaste	/* destroy the state mutex */
483254721Semaste	mutex_destroy(&state->cs_lock);
484254721Semaste	kmem_free(state, sizeof (*state));
485254721Semaste}
486254721Semaste
487254721Semaste/*
488254721Semaste * audiocs_attach()
489254721Semaste *
490254721Semaste * Description:
491254721Semaste *	Attach an instance of the CS4231 driver. This routine does the device
492254721Semaste *	dependent attach tasks.  When it is complete it calls
493254721Semaste *	audio_dev_register() to register with the framework.
494254721Semaste *
495254721Semaste * Arguments:
496254721Semaste *	dev_info_t	*dip	Pointer to the device's dev_info struct
497254721Semaste *
498254721Semaste * Returns:
499254721Semaste *	DDI_SUCCESS		The driver was initialized properly
500254721Semaste *	DDI_FAILURE		The driver couldn't be initialized properly
501254721Semaste */
502254721Semastestatic int
503254721Semasteaudiocs_attach(dev_info_t *dip)
504254721Semaste{
505254721Semaste	CS_state_t		*state;
506254721Semaste	audio_dev_t		*adev;
507254721Semaste
508254721Semaste	/* allocate the state structure */
509254721Semaste	state = kmem_zalloc(sizeof (*state), KM_SLEEP);
510254721Semaste	state->cs_dip = dip;
511254721Semaste	ddi_set_driver_private(dip, state);
512254721Semaste
513254721Semaste	/* now fill it in, initialize the state mutexs first */
514254721Semaste	mutex_init(&state->cs_lock, NULL, MUTEX_DRIVER, NULL);
515254721Semaste
516254721Semaste	/*
517254721Semaste	 * audio state initialization... should always succeed,
518254721Semaste	 * framework will message failure.
519254721Semaste	 */
520254721Semaste	if ((state->cs_adev = audio_dev_alloc(dip, 0)) == NULL) {
521254721Semaste		goto error;
522254721Semaste	}
523254721Semaste	adev = state->cs_adev;
524254721Semaste	audio_dev_set_description(adev, CS_DEV_CONFIG_ONBRD1);
525254721Semaste	audio_dev_add_info(adev, "Legacy codec: Crystal Semiconductor CS4231");
526254721Semaste
527254721Semaste	/* initialize the audio state structures */
528254721Semaste	if ((audiocs_init_state(state)) == DDI_FAILURE) {
529254721Semaste		audio_dev_warn(adev, "init_state() failed");
530254721Semaste		goto error;
531254721Semaste	}
532254721Semaste
533254721Semaste	mutex_enter(&state->cs_lock);
534254721Semaste
535254721Semaste	/* initialize the audio chip */
536254721Semaste	if ((audiocs_chip_init(state)) == DDI_FAILURE) {
537254721Semaste		mutex_exit(&state->cs_lock);
538254721Semaste		audio_dev_warn(adev, "chip_init() failed");
539254721Semaste		goto error;
540254721Semaste	}
541254721Semaste	/* chip init will have powered us up */
542254721Semaste	state->cs_powered = B_TRUE;
543254721Semaste
544254721Semaste	mutex_exit(&state->cs_lock);
545254721Semaste
546254721Semaste	/* finally register with framework to kick everything off */
547254721Semaste	if (audio_dev_register(state->cs_adev) != DDI_SUCCESS) {
548254721Semaste		audio_dev_warn(state->cs_adev, "unable to register audio dev");
549254721Semaste	}
550254721Semaste
551254721Semaste	/* everything worked out, so report the device */
552254721Semaste	ddi_report_dev(dip);
553254721Semaste
554254721Semaste	return (DDI_SUCCESS);
555254721Semaste
556254721Semasteerror:
557254721Semaste	audiocs_destroy(state);
558254721Semaste	return (DDI_FAILURE);
559254721Semaste}
560254721Semaste
561254721Semaste/*
562254721Semaste * audiocs_resume()
563254721Semaste *
564254721Semaste * Description:
565254721Semaste *	Resume a suspended device instance.
566254721Semaste *
567254721Semaste * Arguments:
568254721Semaste *	dev_info_t	*dip	Pointer to the device's dev_info struct
569254721Semaste *
570254721Semaste * Returns:
571254721Semaste *	DDI_SUCCESS		The driver was initialized properly
572254721Semaste *	DDI_FAILURE		The driver couldn't be initialized properly
573254721Semaste */
574254721Semastestatic int
575254721Semasteaudiocs_resume(dev_info_t *dip)
576254721Semaste{
577254721Semaste	CS_state_t		*state;
578254721Semaste	audio_dev_t		*adev;
579254721Semaste
580254721Semaste	/* we've already allocated the state structure so get ptr */
581254721Semaste	state = ddi_get_driver_private(dip);
582254721Semaste	adev = state->cs_adev;
583254721Semaste
584254721Semaste	ASSERT(dip == state->cs_dip);
585254721Semaste	ASSERT(!mutex_owned(&state->cs_lock));
586254721Semaste
587254721Semaste	/* mark the Codec busy -- this should keep power(9e) away */
588254721Semaste	(void) pm_busy_component(state->cs_dip, CS4231_COMPONENT);
589254721Semaste
590254721Semaste	/* power it up */
591254721Semaste	audiocs_power_up(state);
592254721Semaste	state->cs_powered = B_TRUE;
593254721Semaste
594254721Semaste	mutex_enter(&state->cs_lock);
595254721Semaste
596254721Semaste	/* initialize the audio chip */
597254721Semaste	if ((audiocs_chip_init(state)) == DDI_FAILURE) {
598254721Semaste		mutex_exit(&state->cs_lock);
599254721Semaste		audio_dev_warn(adev, "chip_init() failed");
600254721Semaste		(void) pm_idle_component(state->cs_dip, CS4231_COMPONENT);
601254721Semaste		return (DDI_FAILURE);
602254721Semaste	}
603254721Semaste
604254721Semaste	state->cs_suspended = B_FALSE;
605254721Semaste
606254721Semaste	mutex_exit(&state->cs_lock);
607254721Semaste
608254721Semaste	/*
609254721Semaste	 * We have already powered up the chip, but this alerts the
610254721Semaste	 * framework to the fact.
611254721Semaste	 */
612254721Semaste	(void) pm_raise_power(dip, CS4231_COMPONENT, CS4231_PWR_ON);
613254721Semaste	(void) pm_idle_component(state->cs_dip, CS4231_COMPONENT);
614254721Semaste
615254721Semaste	audio_dev_resume(state->cs_adev);
616254721Semaste
617254721Semaste	return (DDI_SUCCESS);
618254721Semaste}
619254721Semaste
620254721Semaste/*
621254721Semaste * audiocs_detach()
622254721Semaste *
623254721Semaste * Description:
624254721Semaste *	Detach an instance of the CS4231 driver.
625254721Semaste *
626254721Semaste * Arguments:
627254721Semaste *	dev_info_t	*dip	Pointer to the device's dev_info struct
628254721Semaste *
629254721Semaste * Returns:
630254721Semaste *	DDI_SUCCESS		The driver was detached
631254721Semaste *	DDI_FAILURE		The driver couldn't be detached (busy)
632254721Semaste */
633254721Semastestatic int
634254721Semasteaudiocs_detach(dev_info_t *dip)
635254721Semaste{
636254721Semaste	CS_state_t		*state;
637254721Semaste	audio_dev_t		*adev;
638254721Semaste	ddi_acc_handle_t	handle;
639254721Semaste
640254721Semaste	/* get the state structure */
641254721Semaste	state = ddi_get_driver_private(dip);
642254721Semaste	handle = CODEC_HANDLE;
643254721Semaste	adev = state->cs_adev;
644254721Semaste
645254721Semaste	/* don't detach if still in use */
646254721Semaste	if (audio_dev_unregister(adev) != DDI_SUCCESS) {
647254721Semaste		return (DDI_FAILURE);
648254721Semaste	}
649254721Semaste
650254721Semaste	if (state->cs_powered) {
651254721Semaste		/*
652254721Semaste		 * Make sure the Codec and DMA engine are off.
653254721Semaste		 */
654254721Semaste		SELIDX(state, INTC_REG);
655254721Semaste		ANDIDX(state, ~(INTC_PEN|INTC_CEN), INTC_VALID_MASK);
656254721Semaste
657254721Semaste		/* make sure the DMA engine isn't going to do anything */
658254721Semaste		CS4231_DMA_RESET(state);
659254721Semaste
660254721Semaste		/*
661254721Semaste		 * power down the device, no reason to waste power without
662254721Semaste		 * a driver
663254721Semaste		 */
664254721Semaste		(void) pm_lower_power(dip, CS4231_COMPONENT, CS4231_PWR_OFF);
665254721Semaste	}
666254721Semaste
667254721Semaste	audiocs_destroy(state);
668254721Semaste
669254721Semaste	return (DDI_SUCCESS);
670254721Semaste}
671254721Semaste
672254721Semaste/*
673254721Semaste * audiocs_suspend()
674254721Semaste *
675254721Semaste * Description:
676254721Semaste *	Suspend an instance of the CS4231 driver.
677254721Semaste *
678254721Semaste * Arguments:
679254721Semaste *	dev_info_t	*dip	Pointer to the device's dev_info struct
680254721Semaste *
681254721Semaste * Returns:
682254721Semaste *	DDI_SUCCESS		The driver was detached
683254721Semaste *	DDI_FAILURE		The driver couldn't be detached
684254721Semaste */
685254721Semastestatic int
686254721Semasteaudiocs_suspend(dev_info_t *dip)
687254721Semaste{
688254721Semaste	CS_state_t		*state;
689254721Semaste
690254721Semaste	/* get the state structure */
691254721Semaste	state = ddi_get_driver_private(dip);
692254721Semaste
693254721Semaste	mutex_enter(&state->cs_lock);
694254721Semaste
695254721Semaste	ASSERT(!state->cs_suspended);
696254721Semaste
697254721Semaste	audio_dev_suspend(state->cs_adev);
698254721Semaste
699254721Semaste	if (state->cs_powered) {
700254721Semaste		/* now we can power down the Codec */
701254721Semaste		audiocs_power_down(state);
702254721Semaste		state->cs_powered = B_FALSE;
703254721Semaste	}
704254721Semaste	state->cs_suspended = B_TRUE;	/* stop new ops */
705254721Semaste	mutex_exit(&state->cs_lock);
706254721Semaste
707254721Semaste	return (DDI_SUCCESS);
708254721Semaste}
709254721Semaste
710254721Semaste#define	PLAYCTL	(AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
711254721Semaste#define	RECCTL	(AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
712254721Semaste#define	MONCTL	(AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
713254721Semaste#define	PCMVOL	(PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
714254721Semaste#define	MAINVOL	(PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
715254721Semaste#define	RECVOL	(RECCTL | AUDIO_CTRL_FLAG_RECVOL)
716254721Semaste#define	MONVOL	(MONCTL | AUDIO_CTRL_FLAG_MONVOL)
717254721Semaste
718254721Semaste/*
719254721Semaste * audiocs_alloc_ctrl
720254721Semaste *
721254721Semaste * Description:
722254721Semaste *	Allocates a control structure for the audio mixer.
723254721Semaste *
724254721Semaste * Arguments:
725254721Semaste *	CS_state_t	*state		Device soft state.
726254721Semaste *	uint32_t	num		Control number to allocate.
727254721Semaste *	uint64_t	val		Initial value.
728254721Semaste *
729254721Semaste * Returns:
730254721Semaste *	Pointer to newly allocated CS_ctrl_t structure.
731254721Semaste */
732254721Semastestatic CS_ctrl_t *
733254721Semasteaudiocs_alloc_ctrl(CS_state_t *state, uint32_t num, uint64_t val)
734254721Semaste{
735254721Semaste	audio_ctrl_desc_t	desc;
736254721Semaste	audio_ctrl_wr_t		fn;
737254721Semaste	CS_ctrl_t		*cc;
738254721Semaste
739254721Semaste	cc = kmem_zalloc(sizeof (*cc), KM_SLEEP);
740254721Semaste	cc->cc_state = state;
741254721Semaste	cc->cc_num = num;
742254721Semaste
743254721Semaste	bzero(&desc, sizeof (desc));
744254721Semaste
745254721Semaste	switch (num) {
746254721Semaste	case CTL_VOLUME:
747254721Semaste		desc.acd_name = AUDIO_CTRL_ID_VOLUME;
748254721Semaste		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
749254721Semaste		desc.acd_minvalue = 0;
750254721Semaste		desc.acd_maxvalue = 100;
751254721Semaste		desc.acd_flags = PCMVOL;
752254721Semaste		fn = audiocs_set_ogain;
753254721Semaste		break;
754254721Semaste
755254721Semaste	case CTL_IGAIN:
756254721Semaste		desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
757254721Semaste		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
758254721Semaste		desc.acd_minvalue = 0;
759254721Semaste		desc.acd_maxvalue = 100;
760254721Semaste		desc.acd_flags = RECVOL;
761254721Semaste		fn = audiocs_set_igain;
762254721Semaste		break;
763254721Semaste
764254721Semaste	case CTL_MGAIN:
765254721Semaste		desc.acd_name = AUDIO_CTRL_ID_MONGAIN;
766254721Semaste		desc.acd_type = AUDIO_CTRL_TYPE_MONO;
767254721Semaste		desc.acd_minvalue = 0;
768254721Semaste		desc.acd_maxvalue = 100;
769254721Semaste		desc.acd_flags = MONVOL;
770254721Semaste		fn = audiocs_set_mgain;
771254721Semaste		break;
772254721Semaste
773254721Semaste	case CTL_INPUTS:
774254721Semaste		desc.acd_name = AUDIO_CTRL_ID_RECSRC;
775254721Semaste		desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
776254721Semaste		desc.acd_minvalue = state->cs_imask;
777254721Semaste		desc.acd_maxvalue = state->cs_imask;
778254721Semaste		desc.acd_flags = RECCTL;
779254721Semaste		for (int i = 0; audiocs_inputs[i]; i++) {
780254721Semaste			desc.acd_enum[i] = audiocs_inputs[i];
781254721Semaste		}
782254721Semaste		fn = audiocs_set_inputs;
783254721Semaste
784254721Semaste		break;
785254721Semaste
786254721Semaste	case CTL_OUTPUTS:
787254721Semaste		desc.acd_name = AUDIO_CTRL_ID_OUTPUTS;
788254721Semaste		desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
789254721Semaste		desc.acd_minvalue = state->cs_omod;
790254721Semaste		desc.acd_maxvalue = state->cs_omask;
791254721Semaste		desc.acd_flags = PLAYCTL | AUDIO_CTRL_FLAG_MULTI;
792254721Semaste		for (int i = 0; audiocs_outputs[i]; i++) {
793254721Semaste			desc.acd_enum[i] = audiocs_outputs[i];
794254721Semaste		}
795254721Semaste		fn = audiocs_set_outputs;
796254721Semaste		break;
797254721Semaste
798254721Semaste	case CTL_MICBOOST:
799254721Semaste		desc.acd_name = AUDIO_CTRL_ID_MICBOOST;
800254721Semaste		desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
801254721Semaste		desc.acd_minvalue = 0;
802254721Semaste		desc.acd_maxvalue = 1;
803254721Semaste		desc.acd_flags = RECCTL;
804254721Semaste		fn = audiocs_set_micboost;
805254721Semaste		break;
806254721Semaste	}
807254721Semaste
808254721Semaste	cc->cc_val = val;
809254721Semaste	cc->cc_ctrl = audio_dev_add_control(state->cs_adev, &desc,
810254721Semaste	    audiocs_get_value, fn, cc);
811254721Semaste
812254721Semaste	return (cc);
813254721Semaste}
814254721Semaste
815254721Semaste/*
816254721Semaste * audiocs_free_ctrl
817254721Semaste *
818254721Semaste * Description:
819254721Semaste *	Frees a control and all resources associated with it.
820254721Semaste *
821254721Semaste * Arguments:
822254721Semaste *	CS_ctrl_t	*cc	Pointer to control structure.
823254721Semaste */
824254721Semastestatic void
825254721Semasteaudiocs_free_ctrl(CS_ctrl_t *cc)
826254721Semaste{
827254721Semaste	if (cc == NULL)
828254721Semaste		return;
829254721Semaste	if (cc->cc_ctrl)
830254721Semaste		audio_dev_del_control(cc->cc_ctrl);
831254721Semaste	kmem_free(cc, sizeof (*cc));
832254721Semaste}
833254721Semaste
834254721Semaste/*
835254721Semaste * audiocs_add_controls
836254721Semaste *
837254721Semaste * Description:
838254721Semaste *	Allocates and registers all controls for this device.
839254721Semaste *
840254721Semaste * Arguments:
841254721Semaste *	CS_state_t	*state		Device soft state.
842254721Semaste *
843254721Semaste * Returns:
844254721Semaste *	DDI_SUCCESS	All controls added and registered
845254721Semaste *	DDI_FAILURE	At least one control was not added or registered.
846254721Semaste */
847254721Semastestatic int
848254721Semasteaudiocs_add_controls(CS_state_t *state)
849254721Semaste{
850254721Semaste#define	ADD_CTRL(CTL, ID, VAL)						\
851254721Semaste	state->cs_##CTL = audiocs_alloc_ctrl(state, ID, VAL);		\
852254721Semaste	if (state->cs_##CTL == NULL) {					\
853254721Semaste		audio_dev_warn(state->cs_adev,				\
854254721Semaste		    "unable to allocate %s control", #ID);		\
855254721Semaste		return (DDI_FAILURE);					\
856254721Semaste	}
857254721Semaste
858254721Semaste	ADD_CTRL(ogain, CTL_VOLUME, 0x4b4b);
859254721Semaste	ADD_CTRL(igain, CTL_IGAIN, 0x3232);
860254721Semaste	ADD_CTRL(mgain, CTL_MGAIN, 0);
861254721Semaste	ADD_CTRL(micboost, CTL_MICBOOST, 0);
862254721Semaste	ADD_CTRL(outputs, CTL_OUTPUTS, (state->cs_omask & ~state->cs_omod) |
863254721Semaste	    (1U << OUTPUT_SPEAKER));
864254721Semaste	ADD_CTRL(inputs, CTL_INPUTS, (1U << INPUT_MIC));
865254721Semaste
866254721Semaste	return (DDI_SUCCESS);
867254721Semaste}
868254721Semaste
869254721Semaste/*
870254721Semaste * audiocs_del_controls
871254721Semaste *
872254721Semaste * Description:
873254721Semaste *	Unregisters and frees all controls for this device.
874254721Semaste *
875254721Semaste * Arguments:
876254721Semaste *	CS_state_t	*state		Device soft state.
877254721Semaste */
878254721Semastevoid
879254721Semasteaudiocs_del_controls(CS_state_t *state)
880254721Semaste{
881254721Semaste	audiocs_free_ctrl(state->cs_ogain);
882254721Semaste	audiocs_free_ctrl(state->cs_igain);
883254721Semaste	audiocs_free_ctrl(state->cs_mgain);
884254721Semaste	audiocs_free_ctrl(state->cs_micboost);
885254721Semaste	audiocs_free_ctrl(state->cs_inputs);
886254721Semaste	audiocs_free_ctrl(state->cs_outputs);
887254721Semaste}
888254721Semaste
889254721Semaste
890254721Semaste/*
891254721Semaste * audiocs_chip_init()
892254721Semaste *
893254721Semaste * Description:
894254721Semaste *	Power up the audio core, initialize the audio Codec, prepare the chip
895254721Semaste *	for use.
896254721Semaste *
897254721Semaste * Arguments:
898254721Semaste *	CS_state_t	*state		The device's state structure
899254721Semaste *
900254721Semaste * Returns:
901254721Semaste *	DDI_SUCCESS			Chip initialized and ready to use
902254721Semaste *	DDI_FAILURE			Chip not initialized and not ready
903254721Semaste */
904254721Semastestatic int
905254721Semasteaudiocs_chip_init(CS_state_t *state)
906254721Semaste{
907254721Semaste	ddi_acc_handle_t	handle = CODEC_HANDLE;
908254721Semaste
909254721Semaste	/* make sure we are powered up */
910254721Semaste	CS4231_DMA_POWER(state, CS4231_PWR_ON);
911254721Semaste
912254721Semaste	CS4231_DMA_RESET(state);
913254721Semaste
914254721Semaste	/* wait for the Codec before we continue */
915254721Semaste	if (audiocs_poll_ready(state) == DDI_FAILURE) {
916254721Semaste		return (DDI_FAILURE);
917254721Semaste	}
918254721Semaste
919254721Semaste	/* activate registers 16 -> 31 */
920254721Semaste	SELIDX(state, MID_REG);
921254721Semaste	ddi_put8(handle, &CS4231_IDR, MID_MODE2);
922254721Semaste
923254721Semaste	/* now figure out what version we have */
924254721Semaste	SELIDX(state, VID_REG);
925254721Semaste	if (ddi_get8(handle, &CS4231_IDR) & VID_A) {
926254721Semaste		state->cs_revA = B_TRUE;
927254721Semaste	} else {
928254721Semaste		state->cs_revA = B_FALSE;
929254721Semaste	}
930254721Semaste
931254721Semaste	/* get rid of annoying popping by muting the output channels */
932254721Semaste	SELIDX(state, LDACO_REG);
933254721Semaste	PUTIDX(state, LDACO_LDM | LDACO_MID_GAIN, LDAC0_VALID_MASK);
934254721Semaste	SELIDX(state, RDACO_REG);
935254721Semaste	PUTIDX(state, RDACO_RDM | RDACO_MID_GAIN, RDAC0_VALID_MASK);
936254721Semaste
937254721Semaste	/* initialize aux input channels to known gain values & muted */
938254721Semaste	SELIDX(state, LAUX1_REG);
939254721Semaste	PUTIDX(state, LAUX1_LX1M | LAUX1_UNITY_GAIN, LAUX1_VALID_MASK);
940254721Semaste	SELIDX(state, RAUX1_REG);
941254721Semaste	PUTIDX(state, RAUX1_RX1M | RAUX1_UNITY_GAIN, RAUX1_VALID_MASK);
942254721Semaste	SELIDX(state, LAUX2_REG);
943254721Semaste	PUTIDX(state, LAUX2_LX2M | LAUX2_UNITY_GAIN, LAUX2_VALID_MASK);
944254721Semaste	SELIDX(state, RAUX2_REG);
945254721Semaste	PUTIDX(state, RAUX2_RX2M | RAUX2_UNITY_GAIN, RAUX2_VALID_MASK);
946254721Semaste
947254721Semaste	/* initialize aux input channels to known gain values & muted */
948254721Semaste	SELIDX(state, LLIC_REG);
949254721Semaste	PUTIDX(state, LLIC_LLM | LLIC_UNITY_GAIN, LLIC_VALID_MASK);
950254721Semaste	SELIDX(state, RLIC_REG);
951254721Semaste	PUTIDX(state, RLIC_RLM | RLIC_UNITY_GAIN, RLIC_VALID_MASK);
952254721Semaste
953254721Semaste	/* program the sample rate, play and capture must be the same */
954254721Semaste	SELIDX(state, FSDF_REG | IAR_MCE);
955254721Semaste	PUTIDX(state, FS_48000 | PDF_LINEAR16NE | PDF_STEREO, FSDF_VALID_MASK);
956254721Semaste	if (audiocs_poll_ready(state) == DDI_FAILURE) {
957254721Semaste		return (DDI_FAILURE);
958254721Semaste	}
959254721Semaste
960254721Semaste	SELIDX(state, CDF_REG | IAR_MCE);
961254721Semaste	PUTIDX(state, CDF_LINEAR16NE | CDF_STEREO, CDF_VALID_MASK);
962254721Semaste	if (audiocs_poll_ready(state) == DDI_FAILURE) {
963254721Semaste		return (DDI_FAILURE);
964254721Semaste	}
965254721Semaste
966254721Semaste	/*
967254721Semaste	 * Set up the Codec for playback and capture disabled, dual DMA, and
968254721Semaste	 * playback and capture DMA.
969254721Semaste	 */
970254721Semaste	SELIDX(state, (INTC_REG | IAR_MCE));
971254721Semaste	PUTIDX(state, INTC_DDC | INTC_PDMA | INTC_CDMA, INTC_VALID_MASK);
972254721Semaste	if (audiocs_poll_ready(state) == DDI_FAILURE) {
973254721Semaste		return (DDI_FAILURE);
974254721Semaste	}
975254721Semaste
976254721Semaste	/*
977254721Semaste	 * Turn on the output level bit to be 2.8 Vpp. Also, don't go to 0 on
978254721Semaste	 * underflow.
979254721Semaste	 */
980254721Semaste	SELIDX(state, AFE1_REG);
981254721Semaste	PUTIDX(state, AFE1_OLB, AFE1_VALID_MASK);
982254721Semaste
983254721Semaste	/* turn on the high pass filter if Rev A */
984254721Semaste	SELIDX(state, AFE2_REG);
985254721Semaste	if (state->cs_revA) {
986254721Semaste		PUTIDX(state, AFE2_HPF, AFE2_VALID_MASK);
987254721Semaste	} else {
988254721Semaste		PUTIDX(state, 0, AFE2_VALID_MASK);
989254721Semaste	}
990254721Semaste
991254721Semaste
992254721Semaste	/* clear the play and capture interrupt flags */
993254721Semaste	SELIDX(state, AFS_REG);
994254721Semaste	ddi_put8(handle, &CS4231_STATUS, (AFS_RESET_STATUS));
995254721Semaste
996254721Semaste	/* the play and record gains will be set by the audio mixer */
997254721Semaste
998254721Semaste	/* unmute the output */
999254721Semaste	SELIDX(state, LDACO_REG);
1000254721Semaste	ANDIDX(state, ~LDACO_LDM, LDAC0_VALID_MASK);
1001254721Semaste	SELIDX(state, RDACO_REG);
1002254721Semaste	ANDIDX(state, ~RDACO_RDM, RDAC0_VALID_MASK);
1003254721Semaste
1004254721Semaste	/* unmute the mono speaker and mute mono in */
1005254721Semaste	SELIDX(state, MIOC_REG);
1006254721Semaste	PUTIDX(state, MIOC_MIM, MIOC_VALID_MASK);
1007254721Semaste
1008254721Semaste	audiocs_configure_output(state);
1009254721Semaste	audiocs_configure_input(state);
1010254721Semaste
1011254721Semaste	return (DDI_SUCCESS);
1012254721Semaste}
1013254721Semaste
1014254721Semaste/*
1015254721Semaste * audiocs_init_state()
1016254721Semaste *
1017254721Semaste * Description:
1018254721Semaste *	This routine initializes the audio driver's state structure and
1019254721Semaste *	maps in the registers. This also includes reading the properties.
1020254721Semaste *
1021254721Semaste *	CAUTION: This routine maps the registers and initializes a mutex.
1022254721Semaste *		 Failure cleanup is handled by cs4231_attach(). It is not
1023254721Semaste *		 handled locally by this routine.
1024254721Semaste *
1025254721Semaste * Arguments:
1026254721Semaste *	CS_state_t	*state		The device's state structure
1027254721Semaste *
1028254721Semaste * Returns:
1029254721Semaste *	DDI_SUCCESS			State structure initialized
1030254721Semaste *	DDI_FAILURE			State structure not initialized
1031254721Semaste */
1032254721Semastestatic int
1033254721Semasteaudiocs_init_state(CS_state_t *state)
1034254721Semaste{
1035254721Semaste	audio_dev_t	*adev = state->cs_adev;
1036254721Semaste	dev_info_t	*dip = state->cs_dip;
1037254721Semaste	char		*prop_str;
1038254721Semaste	char		*pm_comp[] = {
1039254721Semaste				"NAME=audiocs audio device",
1040254721Semaste				"0=off",
1041254721Semaste				"1=on" };
1042254721Semaste
1043254721Semaste	/* set up the pm-components */
1044254721Semaste	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1045254721Semaste	    "pm-components", pm_comp, 3) != DDI_PROP_SUCCESS) {
1046254721Semaste		audio_dev_warn(adev, "couldn't create pm-components property");
1047254721Semaste		return (DDI_FAILURE);
1048254721Semaste	}
1049254721Semaste
1050254721Semaste	/* figure out which DMA engine hardware we have */
1051254721Semaste	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1052254721Semaste	    "dma-model", &prop_str) == DDI_PROP_SUCCESS) {
1053254721Semaste		if (strcmp(prop_str, "eb2dma") == 0) {
1054254721Semaste			state->cs_dma_engine = EB2_DMA;
1055254721Semaste			state->cs_dma_ops = &cs4231_eb2dma_ops;
1056254721Semaste		} else {
1057254721Semaste			state->cs_dma_engine = APC_DMA;
1058254721Semaste			state->cs_dma_ops = &cs4231_apcdma_ops;
1059254721Semaste		}
1060254721Semaste		ddi_prop_free(prop_str);
1061254721Semaste	} else {
1062254721Semaste		state->cs_dma_engine = APC_DMA;
1063254721Semaste		state->cs_dma_ops = &cs4231_apcdma_ops;
1064254721Semaste	}
1065254721Semaste
1066254721Semaste	/* cs_regs, cs_eb2_regs and cs_handles filled in later */
1067254721Semaste
1068254721Semaste	/* most of what's left is filled in when the registers are mapped */
1069254721Semaste
1070254721Semaste	audiocs_get_ports(state);
1071254721Semaste
1072254721Semaste	/* Allocate engines, must be done before register mapping called  */
1073254721Semaste	if ((audiocs_alloc_engine(state, CS4231_PLAY) != DDI_SUCCESS) ||
1074254721Semaste	    (audiocs_alloc_engine(state, CS4231_REC) != DDI_SUCCESS)) {
1075254721Semaste		return (DDI_FAILURE);
1076254721Semaste	}
1077254721Semaste
1078254721Semaste	/* Map in the registers */
1079254721Semaste	if (CS4231_DMA_MAP_REGS(state) == DDI_FAILURE) {
1080254721Semaste		return (DDI_FAILURE);
1081254721Semaste	}
1082254721Semaste
1083254721Semaste
1084254721Semaste	/* Allocate and add controls, must be done *after* registers mapped */
1085254721Semaste	if (audiocs_add_controls(state) != DDI_SUCCESS) {
1086254721Semaste		return (DDI_FAILURE);
1087254721Semaste	}
1088254721Semaste
1089254721Semaste	state->cs_suspended = B_FALSE;
1090254721Semaste	state->cs_powered = B_FALSE;
1091254721Semaste
1092254721Semaste	return (DDI_SUCCESS);
1093254721Semaste}
1094254721Semaste
1095254721Semaste/*
1096254721Semaste * audiocs_get_ports()
1097254721Semaste *
1098254721Semaste * Description:
1099254721Semaste *	Get which audiocs h/w version we have and use this to
1100254721Semaste *	determine the input and output ports as well whether or not
1101254721Semaste *	the hardware has internal loopbacks or not. We also have three
1102254721Semaste *	different ways for the properties to be specified, which we
1103254721Semaste *	also need to worry about.
1104254721Semaste *
1105254721Semaste * Vers	Platform(s)	DMA eng.	audio-module**	loopback
1106254721Semaste * a    SS-4+/SS-5+	apcdma		no		no
1107254721Semaste * b	Ultra-1&2	apcdma		no		yes
1108254721Semaste * c	positron	apcdma		no		yes
1109254721Semaste * d	PPC - retired
1110254721Semaste * e	x86 - retired
1111254721Semaste * f	tazmo		eb2dma		Perigee		no
1112254721Semaste * g	tazmo		eb2dma		Quark		yes
1113254721Semaste * h	darwin+		eb2dma		no		N/A
1114254721Semaste *
1115254721Semaste * Vers	model~		aux1*		aux2*
1116254721Semaste * a	N/A		N/A		N/A
1117254721Semaste * b	N/A		N/A		N/A
1118254721Semaste * c	N/A		N/A		N/A
1119254721Semaste * d	retired
1120254721Semaste * e	retired
1121254721Semaste * f	SUNW,CS4231f	N/A		N/A
1122254721Semaste * g	SUNW,CS4231g	N/A		N/A
1123254721Semaste * h	SUNW,CS4231h	cdrom		none
1124254721Semaste *
1125254721Semaste * *   = Replaces internal-loopback for latest property type, can be
1126254721Semaste *	 set to "cdrom", "loopback", or "none".
1127254721Semaste *
1128254721Semaste * **  = For plugin audio modules only. Starting with darwin, this
1129254721Semaste *	 property is replaces by the model property.
1130254721Semaste *
1131254721Semaste * ~   = Replaces audio-module.
1132254721Semaste *
1133254721Semaste * +   = Has the capability of having a cable run from the internal
1134254721Semaste *	 CD-ROM to the audio device.
1135254721Semaste *
1136254721Semaste * N/A = Not applicable, the property wasn't created for early
1137254721Semaste *	 platforms, or the property has been retired.
1138254721Semaste *
1139254721Semaste * NOTE: Older tazmo and quark machines don't have the model property.
1140254721Semaste *
1141254721Semaste * Arguments:
1142254721Semaste *	CS_state_t	*state		The device's state structure
1143254721Semaste */
1144static void
1145audiocs_get_ports(CS_state_t *state)
1146{
1147	dev_info_t	*dip = state->cs_dip;
1148	audio_dev_t	*adev = state->cs_adev;
1149	char		*prop_str;
1150
1151	/* First we set the common ports, etc. */
1152	state->cs_omask = state->cs_omod =
1153	    (1U << OUTPUT_SPEAKER) |
1154	    (1U << OUTPUT_HEADPHONES) |
1155	    (1U << OUTPUT_LINEOUT);
1156	state->cs_imask =
1157	    (1U << INPUT_MIC) |
1158	    (1U << INPUT_LINEIN) |
1159	    (1U << INPUT_STEREOMIX);
1160
1161	/* now we try the new "model" property */
1162	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1163	    "model", &prop_str) == DDI_PROP_SUCCESS) {
1164		if (strcmp(prop_str, "SUNW,CS4231h") == 0) {
1165			/* darwin */
1166			audio_dev_set_version(adev, CS_DEV_VERSION_H);
1167			state->cs_imask |= (1U << INPUT_CD);
1168			state->cs_omod = (1U << OUTPUT_SPEAKER);
1169		} else if (strcmp(prop_str, "SUNW,CS4231g") == 0) {
1170			/* quark audio module */
1171			audio_dev_set_version(adev, CS_DEV_VERSION_G);
1172			/*
1173			 * NB: This could do SUNVTS LOOPBACK, but we
1174			 * don't support it for now... owing to no
1175			 * support in framework.
1176			 */
1177		} else if (strcmp(prop_str, "SUNW,CS4231f") == 0) {
1178			/* tazmo */
1179			audio_dev_set_version(adev, CS_DEV_VERSION_F);
1180		} else {
1181			audio_dev_set_version(adev, prop_str);
1182			audio_dev_warn(adev,
1183			    "unknown audio model: %s, some parts of "
1184			    "audio may not work correctly", prop_str);
1185		}
1186		ddi_prop_free(prop_str);	/* done with the property */
1187	} else {	/* now try the older "audio-module" property */
1188		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
1189		    DDI_PROP_DONTPASS, "audio-module", &prop_str) ==
1190		    DDI_PROP_SUCCESS) {
1191			switch (*prop_str) {
1192			case 'Q':	/* quark audio module */
1193				audio_dev_set_version(adev, CS_DEV_VERSION_G);
1194				/* See quark comment above about SunVTS */
1195				break;
1196			case 'P':	/* tazmo */
1197				audio_dev_set_version(adev, CS_DEV_VERSION_F);
1198				break;
1199			default:
1200				audio_dev_set_version(adev, prop_str);
1201				audio_dev_warn(adev,
1202				    "unknown audio module: %s, some "
1203				    "parts of audio may not work correctly",
1204				    prop_str);
1205				break;
1206			}
1207			ddi_prop_free(prop_str);	/* done with the prop */
1208		} else {	/* now try heuristics, ;-( */
1209			if (ddi_prop_get_int(DDI_DEV_T_ANY, dip,
1210			    DDI_PROP_DONTPASS, "internal-loopback", B_FALSE)) {
1211				if (state->cs_dma_engine == EB2_DMA) {
1212					audio_dev_set_version(adev,
1213					    CS_DEV_VERSION_C);
1214				} else {
1215					audio_dev_set_version(adev,
1216					    CS_DEV_VERSION_B);
1217				}
1218				/*
1219				 * Again, we don't support SunVTS for these
1220				 * boards, although we potentially could.
1221				 */
1222			} else {
1223				audio_dev_set_version(adev, CS_DEV_VERSION_A);
1224				state->cs_imask |= (1U << INPUT_CD);
1225			}
1226		}
1227	}
1228}
1229
1230/*
1231 * audiocs_power_up()
1232 *
1233 * Description:
1234 *	Power up the Codec and restore the codec's registers.
1235 *
1236 *	NOTE: We don't worry about locking since the only routines
1237 *		that may call us are attach() and power() Both of
1238 *		which should be the only threads in the driver.
1239 *
1240 * Arguments:
1241 *	CS_state_t	*state		The device's state structure
1242 */
1243static void
1244audiocs_power_up(CS_state_t *state)
1245{
1246	ddi_acc_handle_t	handle = CODEC_HANDLE;
1247	int			i;
1248
1249	/* turn on the Codec */
1250	CS4231_DMA_POWER(state, CS4231_PWR_ON);
1251
1252	/* reset the DMA engine(s) */
1253	CS4231_DMA_RESET(state);
1254
1255	(void) audiocs_poll_ready(state);
1256
1257	/*
1258	 * Reload the Codec's registers, the DMA engines will be
1259	 * taken care of when play and record start up again. But
1260	 * first enable registers 16 -> 31.
1261	 */
1262	SELIDX(state, MID_REG);
1263	PUTIDX(state, state->cs_save[MID_REG], MID_VALID_MASK);
1264
1265	for (i = 0; i < CS4231_REGS; i++) {
1266		/* restore Codec registers */
1267		SELIDX(state, (i | IAR_MCE));
1268		ddi_put8(handle, &CS4231_IDR, state->cs_save[i]);
1269		(void) audiocs_poll_ready(state);
1270	}
1271	/* clear MCE bit */
1272	SELIDX(state, 0);
1273}
1274
1275/*
1276 * audiocs_power_down()
1277 *
1278 * Description:
1279 *	Power down the Codec and save the codec's registers.
1280 *
1281 *	NOTE: See the note in cs4231_power_up() about locking.
1282 *
1283 * Arguments:
1284 *	CS_state_t	*state		The device's state structure
1285 */
1286static void
1287audiocs_power_down(CS_state_t *state)
1288{
1289	ddi_acc_handle_t	handle;
1290	int			i;
1291
1292	handle = state->cs_handles.cs_codec_hndl;
1293
1294	/*
1295	 * We are powering down, so we don't need to do a thing with
1296	 * the DMA engines. However, we do need to save the Codec
1297	 * registers.
1298	 */
1299
1300	for (i = 0; i < CS4231_REGS; i++) {
1301		/* save Codec regs */
1302		SELIDX(state, i);
1303		state->cs_save[i] = ddi_get8(handle, &CS4231_IDR);
1304	}
1305
1306	/* turn off the Codec */
1307	CS4231_DMA_POWER(state, CS4231_PWR_OFF);
1308
1309}	/* cs4231_power_down() */
1310
1311/*
1312 * audiocs_configure_input()
1313 *
1314 * Description:
1315 *	Configure input properties of the mixer (e.g. igain, ports).
1316 *
1317 * Arguments:
1318 *	CS_state_t	*state		The device's state structure
1319 */
1320static void
1321audiocs_configure_input(CS_state_t *state)
1322{
1323	uint8_t		l, r;
1324	uint64_t	inputs;
1325	uint64_t	micboost;
1326
1327	ASSERT(mutex_owned(&state->cs_lock));
1328
1329	inputs = state->cs_inputs->cc_val;
1330	micboost = state->cs_micboost->cc_val;
1331	r = (state->cs_igain->cc_val & 0xff);
1332	l = ((state->cs_igain->cc_val & 0xff00) >> 8);
1333
1334	/* rescale these for our atten array */
1335	l = (((uint32_t)l * 255) / 100) & 0xff;
1336	r = (((uint32_t)r * 255) / 100) & 0xff;
1337
1338	/* we downshift by 4 bits -- igain only has 16 possible values */
1339	/* NB: that we do not scale here!  The SADA driver didn't do so. */
1340	l = l >> 4;
1341	r = r >> 4;
1342
1343	if (inputs & (1U << INPUT_MIC)) {
1344		l |= LADCI_LMIC;
1345		r |= RADCI_RMIC;
1346	}
1347	if (inputs & (1U << INPUT_LINEIN)) {
1348		l |= LADCI_LLINE;
1349		r |= RADCI_RLINE;
1350	}
1351	if (inputs & (1U << INPUT_CD)) {
1352		/* note that SunVTS also uses this */
1353		l |= LADCI_LAUX1;
1354		r |= RADCI_RAUX1;
1355	}
1356	if (inputs & (1U << INPUT_STEREOMIX)) {
1357		l |= LADCI_LLOOP;
1358		r |= RADCI_RLOOP;
1359	}
1360	if (micboost) {
1361		l |= LADCI_LMGE;
1362		r |= RADCI_RMGE;
1363	}
1364
1365	SELIDX(state, LADCI_REG);
1366	PUTIDX(state, l, LADCI_VALID_MASK);
1367
1368	SELIDX(state, RADCI_REG);
1369	PUTIDX(state, r, RADCI_VALID_MASK);
1370}
1371
1372/*
1373 * audiocs_configure_output()
1374 *
1375 * Description:
1376 *	Configure output properties of the mixer (e.g. ogain, mgain).
1377 *
1378 * Arguments:
1379 *	CS_state_t	*state		The device's state structure
1380 */
1381static void
1382audiocs_configure_output(CS_state_t *state)
1383{
1384	uint64_t		outputs;
1385	uint8_t			l, r;
1386	uint8_t			rmute, lmute;
1387	uint8_t			mgain;
1388	ddi_acc_handle_t	handle = CODEC_HANDLE;
1389
1390	rmute = lmute = 0;
1391
1392	ASSERT(mutex_owned(&state->cs_lock));
1393
1394	outputs = state->cs_outputs->cc_val;
1395
1396	/* port selection */
1397	SELIDX(state, MIOC_REG);
1398	if (outputs & (1U << OUTPUT_SPEAKER)) {
1399		ANDIDX(state, ~MIOC_MONO_SPKR_MUTE, MIOC_VALID_MASK);
1400	} else {
1401		ORIDX(state, MIOC_MONO_SPKR_MUTE, MIOC_VALID_MASK);
1402	}
1403	SELIDX(state, PC_REG);
1404	if (outputs & (1U << OUTPUT_HEADPHONES)) {
1405		ANDIDX(state, ~PC_HEADPHONE_MUTE, PC_VALID_MASK);
1406	} else {
1407		ORIDX(state, PC_HEADPHONE_MUTE, PC_VALID_MASK);
1408	}
1409	SELIDX(state, PC_REG);
1410	if (outputs & (1U << OUTPUT_LINEOUT)) {
1411		ANDIDX(state, ~PC_LINE_OUT_MUTE, PC_VALID_MASK);
1412	} else {
1413		ORIDX(state, PC_LINE_OUT_MUTE, PC_VALID_MASK);
1414	}
1415
1416	/* monitor gain */
1417	mgain = cs4231_atten[((state->cs_mgain->cc_val * 255) / 100) & 0xff];
1418	SELIDX(state, LC_REG);
1419	if (mgain == 0) {
1420		/* disable loopbacks when gain == 0 */
1421		PUTIDX(state, LC_OFF, LC_VALID_MASK);
1422	} else {
1423		/* we use cs4231_atten[] to linearize attenuation */
1424		PUTIDX(state, (mgain << 2) | LC_LBE, LC_VALID_MASK);
1425	}
1426
1427	/* output gain */
1428	l = ((state->cs_ogain->cc_val >> 8) & 0xff);
1429	r = (state->cs_ogain->cc_val & 0xff);
1430	if (l == 0) {
1431		lmute = LDACO_LDM;
1432	}
1433	if (r == 0) {
1434		rmute = RDACO_RDM;
1435	}
1436
1437	/* rescale these for our atten array */
1438	l = cs4231_atten[(((uint32_t)l * 255) / 100) & 0xff] | lmute;
1439	r = cs4231_atten[(((uint32_t)r * 255) / 100) & 0xff] | rmute;
1440
1441	SELIDX(state, LDACO_REG);
1442	PUTIDX(state, l, LDAC0_VALID_MASK);
1443	SELIDX(state, RDACO_REG);
1444	PUTIDX(state, r, RDAC0_VALID_MASK);
1445}
1446
1447/*
1448 * audiocs_get_value()
1449 *
1450 * Description:
1451 *	Get a control value
1452 *
1453 * Arguments:
1454 *	void		*arg		The device's state structure
1455 *	uint64_t	*valp		Pointer to store value.
1456 *
1457 * Returns:
1458 *	0		The Codec parameter has been retrieved.
1459 */
1460static int
1461audiocs_get_value(void *arg, uint64_t *valp)
1462{
1463	CS_ctrl_t		*cc = arg;
1464	CS_state_t		*state = cc->cc_state;
1465
1466	mutex_enter(&state->cs_lock);
1467	*valp = cc->cc_val;
1468	mutex_exit(&state->cs_lock);
1469	return (0);
1470}
1471
1472
1473/*
1474 * audiocs_set_ogain()
1475 *
1476 * Description:
1477 *	Set the play gain.
1478 *
1479 * Arguments:
1480 *	void		*arg		The device's state structure
1481 *	uint64_t	val		The gain to set (both left and right)
1482 *
1483 * Returns:
1484 *	0		The Codec parameter has been set
1485 */
1486static int
1487audiocs_set_ogain(void *arg, uint64_t val)
1488{
1489	CS_ctrl_t		*cc = arg;
1490	CS_state_t		*state = cc->cc_state;
1491
1492	if ((val & ~0xffff) ||
1493	    ((val & 0xff) > 100) ||
1494	    (((val & 0xff00) >> 8) > 100))
1495		return (EINVAL);
1496
1497	mutex_enter(&state->cs_lock);
1498	cc->cc_val = val;
1499	audiocs_configure_output(state);
1500	mutex_exit(&state->cs_lock);
1501	return (0);
1502}
1503
1504/*
1505 * audiocs_set_micboost()
1506 *
1507 * Description:
1508 *	Set the 20 dB microphone boost.
1509 *
1510 * Arguments:
1511 *	void		*arg		The device's state structure
1512 *	uint64_t	val		The 1 to enable, 0 to disable.
1513 *
1514 * Returns:
1515 *	0		The Codec parameter has been set
1516 */
1517static int
1518audiocs_set_micboost(void *arg, uint64_t val)
1519{
1520	CS_ctrl_t	*cc = arg;
1521	CS_state_t	*state = cc->cc_state;
1522
1523	mutex_enter(&state->cs_lock);
1524	cc->cc_val = val ? B_TRUE : B_FALSE;
1525	audiocs_configure_input(state);
1526	mutex_exit(&state->cs_lock);
1527	return (0);
1528}
1529
1530/*
1531 * audiocs_set_igain()
1532 *
1533 * Description:
1534 *	Set the record gain.
1535 *
1536 * Arguments:
1537 *	void		*arg		The device's state structure
1538 *	uint64_t	val		The gain to set (both left and right)
1539 *
1540 * Returns:
1541 *	0		The Codec parameter has been set
1542 */
1543static int
1544audiocs_set_igain(void *arg, uint64_t val)
1545{
1546	CS_ctrl_t	*cc = arg;
1547	CS_state_t	*state = cc->cc_state;
1548
1549	if ((val & ~0xffff) ||
1550	    ((val & 0xff) > 100) ||
1551	    (((val & 0xff00) >> 8) > 100))
1552		return (EINVAL);
1553
1554	mutex_enter(&state->cs_lock);
1555	cc->cc_val = val;
1556	audiocs_configure_input(state);
1557	mutex_exit(&state->cs_lock);
1558
1559	return (0);
1560}
1561
1562/*
1563 * audiocs_set_inputs()
1564 *
1565 * Description:
1566 *	Set the input ports.
1567 *
1568 * Arguments:
1569 *	void		*arg		The device's state structure
1570 *	uint64_t	val		The mask of output ports.
1571 *
1572 * Returns:
1573 *	0		The Codec parameter has been set
1574 */
1575static int
1576audiocs_set_inputs(void *arg, uint64_t val)
1577{
1578	CS_ctrl_t	*cc = arg;
1579	CS_state_t	*state = cc->cc_state;
1580
1581	if (val & ~(state->cs_imask))
1582		return (EINVAL);
1583
1584	mutex_enter(&state->cs_lock);
1585	cc->cc_val = val;
1586	audiocs_configure_input(state);
1587	mutex_exit(&state->cs_lock);
1588
1589	return (0);
1590}
1591
1592/*
1593 * audiocs_set_outputs()
1594 *
1595 * Description:
1596 *	Set the output ports.
1597 *
1598 * Arguments:
1599 *	void		*arg		The device's state structure
1600 *	uint64_t	val		The mask of input ports.
1601 *
1602 * Returns:
1603 *	0		The Codec parameter has been set
1604 */
1605static int
1606audiocs_set_outputs(void *arg, uint64_t val)
1607{
1608	CS_ctrl_t	*cc = arg;
1609	CS_state_t	*state = cc->cc_state;
1610
1611	if ((val & ~(state->cs_omod)) !=
1612	    (state->cs_omask & ~state->cs_omod))
1613		return (EINVAL);
1614
1615	mutex_enter(&state->cs_lock);
1616	cc->cc_val = val;
1617	audiocs_configure_output(state);
1618	mutex_exit(&state->cs_lock);
1619
1620	return (0);
1621}
1622
1623/*
1624 * audiocs_set_mgain()
1625 *
1626 * Description:
1627 *	Set the monitor gain.
1628 *
1629 * Arguments:
1630 *	void		*arg		The device's state structure
1631 *	uint64_t	val		The gain to set (monoaural).)
1632 *
1633 * Returns:
1634 *	0		The Codec parameter has been set
1635 */
1636static int
1637audiocs_set_mgain(void *arg, uint64_t gain)
1638{
1639	CS_ctrl_t	*cc = arg;
1640	CS_state_t	*state = cc->cc_state;
1641
1642	if (gain > 100)
1643		return (EINVAL);
1644
1645	mutex_enter(&state->cs_lock);
1646	cc->cc_val = gain;
1647	audiocs_configure_output(state);
1648	mutex_exit(&state->cs_lock);
1649
1650	return (0);
1651}
1652
1653/*
1654 * audiocs_open()
1655 *
1656 * Description:
1657 *	Opens a DMA engine for use.
1658 *
1659 * Arguments:
1660 *	void		*arg		The DMA engine to set up
1661 *	int		flag		Open flags
1662 *	unsigned	*nframesp	Receives number of frames
1663 *	caddr_t		*bufp		Receives kernel data buffer
1664 *
1665 * Returns:
1666 *	0	on success
1667 *	errno	on failure
1668 */
1669static int
1670audiocs_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
1671{
1672	CS_engine_t	*eng = arg;
1673	CS_state_t	*state = eng->ce_state;
1674	dev_info_t	*dip = state->cs_dip;
1675
1676	_NOTE(ARGUNUSED(flag));
1677
1678	(void) pm_busy_component(dip, CS4231_COMPONENT);
1679	if (pm_raise_power(dip, CS4231_COMPONENT, CS4231_PWR_ON) ==
1680	    DDI_FAILURE) {
1681
1682		/* match the busy call above */
1683		(void) pm_idle_component(dip, CS4231_COMPONENT);
1684
1685		audio_dev_warn(state->cs_adev, "power up failed");
1686	}
1687
1688	eng->ce_count = 0;
1689	*nframesp = CS4231_NFRAMES;
1690	*bufp = eng->ce_kaddr;
1691
1692	return (0);
1693}
1694
1695/*
1696 * audiocs_close()
1697 *
1698 * Description:
1699 *	Closes an audio DMA engine that was previously opened.  Since
1700 *	nobody is using it, we take this opportunity to possibly power
1701 *	down the entire device.
1702 *
1703 * Arguments:
1704 *	void	*arg		The DMA engine to shut down
1705 */
1706static void
1707audiocs_close(void *arg)
1708{
1709	CS_engine_t	*eng = arg;
1710	CS_state_t	*state = eng->ce_state;
1711
1712	(void) pm_idle_component(state->cs_dip, CS4231_COMPONENT);
1713}
1714
1715/*
1716 * audiocs_stop()
1717 *
1718 * Description:
1719 *	This is called by the framework to stop an engine that is
1720 *	transferring data.
1721 *
1722 * Arguments:
1723 *	void	*arg		The DMA engine to stop
1724 */
1725static void
1726audiocs_stop(void *arg)
1727{
1728	CS_engine_t		*eng = arg;
1729	CS_state_t		*state = eng->ce_state;
1730	ddi_acc_handle_t	handle = CODEC_HANDLE;
1731
1732	mutex_enter(&state->cs_lock);
1733	/*
1734	 * Stop the DMA engine.
1735	 */
1736	CS4231_DMA_STOP(state, eng);
1737
1738	/*
1739	 * Stop the codec.
1740	 */
1741	SELIDX(state, INTC_REG);
1742	ANDIDX(state, ~(eng->ce_codec_en), INTC_VALID_MASK);
1743	mutex_exit(&state->cs_lock);
1744}
1745
1746/*
1747 * audiocs_start()
1748 *
1749 * Description:
1750 *	This is called by the framework to start an engine transferring data.
1751 *
1752 * Arguments:
1753 *	void	*arg		The DMA engine to start
1754 *
1755 * Returns:
1756 *	0 	on success, an errno otherwise
1757 */
1758static int
1759audiocs_start(void *arg)
1760{
1761	CS_engine_t		*eng = arg;
1762	CS_state_t		*state = eng->ce_state;
1763	ddi_acc_handle_t	handle = CODEC_HANDLE;
1764	uint8_t			mask;
1765	uint8_t			value;
1766	uint8_t			reg;
1767	int			rv;
1768
1769	mutex_enter(&state->cs_lock);
1770
1771	if (eng->ce_num == CS4231_PLAY) {
1772		/* sample rate only set on play side */
1773		value = FS_48000 | PDF_STEREO | PDF_LINEAR16NE;
1774		reg = FSDF_REG;
1775		mask = FSDF_VALID_MASK;
1776	} else {
1777		value = CDF_STEREO | CDF_LINEAR16NE;
1778		reg = CDF_REG;
1779		mask = CDF_VALID_MASK;
1780	}
1781	eng->ce_curoff = 0;
1782	eng->ce_curidx = 0;
1783
1784	SELIDX(state, reg | IAR_MCE);
1785	PUTIDX(state, value, mask);
1786
1787	if (audiocs_poll_ready(state) != DDI_SUCCESS) {
1788		rv = EIO;
1789	} else if (CS4231_DMA_START(state, eng) != DDI_SUCCESS) {
1790		rv = EIO;
1791	} else {
1792		/*
1793		 * Start the codec.
1794		 */
1795		SELIDX(state, INTC_REG);
1796		ORIDX(state, eng->ce_codec_en, INTC_VALID_MASK);
1797		rv = 0;
1798	}
1799
1800	mutex_exit(&state->cs_lock);
1801	return (rv);
1802}
1803
1804/*
1805 * audiocs_format()
1806 *
1807 * Description:
1808 *	Called by the framework to query the format of the device.
1809 *
1810 * Arguments:
1811 *	void	*arg		The DMA engine to query
1812 *
1813 * Returns:
1814 *	AUDIO_FORMAT_S16_NE
1815 */
1816static int
1817audiocs_format(void *arg)
1818{
1819	_NOTE(ARGUNUSED(arg));
1820
1821	return (AUDIO_FORMAT_S16_NE);
1822}
1823
1824/*
1825 * audiocs_channels()
1826 *
1827 * Description:
1828 *	Called by the framework to query the channels of the device.
1829 *
1830 * Arguments:
1831 *	void	*arg		The DMA engine to query
1832 *
1833 * Returns:
1834 *	2 (stereo)
1835 */
1836static int
1837audiocs_channels(void *arg)
1838{
1839	_NOTE(ARGUNUSED(arg));
1840
1841	return (2);
1842}
1843
1844/*
1845 * audiocs_rates()
1846 *
1847 * Description:
1848 *	Called by the framework to query the sample rate of the device.
1849 *
1850 * Arguments:
1851 *	void	*arg		The DMA engine to query
1852 *
1853 * Returns:
1854 *	48000
1855 */
1856static int
1857audiocs_rate(void *arg)
1858{
1859	_NOTE(ARGUNUSED(arg));
1860
1861	return (48000);
1862}
1863
1864/*
1865 * audiocs_count()
1866 *
1867 * Description:
1868 *	This is called by the framework to get the engine's frame counter
1869 *
1870 * Arguments:
1871 *	void	*arg		The DMA engine to query
1872 *
1873 * Returns:
1874 *	frame count for current engine
1875 */
1876static uint64_t
1877audiocs_count(void *arg)
1878{
1879	CS_engine_t		*eng = arg;
1880	CS_state_t		*state = eng->ce_state;
1881	uint64_t		val;
1882	uint32_t		off;
1883
1884	mutex_enter(&state->cs_lock);
1885
1886	off = CS4231_DMA_ADDR(state, eng);
1887	ASSERT(off >= eng->ce_paddr);
1888	off -= eng->ce_paddr;
1889
1890	/*
1891	 * Every now and then, we get a value that is just a wee bit
1892	 * too large.  This seems to be a small value related to
1893	 * prefetch.  Rather than believe it, we just assume the last
1894	 * offset in the buffer.  This should allow us to handle
1895	 * wraps, but without inserting bogus sample counts.
1896	 */
1897	if (off >= CS4231_BUFSZ) {
1898		off = CS4231_BUFSZ - 4;
1899	}
1900
1901	off /= 4;
1902
1903	val = (off >= eng->ce_curoff) ?
1904	    off - eng->ce_curoff :
1905	    off + CS4231_NFRAMES - eng->ce_curoff;
1906
1907	eng->ce_count += val;
1908	eng->ce_curoff = off;
1909	val = eng->ce_count;
1910
1911	/* while here, possibly reload the next address */
1912	CS4231_DMA_RELOAD(state, eng);
1913	mutex_exit(&state->cs_lock);
1914
1915	return (val);
1916}
1917
1918/*
1919 * audiocs_sync()
1920 *
1921 * Description:
1922 *	This is called by the framework to synchronize DMA caches.
1923 *
1924 * Arguments:
1925 *	void	*arg		The DMA engine to sync
1926 */
1927static void
1928audiocs_sync(void *arg, unsigned nframes)
1929{
1930	CS_engine_t *eng = arg;
1931	_NOTE(ARGUNUSED(nframes));
1932
1933	(void) ddi_dma_sync(eng->ce_dmah, 0, 0, eng->ce_syncdir);
1934}
1935
1936/*
1937 * audiocs_alloc_engine()
1938 *
1939 * Description:
1940 *	Allocates the DMA handles and the memory for the DMA engine.
1941 *
1942 * Arguments:
1943 *	CS_state_t	*dip	Pointer to the device's soft state
1944 *	int		num	Engine number, CS4231_PLAY or CS4231_REC.
1945 *
1946 * Returns:
1947 *	DDI_SUCCESS		Engine initialized.
1948 *	DDI_FAILURE		Engine not initialized.
1949 */
1950int
1951audiocs_alloc_engine(CS_state_t *state, int num)
1952{
1953	unsigned		caps;
1954	int			dir;
1955	int			rc;
1956	audio_dev_t		*adev;
1957	dev_info_t		*dip;
1958	CS_engine_t		*eng;
1959	uint_t			ccnt;
1960	ddi_dma_cookie_t	dmac;
1961	size_t			bufsz;
1962
1963	static ddi_device_acc_attr_t buf_attr = {
1964		DDI_DEVICE_ATTR_V0,
1965		DDI_NEVERSWAP_ACC,
1966		DDI_STRICTORDER_ACC
1967	};
1968
1969	adev = state->cs_adev;
1970	dip = state->cs_dip;
1971
1972	eng = kmem_zalloc(sizeof (*eng), KM_SLEEP);
1973	eng->ce_state = state;
1974	eng->ce_started = B_FALSE;
1975	eng->ce_num = num;
1976
1977	switch (num) {
1978	case CS4231_REC:
1979		dir = DDI_DMA_READ;
1980		caps = ENGINE_INPUT_CAP;
1981		eng->ce_syncdir = DDI_DMA_SYNC_FORKERNEL;
1982		eng->ce_codec_en = INTC_CEN;
1983		break;
1984	case CS4231_PLAY:
1985		dir = DDI_DMA_WRITE;
1986		caps = ENGINE_OUTPUT_CAP;
1987		eng->ce_syncdir = DDI_DMA_SYNC_FORDEV;
1988		eng->ce_codec_en = INTC_PEN;
1989		break;
1990	default:
1991		kmem_free(eng, sizeof (*eng));
1992		audio_dev_warn(adev, "bad engine number (%d)!", num);
1993		return (DDI_FAILURE);
1994	}
1995	state->cs_engines[num] = eng;
1996
1997	/* allocate dma handle */
1998	rc = ddi_dma_alloc_handle(dip, CS4231_DMA_ATTR(state), DDI_DMA_SLEEP,
1999	    NULL, &eng->ce_dmah);
2000	if (rc != DDI_SUCCESS) {
2001		audio_dev_warn(adev, "ddi_dma_alloc_handle failed: %d", rc);
2002		return (DDI_FAILURE);
2003	}
2004	/* allocate DMA buffer */
2005	rc = ddi_dma_mem_alloc(eng->ce_dmah, CS4231_BUFSZ, &buf_attr,
2006	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &eng->ce_kaddr,
2007	    &bufsz, &eng->ce_acch);
2008	if (rc == DDI_FAILURE) {
2009		audio_dev_warn(adev, "dma_mem_alloc failed");
2010		return (DDI_FAILURE);
2011	}
2012
2013	/* bind DMA buffer */
2014	rc = ddi_dma_addr_bind_handle(eng->ce_dmah, NULL,
2015	    eng->ce_kaddr, CS4231_BUFSZ, dir | DDI_DMA_CONSISTENT,
2016	    DDI_DMA_SLEEP, NULL, &dmac, &ccnt);
2017	if ((rc != DDI_DMA_MAPPED) || (ccnt != 1)) {
2018		audio_dev_warn(adev,
2019		    "ddi_dma_addr_bind_handle failed: %d", rc);
2020		return (DDI_FAILURE);
2021	}
2022
2023	eng->ce_paddr = dmac.dmac_address;
2024
2025	eng->ce_engine = audio_engine_alloc(&audiocs_engine_ops, caps);
2026	if (eng->ce_engine == NULL) {
2027		audio_dev_warn(adev, "audio_engine_alloc failed");
2028		return (DDI_FAILURE);
2029	}
2030
2031	audio_engine_set_private(eng->ce_engine, eng);
2032	audio_dev_add_engine(adev, eng->ce_engine);
2033	return (DDI_SUCCESS);
2034}
2035
2036/*
2037 * audiocs_free_engine()
2038 *
2039 * Description:
2040 *	This routine fress the engine and all associated resources.
2041 *
2042 * Arguments:
2043 *	CS_engine_t	*eng	Engine to free.
2044 */
2045void
2046audiocs_free_engine(CS_engine_t *eng)
2047{
2048	CS_state_t	*state = eng->ce_state;
2049	audio_dev_t	*adev = state->cs_adev;
2050
2051	if (eng == NULL)
2052		return;
2053	if (eng->ce_engine) {
2054		audio_dev_remove_engine(adev, eng->ce_engine);
2055		audio_engine_free(eng->ce_engine);
2056	}
2057	if (eng->ce_paddr) {
2058		(void) ddi_dma_unbind_handle(eng->ce_dmah);
2059	}
2060	if (eng->ce_acch) {
2061		ddi_dma_mem_free(&eng->ce_acch);
2062	}
2063	if (eng->ce_dmah) {
2064		ddi_dma_free_handle(&eng->ce_dmah);
2065	}
2066	kmem_free(eng, sizeof (*eng));
2067}
2068
2069/*
2070 * audiocs_poll_ready()
2071 *
2072 * Description:
2073 *	This routine waits for the Codec to complete its initialization
2074 *	sequence and is done with its autocalibration.
2075 *
2076 *	Early versions of the Codec have a bug that can take as long as
2077 *	15 seconds to complete its initialization. For these cases we
2078 *	use a timeout mechanism so we don't keep the machine locked up.
2079 *
2080 * Arguments:
2081 *	CS_state_t	*state	The device's state structure
2082 *
2083 * Returns:
2084 *	DDI_SUCCESS		The Codec is ready to continue
2085 *	DDI_FAILURE		The Codec isn't ready to continue
2086 */
2087int
2088audiocs_poll_ready(CS_state_t *state)
2089{
2090	ddi_acc_handle_t	handle = CODEC_HANDLE;
2091	int			x = 0;
2092	uint8_t			iar;
2093	uint8_t			idr;
2094
2095	ASSERT(state->cs_regs != NULL);
2096	ASSERT(handle != NULL);
2097
2098	/* wait for the chip to initialize itself */
2099	iar = ddi_get8(handle, &CS4231_IAR);
2100
2101	while ((iar & IAR_INIT) && x++ < CS4231_TIMEOUT) {
2102		drv_usecwait(50);
2103		iar = ddi_get8(handle, &CS4231_IAR);
2104	}
2105
2106	if (x >= CS4231_TIMEOUT) {
2107		return (DDI_FAILURE);
2108	}
2109
2110	x = 0;
2111
2112	/*
2113	 * Now wait for the chip to complete its autocalibration.
2114	 * Set the test register.
2115	 */
2116	SELIDX(state, ESI_REG);
2117
2118	idr = ddi_get8(handle, &CS4231_IDR);
2119
2120	while ((idr & ESI_ACI) && x++ < CS4231_TIMEOUT) {
2121		drv_usecwait(50);
2122		idr = ddi_get8(handle, &CS4231_IDR);
2123	}
2124
2125	if (x >= CS4231_TIMEOUT) {
2126		return (DDI_FAILURE);
2127	}
2128
2129
2130	return (DDI_SUCCESS);
2131
2132}
2133
2134/*
2135 * audiocs_sel_index()
2136 *
2137 * Description:
2138 *	Select a cs4231 register. The cs4231 has a hardware bug where a
2139 *	register is not always selected the first time. We try and try
2140 *	again until the proper register is selected or we time out and
2141 *	print an error message.
2142 *
2143 * Arguments:
2144 *	audiohdl_t	ahandle		Handle to this device
2145 *	ddi_acc_handle_t handle		A handle to the device's registers
2146 *	uint8_t		addr		The register address to program
2147 *	int		reg		The register to select
2148 */
2149void
2150#ifdef	DEBUG
2151audiocs_sel_index(CS_state_t *state, uint8_t reg, int n)
2152#else
2153audiocs_sel_index(CS_state_t *state, uint8_t reg)
2154#endif
2155{
2156	int			x;
2157	uint8_t			T;
2158	ddi_acc_handle_t	handle = CODEC_HANDLE;
2159	uint8_t			*addr = &CS4231_IAR;
2160
2161	for (x = 0; x < CS4231_RETRIES; x++) {
2162		ddi_put8(handle, addr, reg);
2163		T = ddi_get8(handle, addr);
2164		if (T == reg) {
2165			break;
2166		}
2167		drv_usecwait(1000);
2168	}
2169
2170	if (x == CS4231_RETRIES) {
2171		audio_dev_warn(state->cs_adev,
2172#ifdef	DEBUG
2173		    "line %d: Couldn't select index (0x%02x 0x%02x)", n,
2174#else
2175		    "Couldn't select index (0x%02x 0x%02x)",
2176#endif
2177		    T, reg);
2178		audio_dev_warn(state->cs_adev,
2179		    "audio may not work correctly until it is stopped and "
2180		    "restarted");
2181	}
2182}
2183
2184/*
2185 * audiocs_put_index()
2186 *
2187 * Description:
2188 *	Program a cs4231 register. The cs4231 has a hardware bug where a
2189 *	register is not programmed properly the first time. We program a value,
2190 *	then immediately read back the value and reprogram if nescessary.
2191 *	We do this until the register is properly programmed or we time out and
2192 *	print an error message.
2193 *
2194 * Arguments:
2195 *	CS_state_t	state		Handle to this device
2196 *	uint8_t		mask		Mask to not set reserved register bits
2197 *	int		val		The value to program
2198 */
2199void
2200#ifdef DEBUG
2201audiocs_put_index(CS_state_t *state, uint8_t val, uint8_t mask, int n)
2202#else
2203audiocs_put_index(CS_state_t *state, uint8_t val, uint8_t mask)
2204#endif
2205{
2206	int			x;
2207	uint8_t			T;
2208	ddi_acc_handle_t	handle = CODEC_HANDLE;
2209	uint8_t			*addr = &CS4231_IDR;
2210
2211	val &= mask;
2212
2213	for (x = 0; x < CS4231_RETRIES; x++) {
2214		ddi_put8(handle, addr, val);
2215		T = ddi_get8(handle, addr);
2216		if (T == val) {
2217			break;
2218		}
2219		drv_usecwait(1000);
2220	}
2221
2222	if (x == CS4231_RETRIES) {
2223#ifdef DEBUG
2224		audio_dev_warn(state->cs_adev,
2225		    "line %d: Couldn't set value (0x%02x 0x%02x)", n, T, val);
2226#else
2227		audio_dev_warn(state->cs_adev,
2228		    "Couldn't set value (0x%02x 0x%02x)", T, val);
2229#endif
2230		audio_dev_warn(state->cs_adev,
2231		    "audio may not work correctly until it is stopped and "
2232		    "restarted");
2233	}
2234}
2235