2a921792e49e3ed65278a9b4c4bf0d249bfdf61a
[bertos.git] / bertos / drv / wm8731.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \author Daniele Basile <asterix@develer.com>
34  *
35  * \brief WM8731 Audio codec 2 wire driver.
36  *
37  */
38
39 #include "wm8731.h"
40
41 #include "hw/hw_wm8731.h"
42 #include "cfg/cfg_wm8731.h"
43
44 // Define logging setting (for cfg/log.h module).
45 #define LOG_LEVEL   WM8731_LOG_LEVEL
46 #define LOG_FORMAT  WM8731_LOG_FORMAT
47 #include <cfg/log.h>
48 #include <cfg/macros.h>
49
50 #include <cpu/irq.h>
51
52 #include <drv/i2c.h>
53
54
55 static void wm8731_write(Wm8731 *ctx, uint8_t reg, uint16_t value)
56 {
57
58         uint16_t tmp = ((reg & 0x7F) << 9) | (value & 0x1FF);
59
60         i2c_start_w(ctx->i2c, ctx->addr, 2, I2C_STOP);
61         i2c_putc(ctx->i2c, (uint8_t)((tmp & 0xFF00) >> 8));
62         i2c_putc(ctx->i2c, (uint8_t)(tmp & 0xFF));
63
64         if (i2c_error(ctx->i2c))
65                 LOG_ERR("Error while send command to codec.\n");
66
67 }
68
69 void wm8731_setVolume(Wm8731 *ctx, uint16_t device, uint8_t volume)
70 {
71         uint16_t value;
72
73         if (device & WM8731_LINE_IN_RX)
74         {
75                 if (!volume)
76                         wm8731_write(ctx, WM8731_REG_RIGHT_LINEIN, BV(WM8731_LINMUTE_BIT));
77
78                 value = DIV_ROUND(volume * WM8731_LINVOL_BITS_MASK, 100) & WM8731_LINVOL_BITS_MASK;
79
80                 wm8731_write(ctx, WM8731_REG_RIGHT_LINEIN, ~BV(WM8731_LINMUTE_BIT));
81                 wm8731_write(ctx, WM8731_REG_RIGHT_LINEIN, value);
82                 LOG_INFO("Set LINE IN Rx vol[%d]%% raw[%d]\n", volume, value);
83         }
84
85         if (device & WM8731_LINE_IN_LX)
86         {
87                 if (!volume)
88                         wm8731_write(ctx, WM8731_REG_LEFT_LINEIN, BV(WM8731_LINMUTE_BIT));
89
90                 value = DIV_ROUND(volume * WM8731_RINVOL_BITS_MASK, 100) & WM8731_RINVOL_BITS_MASK;
91
92                 wm8731_write(ctx, WM8731_REG_LEFT_LINEIN, ~BV(WM8731_LINMUTE_BIT));
93                 wm8731_write(ctx, WM8731_REG_LEFT_LINEIN, value);
94                 LOG_INFO("Set LINE IN Lx vol[%d]%% raw[%d]\n", volume, value);
95         }
96
97
98         if (device & WM8731_HEADPHONE_RX)
99         {
100                 value = DIV_ROUND(volume * WM8731_RHPVOL_BITS_MASK, 100) & WM8731_LHPVOL_BITS_MASK;
101                 wm8731_write(ctx, WM8731_REG_RIGHT_HPOUT, value | BV(WM8731_RZCEN_BIT));
102                 LOG_INFO("Set HEADPHONE Rx vol[%d]%% raw[%d]\n", volume, value);
103         }
104
105
106         if (device & WM8731_HEADPHONE_LX)
107         {
108                 value = DIV_ROUND(volume * WM8731_LHPVOL_BITS_MASK, 100) & WM8731_LHPVOL_BITS_MASK;
109                 wm8731_write(ctx, WM8731_REG_LEFT_HPOUT, value  | BV(WM8731_LZCEN_BIT));
110                 LOG_INFO("Set HEADPHONE Lx vol[%d]%% raw[%d]\n", volume, value);
111         }
112
113 }
114
115 void wm8731_powerOn(Wm8731 *ctx)
116 {
117         LOG_INFO("Power on codec\n");
118         wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, ~BV(WM8731_POWEROFF_BIT) & 0x7F);
119 }
120
121 void wm8731_powerOff(Wm8731 *ctx)
122 {
123         LOG_INFO("Power off codec\n");
124         wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, BV(WM8731_POWEROFF_BIT) & 0x7F);
125 }
126
127 void wm8731_powerOnDevices(Wm8731 *ctx, uint16_t device)
128 {
129         wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, ~device & 0x7F);
130         LOG_INFO("Turn on the devices[%x]\n", ~device & 0x7F);
131 }
132
133 void wm8731_powerOffDevices(Wm8731 *ctx, uint16_t device)
134 {
135         wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, device & 0x7F);
136         LOG_INFO("Turn off the devices[%x]\n", device);
137 }
138
139 void wm8731_init(Wm8731 *ctx, I2c *i2c, uint8_t codec_addr)
140 {
141         ctx->i2c = i2c;
142         ctx->addr = codec_addr;
143
144         WM8731_PIN_INIT();
145         WM8731_MCLK_INIT();
146
147         LOG_INFO("Init WM8731 codec.\n");
148
149         /* Reset codec and active it */
150         wm8731_write(ctx, WM8731_REG_RESET, 0);
151
152
153         /* Configure the codec */
154         wm8731_write(ctx, WM8731_REG_DIGITAL_PATH_CTRL, CONFIG_WM8731_DEEMP | CONFIG_WM8731_DAPC |
155                                                 (CONFIG_WM8731_DACMU << WM8731_DACMU));
156         wm8731_write(ctx, WM8731_REG_ANALOGUE_PATH_CTRL, (CONFIG_WM8731_MICBOOST ? WM8731_MICBOOST : ~WM8731_MICBOOST) |
157                                                 CONFIG_WM8731_INSEL | CONFIG_WM8731_BYPASS | CONFIG_WM8731_SIDEATT);
158
159         wm8731_write(ctx, WM8731_REG_DA_INTERFACE_FORMAT, 0x2);
160         wm8731_write(ctx, WM8731_REG_SAMPLECTRL, 0x6);
161
162         wm8731_write(ctx, WM8731_REG_ACTIVE_CTRL, 1);
163
164         /* By default we turn on all devices and disable only the outclock */
165         wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, 0x47);
166 }