/*
* wm8955.c -- WM8955 ALSA SoC Audio driver
*
* Copyright 2009 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/wm8955.h>
#include "wm8955.h"
#define WM8955_NUM_SUPPLIES 4
static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
"DCVDD",
"DBVDD",
"HPVDD",
"AVDD",
};
/* codec private data */
struct wm8955_priv {
enum snd_soc_control_type control_type;
unsigned int mclk_rate;
int deemph;
int fs;
struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
};
static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
0x0000, /* R0 */
0x0000, /* R1 */
0x0079, /* R2 - LOUT1 volume */
0x0079, /* R3 - ROUT1 volume */
0x0000, /* R4 */
0x0008, /* R5 - DAC Control */
0x0000, /* R6 */
0x000A, /* R7 - Audio Interface */
0x0000, /* R8 - Sample Rate */
0x0000, /* R9 */
0x00FF, /* R10 - Left DAC volume */
0x00FF, /* R11 - Right DAC volume */
0x000F, /* R12 - Bass control */
0x000F, /* R13 - Treble control */
0x0000, /* R14 */
0x0000, /* R15 - Reset */
0x0000, /* R16 */
0x0000, /* R17 */
0x0000, /* R18 */
0x0000, /* R19 */
0x0000, /* R20 */
0x0000, /* R21 */
0x0000, /* R22 */
0x00C1, /* R23 - Additional control (1) */
0x0000, /* R24 - Additional control (2) */
0x0000, /* R25 - Power Management (1) */
0x0000, /* R26 - Power Management (2) */
0x0000, /* R27 - Additional Control (3) */
0x0000, /* R28 */
0x0000, /* R29 */
0x0000, /* R30 */
0x0000, /* R31 */
0x0000, /* R32 */
0x0000, /* R33 */
0x0050, /* R34 - Left out Mix (1) */
0x0050, /* R35 - Left out Mix (2) */
0x0050, /* R36 - Right out Mix (1) */
0x0050, /* R37 - Right Out Mix (2) */
0x0050, /* R38 - Mono out Mix (1) */
0x0050, /* R39 - Mono out Mix (2) */
0x0079, /* R40 - LOUT2 volume */
0x0079, /* R41 - ROUT2 volume */
0x0079, /* R42 - MONOOUT volume */
0x0000, /* R43 - Clocking / PLL */
0x0103, /* R44 - PLL Control 1 */
0x0024, /* R45 - PLL Control 2 */
0x01BA, /* R46 - PLL Control 3 */
0x0000, /* R47 */
0x0000, /* R48 */
0x0000, /* R49 */
0x0000, /* R50 */
0x0000, /* R51 */
0x0000, /* R52 */
0x0000, /* R53 */
0x0000, /* R54 */
0x0000, /* R55 */
0x0000, /* R56 */
0x0000, /* R57 */
0x0000, /* R58 */
0x0000, /* R59 - PLL Control 4 */
};
static int wm8955_reset(struct snd_soc_codec *codec)
{
return snd_soc_write(codec, WM8955_RESET, 0);
}
struct pll_factors {
int n;
int k;
int outdiv;
};
/* The size in bits of the FLL divide multiplied by 10
* to allow rounding later */
#define FIXED_FLL_SIZE ((1 << 22) * 10)
static int wm8995_pll_factors(struct device *dev,
int Fref, int Fout, struct pll_factors *pll)
{
u64 Kpart;
unsigned int K, Ndiv, Nmod, target;
dev_dbg(dev, "Fref=%u Fout=%u\n", Fref, Fout);
/* The oscilator should run at should be 90-100MHz, and
* there's a divide by 4 plus an optional divide by 2 in the
* output path to generate the system clock. The clock table
* is sortd so we should always generate a suitable target. */
target = Fout * 4;
if (target < 90000000) {
pll->outdiv = 1;
target *= 2;
} else {
pll->outdiv = 0;
}
WARN_ON(target < 90000000 || target > 100000000);
dev_dbg(dev, "Fvco=%dHz\n", target);
/* Now, calculate N.K */
Ndiv = target / Fref;
pll->n = Ndiv;
Nmod = target % Fref;