/*
* wm8750.c -- WM8750 ALSA SoC audio driver
*
* Copyright 2005 Openedhand Ltd.
*
* Author: Richard Purdie <richard@openedhand.com>
*
* Based on WM8753.c
*
* 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/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "wm8750.h"
#define AUDIO_NAME "WM8750"
#define WM8750_VERSION "0.12"
/*
* Debug
*/
#define WM8750_DEBUG 0
#ifdef WM8750_DEBUG
#define dbg(format, arg...) \
printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
#else
#define dbg(format, arg...) do {} while (0)
#endif
#define err(format, arg...) \
printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
#define info(format, arg...) \
printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
#define warn(format, arg...) \
printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
/* codec private data */
struct wm8750_priv {
unsigned int sysclk;
};
/*
* wm8750 register cache
* We can't read the WM8750 register space when we
* are using 2 wire for device control, so we cache them instead.
*/
static const u16 wm8750_reg[] = {
0x0097, 0x0097, 0x0079, 0x0079, /* 0 */
0x0000, 0x0008, 0x0000, 0x000a, /* 4 */
0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */
0x000f, 0x000f, 0x0000, 0x0000, /* 12 */
0x0000, 0x007b, 0x0000, 0x0032, /* 16 */
0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */
0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
0x0000, 0x0000, 0x0050, 0x0050, /* 32 */
0x0050, 0x0050, 0x0050, 0x0050, /* 36 */
0x0079, 0x0079, 0x0079, /* 40 */
};
/*
* read wm8750 register cache
*/
static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg > WM8750_CACHE_REGNUM)
return -1;
return cache[reg];
}
/*
* write wm8750 register cache
*/
static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg > WM8750_CACHE_REGNUM)
return;
cache[reg] = value;
}
static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8753 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8750_write_reg_cache (codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
#define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0)
/*
* WM8750 Controls
*/
static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"};
static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
static const char *wm8750_treble[] = {"8kHz", "4kHz"};
static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"};
static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"};
static const char *wm8750_3d_func[] = {"Capture", "Playback"};
static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"};
static const char *wm8750_ng_type[] = {"Constant PGA Gain",
"Mute ADC Output"};
static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA",
"Differential"};
static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3",
"Differential"};
static const char *wm8750_out3