xref: /freebsd/sys/dev/sound/pci/spicds.c (revision ce356b70)
112ab72d3SAlexander Leidinger /*
212ab72d3SAlexander Leidinger  * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
312ab72d3SAlexander Leidinger  * All rights reserved.
412ab72d3SAlexander Leidinger  *
512ab72d3SAlexander Leidinger  * Redistribution and use in source and binary forms, with or without
612ab72d3SAlexander Leidinger  * modification, are permitted provided that the following conditions
712ab72d3SAlexander Leidinger  * are met:
812ab72d3SAlexander Leidinger  * 1. Redistributions of source code must retain the above copyright
912ab72d3SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer.
1012ab72d3SAlexander Leidinger  * 2. Redistributions in binary form must reproduce the above copyright
1112ab72d3SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer in the
1212ab72d3SAlexander Leidinger  *    documentation and/or other materials provided with the distribution.
1312ab72d3SAlexander Leidinger  *
1412ab72d3SAlexander Leidinger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1512ab72d3SAlexander Leidinger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1612ab72d3SAlexander Leidinger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1712ab72d3SAlexander Leidinger  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1812ab72d3SAlexander Leidinger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1912ab72d3SAlexander Leidinger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2012ab72d3SAlexander Leidinger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2112ab72d3SAlexander Leidinger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
2212ab72d3SAlexander Leidinger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2312ab72d3SAlexander Leidinger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
2412ab72d3SAlexander Leidinger  * SUCH DAMAGE.
2512ab72d3SAlexander Leidinger  *
2612ab72d3SAlexander Leidinger  * $FreeBSD$
2712ab72d3SAlexander Leidinger  */
2812ab72d3SAlexander Leidinger 
2912ab72d3SAlexander Leidinger #include <dev/sound/pcm/sound.h>
3012ab72d3SAlexander Leidinger 
3112ab72d3SAlexander Leidinger #include <dev/sound/pci/ak452x.h>
3212ab72d3SAlexander Leidinger 
3312ab72d3SAlexander Leidinger MALLOC_DEFINE(M_AK452X, "ak452x", "ak452x codec");
3412ab72d3SAlexander Leidinger 
3512ab72d3SAlexander Leidinger #define AK452X_NAMELEN	16
3612ab72d3SAlexander Leidinger struct ak452x_info {
3712ab72d3SAlexander Leidinger 	device_t dev;
3812ab72d3SAlexander Leidinger 	ak452x_ctrl ctrl;
3912ab72d3SAlexander Leidinger 	void *devinfo;
4012ab72d3SAlexander Leidinger 	int num; /* number of this device */
4112ab72d3SAlexander Leidinger 	unsigned int type;   /* codec type */
4212ab72d3SAlexander Leidinger 	unsigned int cif;    /* Controll data Interface Format (0/1) */
4312ab72d3SAlexander Leidinger 	unsigned int format; /* data format and master clock frequency */
4412ab72d3SAlexander Leidinger 	unsigned int dvc;    /* De-emphasis and Volume Control */
4512ab72d3SAlexander Leidinger 	unsigned int left, right;
4612ab72d3SAlexander Leidinger 	char name[AK452X_NAMELEN];
4712ab72d3SAlexander Leidinger 	void *lock;
4812ab72d3SAlexander Leidinger };
4912ab72d3SAlexander Leidinger 
5012ab72d3SAlexander Leidinger static void
5112ab72d3SAlexander Leidinger ak452x_wrbit(struct ak452x_info *codec, int bit)
5212ab72d3SAlexander Leidinger {
5312ab72d3SAlexander Leidinger 	unsigned int cs, cdti;
5412ab72d3SAlexander Leidinger 	if (codec->cif)
5512ab72d3SAlexander Leidinger 		cs = 1;
5612ab72d3SAlexander Leidinger 	else
5712ab72d3SAlexander Leidinger 		cs = 0;
5812ab72d3SAlexander Leidinger 	if (bit)
5912ab72d3SAlexander Leidinger 		cdti = 1;
6012ab72d3SAlexander Leidinger 	else
6112ab72d3SAlexander Leidinger 		cdti = 0;
6212ab72d3SAlexander Leidinger 	codec->ctrl(codec->devinfo, cs, 0, cdti);
6312ab72d3SAlexander Leidinger 	DELAY(1);
6412ab72d3SAlexander Leidinger 	codec->ctrl(codec->devinfo, cs, 1, cdti);
6512ab72d3SAlexander Leidinger 	DELAY(1);
6612ab72d3SAlexander Leidinger 
6712ab72d3SAlexander Leidinger 	return;
6812ab72d3SAlexander Leidinger }
6912ab72d3SAlexander Leidinger 
7012ab72d3SAlexander Leidinger static void
7112ab72d3SAlexander Leidinger ak452x_wrcd(struct ak452x_info *codec, int reg, u_int8_t val)
7212ab72d3SAlexander Leidinger {
7312ab72d3SAlexander Leidinger 	int mask;
7412ab72d3SAlexander Leidinger 
7512ab72d3SAlexander Leidinger #if(0)
7612ab72d3SAlexander Leidinger 	device_printf(codec->dev, "ak452x_wrcd(codec, 0x%02x, 0x%02x)\n", reg, val);
7712ab72d3SAlexander Leidinger #endif
7812ab72d3SAlexander Leidinger 	/* start */
7912ab72d3SAlexander Leidinger 	if (codec->cif)
8012ab72d3SAlexander Leidinger 		codec->ctrl(codec->devinfo, 1, 1, 0);
8112ab72d3SAlexander Leidinger 	else
8212ab72d3SAlexander Leidinger 		codec->ctrl(codec->devinfo, 0, 1, 0);
8312ab72d3SAlexander Leidinger 	DELAY(1);
8412ab72d3SAlexander Leidinger 	/* chip address */
8512ab72d3SAlexander Leidinger 	ak452x_wrbit(codec, 1);
8612ab72d3SAlexander Leidinger 	ak452x_wrbit(codec, 0);
8712ab72d3SAlexander Leidinger 	/* write */
8812ab72d3SAlexander Leidinger 	ak452x_wrbit(codec, 1);
8912ab72d3SAlexander Leidinger 	/* register address */
9012ab72d3SAlexander Leidinger 	for (mask = 0x10; mask != 0; mask >>= 1)
9112ab72d3SAlexander Leidinger 		ak452x_wrbit(codec, reg & mask);
9212ab72d3SAlexander Leidinger 	/* data */
9312ab72d3SAlexander Leidinger 	for (mask = 0x80; mask != 0; mask >>= 1)
9412ab72d3SAlexander Leidinger 		ak452x_wrbit(codec, val & mask);
9512ab72d3SAlexander Leidinger 	/* stop */
9612ab72d3SAlexander Leidinger 	DELAY(1);
9712ab72d3SAlexander Leidinger 	if (codec->cif) {
9812ab72d3SAlexander Leidinger 		codec->ctrl(codec->devinfo, 0, 1, 0);
9912ab72d3SAlexander Leidinger 		DELAY(1);
10012ab72d3SAlexander Leidinger 		codec->ctrl(codec->devinfo, 1, 1, 0);
10112ab72d3SAlexander Leidinger 	}
10212ab72d3SAlexander Leidinger 	else {
10312ab72d3SAlexander Leidinger 		codec->ctrl(codec->devinfo, 1, 1, 0);
10412ab72d3SAlexander Leidinger 	}
10512ab72d3SAlexander Leidinger 
10612ab72d3SAlexander Leidinger 	return;
10712ab72d3SAlexander Leidinger }
10812ab72d3SAlexander Leidinger 
10912ab72d3SAlexander Leidinger struct ak452x_info *
11012ab72d3SAlexander Leidinger ak452x_create(device_t dev, void *devinfo, int num, ak452x_ctrl ctrl)
11112ab72d3SAlexander Leidinger {
11212ab72d3SAlexander Leidinger 	struct ak452x_info *codec;
11312ab72d3SAlexander Leidinger 
11412ab72d3SAlexander Leidinger #if(0)
11512ab72d3SAlexander Leidinger 	device_printf(dev, "ak452x_create(dev, devinfo, %d, ctrl)\n", num);
11612ab72d3SAlexander Leidinger #endif
11712ab72d3SAlexander Leidinger 	codec = (struct ak452x_info *)malloc(sizeof *codec, M_AK452X, M_NOWAIT);
11812ab72d3SAlexander Leidinger 	if (codec == NULL)
11912ab72d3SAlexander Leidinger 		return NULL;
12012ab72d3SAlexander Leidinger 
12112ab72d3SAlexander Leidinger 	snprintf(codec->name, AK452X_NAMELEN, "%s:ak452x%d", device_get_nameunit(dev), num);
122ce356b70SAlexander Leidinger 	codec->lock = snd_mtxcreate(codec->name, codec->name);
12312ab72d3SAlexander Leidinger 	codec->dev = dev;
12412ab72d3SAlexander Leidinger 	codec->ctrl = ctrl;
12512ab72d3SAlexander Leidinger 	codec->devinfo = devinfo;
12612ab72d3SAlexander Leidinger 	codec->num = num;
12712ab72d3SAlexander Leidinger 	codec->type = AK452X_TYPE_4524;
12812ab72d3SAlexander Leidinger 	codec->cif = 0;
12912ab72d3SAlexander Leidinger 	codec->format = AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X;
13012ab72d3SAlexander Leidinger 	codec->dvc = AK452X_DVC_DEMOFF | AK452X_DVC_ZTM1024 | AK452X_DVC_ZCE;
13112ab72d3SAlexander Leidinger 
13212ab72d3SAlexander Leidinger 	return codec;
13312ab72d3SAlexander Leidinger }
13412ab72d3SAlexander Leidinger 
13512ab72d3SAlexander Leidinger void
13612ab72d3SAlexander Leidinger ak452x_destroy(struct ak452x_info *codec)
13712ab72d3SAlexander Leidinger {
13812ab72d3SAlexander Leidinger 	snd_mtxfree(codec->lock);
13912ab72d3SAlexander Leidinger 	free(codec, M_AK452X);
14012ab72d3SAlexander Leidinger }
14112ab72d3SAlexander Leidinger 
14212ab72d3SAlexander Leidinger void
14312ab72d3SAlexander Leidinger ak452x_settype(struct ak452x_info *codec, unsigned int type)
14412ab72d3SAlexander Leidinger {
14512ab72d3SAlexander Leidinger 	snd_mtxlock(codec->lock);
14612ab72d3SAlexander Leidinger 	codec->type = type;
14712ab72d3SAlexander Leidinger 	snd_mtxunlock(codec->lock);
14812ab72d3SAlexander Leidinger }
14912ab72d3SAlexander Leidinger 
15012ab72d3SAlexander Leidinger void
15112ab72d3SAlexander Leidinger ak452x_setcif(struct ak452x_info *codec, unsigned int cif)
15212ab72d3SAlexander Leidinger {
15312ab72d3SAlexander Leidinger 	snd_mtxlock(codec->lock);
15412ab72d3SAlexander Leidinger 	codec->cif = cif;
15512ab72d3SAlexander Leidinger 	snd_mtxunlock(codec->lock);
15612ab72d3SAlexander Leidinger }
15712ab72d3SAlexander Leidinger 
15812ab72d3SAlexander Leidinger void
15912ab72d3SAlexander Leidinger ak452x_setformat(struct ak452x_info *codec, unsigned int format)
16012ab72d3SAlexander Leidinger {
16112ab72d3SAlexander Leidinger 	snd_mtxlock(codec->lock);
16212ab72d3SAlexander Leidinger 	codec->format = format;
16312ab72d3SAlexander Leidinger 	snd_mtxunlock(codec->lock);
16412ab72d3SAlexander Leidinger }
16512ab72d3SAlexander Leidinger 
16612ab72d3SAlexander Leidinger void
16712ab72d3SAlexander Leidinger ak452x_setdvc(struct ak452x_info *codec, unsigned int dvc)
16812ab72d3SAlexander Leidinger {
16912ab72d3SAlexander Leidinger 	snd_mtxlock(codec->lock);
170ce356b70SAlexander Leidinger 	codec->dvc = dvc;
17112ab72d3SAlexander Leidinger 	snd_mtxunlock(codec->lock);
17212ab72d3SAlexander Leidinger }
17312ab72d3SAlexander Leidinger 
17412ab72d3SAlexander Leidinger void
17512ab72d3SAlexander Leidinger ak452x_init(struct ak452x_info *codec)
17612ab72d3SAlexander Leidinger {
17712ab72d3SAlexander Leidinger #if(0)
17812ab72d3SAlexander Leidinger 	device_printf(codec->dev, "ak452x_init(codec)\n");
17912ab72d3SAlexander Leidinger #endif
18012ab72d3SAlexander Leidinger 	snd_mtxlock(codec->lock);
18112ab72d3SAlexander Leidinger 	/* power off */
18212ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_POWER, 0);
18312ab72d3SAlexander Leidinger 	/* set parameter */
18412ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_FORMAT, codec->format);
18512ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_DVC, codec->dvc);
18612ab72d3SAlexander Leidinger 	/* power on */
18712ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_POWER, AK452X_POWER_PWDA | AK452X_POWER_PWAD | AK452X_POWER_PWVR);
18812ab72d3SAlexander Leidinger 	/* free reset register */
18912ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD);
19012ab72d3SAlexander Leidinger 	snd_mtxunlock(codec->lock);
19112ab72d3SAlexander Leidinger }
19212ab72d3SAlexander Leidinger 
19312ab72d3SAlexander Leidinger void
19412ab72d3SAlexander Leidinger ak452x_reinit(struct ak452x_info *codec)
19512ab72d3SAlexander Leidinger {
19612ab72d3SAlexander Leidinger 	snd_mtxlock(codec->lock);
19712ab72d3SAlexander Leidinger 	/* reset */
19812ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_RESET, 0);
19912ab72d3SAlexander Leidinger 	/* set parameter */
20012ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_FORMAT, codec->format);
20112ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_DVC, codec->dvc);
20212ab72d3SAlexander Leidinger 	/* free reset register */
20312ab72d3SAlexander Leidinger 	ak452x_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD);
20412ab72d3SAlexander Leidinger 	snd_mtxunlock(codec->lock);
20512ab72d3SAlexander Leidinger }
20612ab72d3SAlexander Leidinger 
20712ab72d3SAlexander Leidinger void
20812ab72d3SAlexander Leidinger ak452x_set(struct ak452x_info *codec, int dir, unsigned int left, unsigned int right)
20912ab72d3SAlexander Leidinger {
21012ab72d3SAlexander Leidinger #if(0)
21112ab72d3SAlexander Leidinger 	device_printf(codec->dev, "ak452x_set(codec, %d, %d, %d)\n", dir, left, right);
21212ab72d3SAlexander Leidinger #endif
21312ab72d3SAlexander Leidinger 	snd_mtxlock(codec->lock);
21412ab72d3SAlexander Leidinger 	if (left >= 100)
21512ab72d3SAlexander Leidinger 		left  = 127;
21612ab72d3SAlexander Leidinger 	else
21712ab72d3SAlexander Leidinger 		left = left * 127 / 100;
21812ab72d3SAlexander Leidinger 	if (right >= 100)
21912ab72d3SAlexander Leidinger 		right  = 127;
22012ab72d3SAlexander Leidinger 	else
22112ab72d3SAlexander Leidinger 		right = right * 127 / 100;
22212ab72d3SAlexander Leidinger 	if (dir == PCMDIR_REC && codec->type == AK452X_TYPE_4524) {
22312ab72d3SAlexander Leidinger #if(0)
22412ab72d3SAlexander Leidinger 		device_printf(codec->dev, "ak452x_set(): AK4524(REC) %d/%d\n", left, right);
22512ab72d3SAlexander Leidinger #endif
22612ab72d3SAlexander Leidinger 		ak452x_wrcd(codec, AK4524_LIPGA, left);
22712ab72d3SAlexander Leidinger 		ak452x_wrcd(codec, AK4524_RIPGA, right);
22812ab72d3SAlexander Leidinger 	}
22912ab72d3SAlexander Leidinger 	if (dir == PCMDIR_PLAY && codec->type == AK452X_TYPE_4524) {
23012ab72d3SAlexander Leidinger #if(0)
23112ab72d3SAlexander Leidinger 		device_printf(codec->dev, "ak452x_set(): AK4524(PLAY) %d/%d\n", left, right);
23212ab72d3SAlexander Leidinger #endif
23312ab72d3SAlexander Leidinger 		ak452x_wrcd(codec, AK4524_LOATT, left);
23412ab72d3SAlexander Leidinger 		ak452x_wrcd(codec, AK4524_ROATT, right);
23512ab72d3SAlexander Leidinger 	}
23612ab72d3SAlexander Leidinger 	if (dir == PCMDIR_PLAY && codec->type == AK452X_TYPE_4528) {
23712ab72d3SAlexander Leidinger #if(0)
23812ab72d3SAlexander Leidinger 		device_printf(codec->dev, "ak452x_set(): AK4528(PLAY) %d/%d\n", left, right);
23912ab72d3SAlexander Leidinger #endif
24012ab72d3SAlexander Leidinger 		ak452x_wrcd(codec, AK4528_LOATT, left);
24112ab72d3SAlexander Leidinger 		ak452x_wrcd(codec, AK4528_ROATT, right);
24212ab72d3SAlexander Leidinger 	}
24312ab72d3SAlexander Leidinger 	snd_mtxunlock(codec->lock);
24412ab72d3SAlexander Leidinger }
24512ab72d3SAlexander Leidinger 
246ce356b70SAlexander Leidinger MODULE_DEPEND(snd_ak452x, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
24712ab72d3SAlexander Leidinger MODULE_VERSION(snd_ak452x, 1);
248