4 * This file is part of BeRTOS.
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.
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.
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
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.
29 * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
33 * \author Daniele Basile <asterix@develer.com>
35 * \brief WM8731 Audio codec 2 wire driver.
41 #include "hw/hw_wm8731.h"
42 #include "cfg/cfg_wm8731.h"
44 // Define logging setting (for cfg/log.h module).
45 #define LOG_LEVEL WM8731_LOG_LEVEL
46 #define LOG_FORMAT WM8731_LOG_FORMAT
48 #include <cfg/macros.h>
55 static void wm8731_write(Wm8731 *ctx, uint8_t reg, uint16_t value)
58 uint16_t tmp = ((reg & 0x7F) << 9) | (value & 0x1FF);
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));
64 int err = i2c_error(ctx->i2c);
66 LOG_ERR("Error[%d] while send command to codec.\n", err);
70 #define RANGECONV(data, y1, y2) (((((int32_t)(data)) * ((y2) - (y1))) / ((1 << 8) - 1)) + (y1))
71 void wm8731_setVolume(Wm8731 *ctx, uint16_t device, uint8_t volume)
75 if (device & WM8731_LINE_IN)
79 wm8731_write(ctx, WM8731_REG_RIGHT_LINEIN, BV(WM8731_LINMUTE_BIT) | BV(WM8731_RLINBOTH_BIT));
80 wm8731_write(ctx, WM8731_REG_LEFT_LINEIN, BV(WM8731_LINMUTE_BIT) | BV(WM8731_LRINBOTH_BIT));
83 value = DIV_ROUND(volume * WM8731_LINVOL_BITS_MASK, 100);
85 wm8731_write(ctx, WM8731_REG_RIGHT_LINEIN, ~BV(WM8731_LINMUTE_BIT) | value);
86 wm8731_write(ctx, WM8731_REG_LEFT_LINEIN, ~BV(WM8731_RINMUTE_BIT) | value);
87 LOG_INFO("Set LINE IN vol[%d]%% raw[%d]\n", volume, value);
90 if (device & WM8731_HEADPHONE)
92 value = DIV_ROUND(volume * WM8731_RHPVOL_BITS_MASK, 100);
94 wm8731_write(ctx, WM8731_REG_RIGHT_HPOUT, value | BV(WM8731_RZCEN_BIT) | BV(WM8731_RLHPBOTH_BIT));
95 wm8731_write(ctx, WM8731_REG_LEFT_HPOUT, value | BV(WM8731_LZCEN_BIT) | BV(WM8731_LRHPBOTH_BIT));
96 LOG_INFO("Set HEADPHONE vol[%d]%% raw[%d]\n", volume, value);
101 void wm8731_powerOn(Wm8731 *ctx)
103 LOG_INFO("Power on codec\n");
104 wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, ~BV(WM8731_POWEROFF_BIT) & 0x7F);
107 void wm8731_powerOff(Wm8731 *ctx)
109 LOG_INFO("Power off codec\n");
110 wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, BV(WM8731_POWEROFF_BIT) & 0x7F);
113 void wm8731_powerOnDevices(Wm8731 *ctx, uint16_t device)
115 wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, ~device & 0x7F);
116 LOG_INFO("Turn on the devices[%x]\n", ~device & 0x7F);
119 void wm8731_powerOffDevices(Wm8731 *ctx, uint16_t device)
121 wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, device & 0x7F);
122 LOG_INFO("Turn off the devices[%x]\n", device);
125 void wm8731_init(Wm8731 *ctx, I2c *i2c, uint8_t codec_addr)
128 ctx->addr = codec_addr;
133 LOG_INFO("Init WM8731 codec.\n");
135 /* Reset codec and active it */
136 wm8731_write(ctx, WM8731_REG_RESET, 0);
139 /* Configure the codec */
140 wm8731_write(ctx, WM8731_REG_DIGITAL_PATH_CTRL, CONFIG_WM8731_DEEMP | CONFIG_WM8731_DAPC | (CONFIG_WM8731_DACMU << WM8731_DACMU));
142 #if CONFIG_WM8731_MICBOOST
143 wm8731_write(ctx, WM8731_REG_ANALOGUE_PATH_CTRL, BV(WM8731_MICBOOST) | CONFIG_WM8731_INSEL | CONFIG_WM8731_BYPASS | CONFIG_WM8731_SIDEATT);
145 wm8731_write(ctx, WM8731_REG_ANALOGUE_PATH_CTRL, (CONFIG_WM8731_INSEL | CONFIG_WM8731_BYPASS | CONFIG_WM8731_SIDEATT) & ~BV(WM8731_MICBOOST));
149 wm8731_write(ctx, WM8731_REG_DA_INTERFACE_FORMAT, CONFIG_WM8731_INTERFACE_FORMAT | CONFIG_WM8731_IWL_BITS | BV(WM8731_MS_BIT));
151 wm8731_write(ctx, WM8731_REG_DA_INTERFACE_FORMAT,
152 (CONFIG_WM8731_INTERFACE_FORMAT | CONFIG_WM8731_IWL_BITS | BV(WM8731_MS_BIT)) & ~BV(WM8731_MS_BIT));
155 wm8731_write(ctx, WM8731_REG_SAMPLECTRL, CONFIG_WM8731_SAMPLING_RATES);
157 /* By default we turn on all devices and disable only the outclock */
158 wm8731_write(ctx, WM8731_REG_ACTIVE_CTRL, 1);
159 wm8731_write(ctx, WM8731_REG_PWDOWN_CTRL, 0x40);