blob: 60c4e66c76e47092741a9006546edef2dec81b3a [file] [log] [blame]
Dave Chapman465596b2006-02-05 17:16:34 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Michael Sevakis15b73212007-10-02 07:48:50 +000010 * Driver for WM8721 audio codec
Dave Chapman465596b2006-02-05 17:16:34 +000011 *
12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in January 2006
14 *
15 * Original file: linux/arch/armnommu/mach-ipod/audio.c
16 *
17 * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
18 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000019 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version 2
22 * of the License, or (at your option) any later version.
Dave Chapman465596b2006-02-05 17:16:34 +000023 *
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
25 * KIND, either express or implied.
26 *
27 ****************************************************************************/
Christian Gmeiner98e4f6f2007-05-22 16:12:30 +000028#include "config.h"
Christian Gmeinerbcdf43d2007-05-20 23:10:15 +000029#include "logf.h"
Dave Chapman465596b2006-02-05 17:16:34 +000030#include "system.h"
Dave Chapman465596b2006-02-05 17:16:34 +000031#include "string.h"
Dave Chapman465596b2006-02-05 17:16:34 +000032#include "audio.h"
33
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +000034#include "wmcodec.h"
Marcoen Hirschberg85f06b82007-05-22 20:39:50 +000035#include "audiohw.h"
Daniel Ankersacbbe822006-12-09 19:18:18 +000036#include "i2s.h"
Dave Chapman465596b2006-02-05 17:16:34 +000037
Dave Chapman465596b2006-02-05 17:16:34 +000038#define IPOD_PCM_LEVEL 0x65 /* -6dB */
39
Jens Arnold72f10272007-01-14 12:38:40 +000040/* use zero crossing to reduce clicks during volume changes */
41#define VOLUME_ZC_WAIT (1<<7)
42
Christian Gmeinercdbf33a2007-05-22 15:56:05 +000043const struct sound_settings_info audiohw_settings[] = {
44 [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25},
45 /* HAVE_SW_TONE_CONTROLS */
46 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
47 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
Marcoen Hirschbergdf31f5f2007-12-10 11:14:28 +000048 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
Christian Gmeinercdbf33a2007-05-22 15:56:05 +000049 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
Thom Johansen8f721922007-10-09 21:29:20 +000050 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
Christian Gmeinercdbf33a2007-05-22 15:56:05 +000051};
52
Marcoen Hirschberg1b967f42006-12-06 13:34:15 +000053/* convert tenth of dB volume (-730..60) to master volume register value */
54int tenthdb2master(int db)
55{
56 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
57 /* 1111111 == +6dB (0x7f) */
58 /* 1111001 == 0dB (0x79) */
59 /* 0110000 == -73dB (0x30 */
60 /* 0101111 == mute (0x2f) */
61
62 if (db < VOLUME_MIN) {
63 return 0x2f;
64 } else {
65 return((db/10)+0x30+73);
66 }
67}
68
69/* convert tenth of dB volume (-780..0) to mixer volume register value */
70int tenthdb2mixer(int db)
71{
72 if (db < -660) /* 1.5 dB steps */
73 return (2640 - db) / 15;
74 else if (db < -600) /* 0.75 dB steps */
75 return (990 - db) * 2 / 15;
76 else if (db < -460) /* 0.5 dB steps */
77 return (460 - db) / 5;
78 else /* 0.25 dB steps */
79 return -db * 2 / 5;
80}
Dave Chapman2f767632006-02-26 15:59:46 +000081
Christian Gmeinerd1178d22007-06-13 06:33:40 +000082void audiohw_mute(bool mute)
Dave Chapman465596b2006-02-05 17:16:34 +000083{
84 if (mute)
85 {
86 /* Set DACMU = 1 to soft-mute the audio DACs. */
Michael Sevakisb6dab332007-10-02 08:30:30 +000087 wmcodec_write(DAPCTRL, 0x8);
Dave Chapman465596b2006-02-05 17:16:34 +000088 } else {
89 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
Michael Sevakisb6dab332007-10-02 08:30:30 +000090 wmcodec_write(DAPCTRL, 0x0);
Dave Chapman465596b2006-02-05 17:16:34 +000091 }
Dave Chapman465596b2006-02-05 17:16:34 +000092}
Dave Chapman2f767632006-02-26 15:59:46 +000093
Dave Chapman465596b2006-02-05 17:16:34 +000094/** From ipodLinux **/
95static void codec_set_active(int active)
96{
97 /* set active to 0x0 or 0x1 */
98 if (active) {
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +000099 wmcodec_write(ACTIVECTRL, 0x01);
Dave Chapman465596b2006-02-05 17:16:34 +0000100 } else {
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000101 wmcodec_write(ACTIVECTRL, 0x00);
Dave Chapman465596b2006-02-05 17:16:34 +0000102 }
103}
104
Dave Chapman465596b2006-02-05 17:16:34 +0000105
106/* Silently enable / disable audio output */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000107void audiohw_enable_output(bool enable)
Dave Chapman465596b2006-02-05 17:16:34 +0000108{
Jens Arnold7e0ea212006-03-30 20:18:02 +0000109 if (enable)
Dave Chapman465596b2006-02-05 17:16:34 +0000110 {
111 /* reset the I2S controller into known state */
112 i2s_reset();
113
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000114 wmcodec_write(RESET, 0x0); /*Reset*/
Dave Chapman465596b2006-02-05 17:16:34 +0000115
116 codec_set_active(0x0);
117
118 /* DACSEL=1 */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000119 wmcodec_write(0x4, 0x10);
Dave Chapman465596b2006-02-05 17:16:34 +0000120
121 /* set power register to POWEROFF=0 on OUTPD=0, DACPD=0 */
Michael Sevakisb6dab332007-10-02 08:30:30 +0000122 wmcodec_write(PDCTRL, 0x67);
Dave Chapman465596b2006-02-05 17:16:34 +0000123
124 /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */
125 /* IWL=00(16 bit) FORMAT=10(I2S format) */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000126 wmcodec_write(AINTFCE, 0x42);
Dave Chapman465596b2006-02-05 17:16:34 +0000127
Michael Sevakis15b73212007-10-02 07:48:50 +0000128 audiohw_set_sample_rate(WM8721_USB24_44100HZ);
Dave Chapman465596b2006-02-05 17:16:34 +0000129
130 /* set the volume to -6dB */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000131 wmcodec_write(LOUTVOL, IPOD_PCM_LEVEL);
132 wmcodec_write(ROUTVOL, 0x100 | IPOD_PCM_LEVEL);
Dave Chapman465596b2006-02-05 17:16:34 +0000133
134 /* ACTIVE=1 */
135 codec_set_active(1);
136
137 /* 5. Set DACMU = 0 to soft-un-mute the audio DACs. */
Michael Sevakisb6dab332007-10-02 08:30:30 +0000138 wmcodec_write(DAPCTRL, 0x0);
Barry Wardelle3792252006-08-30 22:31:05 +0000139
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000140 audiohw_mute(0);
Dave Chapman465596b2006-02-05 17:16:34 +0000141 } else {
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000142 audiohw_mute(1);
Dave Chapman465596b2006-02-05 17:16:34 +0000143 }
144}
145
Christian Gmeiner06971be2008-02-13 11:19:23 +0000146void audiohw_set_master_vol(int vol_l, int vol_r)
Dave Chapman465596b2006-02-05 17:16:34 +0000147{
148 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
149 /* 1111111 == +6dB */
150 /* 1111001 == 0dB */
151 /* 0110000 == -73dB */
152 /* 0101111 == mute (0x2f) */
Jens Arnold72f10272007-01-14 12:38:40 +0000153 wmcodec_write(LOUTVOL, VOLUME_ZC_WAIT | vol_l);
154 wmcodec_write(ROUTVOL, VOLUME_ZC_WAIT | vol_r);
Dave Chapman465596b2006-02-05 17:16:34 +0000155}
156
Michael Sevakis15b73212007-10-02 07:48:50 +0000157/* Nice shutdown of WM8721 codec */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000158void audiohw_close(void)
Dave Chapman465596b2006-02-05 17:16:34 +0000159{
160 /* set DACMU=1 DEEMPH=0 */
Michael Sevakisb6dab332007-10-02 08:30:30 +0000161 wmcodec_write(DAPCTRL, 0x8);
Dave Chapman465596b2006-02-05 17:16:34 +0000162
163 /* ACTIVE=0 */
164 codec_set_active(0x0);
165
Dave Chapman465596b2006-02-05 17:16:34 +0000166 /* set DACSEL=0, MUTEMIC=1 */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000167 wmcodec_write(0x4, 0x2);
Dave Chapman465596b2006-02-05 17:16:34 +0000168
169 /* set POWEROFF=0 OUTPD=0 DACPD=1 */
Michael Sevakisb6dab332007-10-02 08:30:30 +0000170 wmcodec_write(PDCTRL, 0x6f);
Dave Chapman465596b2006-02-05 17:16:34 +0000171
172 /* set POWEROFF=1 OUTPD=1 DACPD=1 */
Michael Sevakisb6dab332007-10-02 08:30:30 +0000173 wmcodec_write(PDCTRL, 0xff);
Dave Chapman465596b2006-02-05 17:16:34 +0000174}
175
176/* Change the order of the noise shaper, 5th order is recommended above 32kHz */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000177void audiohw_set_nsorder(int order)
Dave Chapman465596b2006-02-05 17:16:34 +0000178{
179 (void)order;
180}
181
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000182void audiohw_set_sample_rate(int sampling_control)
Dave Chapman465596b2006-02-05 17:16:34 +0000183{
184 codec_set_active(0x0);
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000185 wmcodec_write(SAMPCTRL, sampling_control);
Dave Chapman465596b2006-02-05 17:16:34 +0000186 codec_set_active(0x1);
187}