nfsd: nfsd should drop CAP_MKNOD for non-root
[safe/jmp/linux-2.6] / sound / soc / codecs / wm8990.c
index a7d25e2..a5731fa 100644 (file)
@@ -2,8 +2,7 @@
  * wm8990.c  --  WM8990 ALSA Soc Audio driver
  *
  * Copyright 2008 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
 
 #include "wm8990.h"
 
-#define AUDIO_NAME "wm8990"
 #define WM8990_VERSION "0.2"
 
-/*
- * Debug
- */
-
-#define WM8990_DEBUG 0
-
-#ifdef WM8990_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 wm8990_priv {
        unsigned int sysclk;
@@ -101,7 +80,7 @@ static const u16 wm8990_reg[] = {
        0x0003,     /* R35 - ClassD1 */
        0x0000,     /* R36 */
        0x0100,     /* R37 - ClassD3 */
-       0x0000,     /* R38 */
+       0x0079,     /* R38 - ClassD4 */
        0x0000,     /* R39 - Input Mixer1 */
        0x0000,     /* R40 - Input Mixer2 */
        0x0000,     /* R41 - Input Mixer3 */
@@ -126,6 +105,7 @@ static const u16 wm8990_reg[] = {
        0x0008,     /* R60 - PLL1 */
        0x0031,     /* R61 - PLL2 */
        0x0026,     /* R62 - PLL3 */
+       0x0000,     /* R63 - Driver internal */
 };
 
 /*
@@ -146,10 +126,9 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec,
        unsigned int reg, unsigned int value)
 {
        u16 *cache = codec->reg_cache;
-       BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1);
 
-       /* Reset register is uncached */
-       if (reg == 0)
+       /* Reset register and reserved registers are uncached */
+       if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1)
                return;
 
        cache[reg] = value;
@@ -197,7 +176,9 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value & 0xff;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int reg = mc->reg;
        int ret;
        u16 val;
 
@@ -330,11 +311,15 @@ SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1,
        WM8990_CDMODE_BIT, 1, 0),
 
 SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME,
-       WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0),
+       WM8990_SPKATTN_SHIFT, WM8990_SPKATTN_MASK, 0),
 SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3,
        WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0),
 SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3,
        WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0),
+SOC_SINGLE_TLV("Speaker Volume", WM8990_CLASSD4,
+       WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("Speaker ZC Switch", WM8990_CLASSD4,
+       WM8990_SPKZC_SHIFT, WM8990_SPKZC_MASK, 0),
 
 SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
        WM8990_LEFT_DAC_DIGITAL_VOLUME,
@@ -939,7 +924,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
        {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
        {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
-       {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},
+       {"SPKMIX", "SPKMIX Left DAC Switch", "Left DAC"},
 
        /* LONMIX */
        {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
@@ -1048,7 +1033,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
        pll_div->k = K;
 }
 
-static int wm8990_set_dai_pll(struct snd_soc_codec_dai *codec_dai,
+static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai,
                int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
        u16 reg;
@@ -1084,7 +1069,7 @@ static int wm8990_set_dai_pll(struct snd_soc_codec_dai *codec_dai,
 /*
  * Clock after PLL and dividers
  */
-static int wm8990_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1097,7 +1082,7 @@ static int wm8990_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
 /*
  * Set's ADC and Voice DAC format.
  */
-static int wm8990_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1150,7 +1135,7 @@ static int wm8990_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return 0;
 }
 
-static int wm8990_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,
+static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                int div_id, int div)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1188,7 +1173,8 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,
  * Set PCM DAI bit size and sample rate.
  */
 static int wm8990_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
@@ -1215,7 +1201,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int wm8990_mute(struct snd_soc_codec_dai *dai, int mute)
+static int wm8990_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        u16 val;
@@ -1238,8 +1224,14 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
+
        case SND_SOC_BIAS_PREPARE:
+               /* VMID=2*50k */
+               val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) &
+                       ~WM8990_VMID_MODE_MASK;
+               wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
                break;
+
        case SND_SOC_BIAS_STANDBY:
                if (codec->bias_level == SND_SOC_BIAS_OFF) {
                        /* Enable all output discharge bits */
@@ -1288,10 +1280,17 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
 
                        /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
                        wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
-               } else {
-                       /* ON -> standby */
 
+                       /* Enable workaround for ADC clocking issue. */
+                       wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2);
+                       wm8990_write(codec, WM8990_EXT_CTL1, 0xa003);
+                       wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0);
                }
+
+               /* VMID=2*250k */
+               val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) &
+                       ~WM8990_VMID_MODE_MASK;
+               wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
                break;
 
        case SND_SOC_BIAS_OFF:
@@ -1348,7 +1347,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
  * 1. ADC/DAC on Primary Interface
  * 2. ADC on Primary Interface/DAC on secondary
  */
-struct snd_soc_codec_dai wm8990_dai = {
+struct snd_soc_dai wm8990_dai = {
 /* ADC/DAC on primary */
        .name = "WM8990 ADC/DAC Primary",
        .id = 1,
@@ -1365,8 +1364,7 @@ struct snd_soc_codec_dai wm8990_dai = {
                .rates = WM8990_RATES,
                .formats = WM8990_FORMATS,},
        .ops = {
-               .hw_params = wm8990_hw_params,},
-       .dai_ops = {
+               .hw_params = wm8990_hw_params,
                .digital_mute = wm8990_mute,
                .set_fmt = wm8990_set_dai_fmt,
                .set_clkdiv = wm8990_set_dai_clkdiv,
@@ -1465,7 +1463,7 @@ static int wm8990_init(struct snd_soc_device *socdev)
 
        wm8990_add_controls(codec);
        wm8990_add_widgets(codec);
-       ret = snd_soc_register_card(socdev);
+       ret = snd_soc_init_card(socdev);
        if (ret < 0) {
                printk(KERN_ERR "wm8990: failed to register card\n");
                goto card_err;
@@ -1492,83 +1490,86 @@ static struct snd_soc_device *wm8990_socdev;
  *    low  = 0x34
  *    high = 0x36
  */
-static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
-
-/* Magic definition of all other variables and things */
-I2C_CLIENT_INSMOD;
 
-static struct i2c_driver wm8990_i2c_driver;
-static struct i2c_client client_template;
-
-static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+static int wm8990_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        struct snd_soc_device *socdev = wm8990_socdev;
-       struct wm8990_setup_data *setup = socdev->codec_data;
        struct snd_soc_codec *codec = socdev->codec;
-       struct i2c_client *i2c;
        int ret;
 
-       if (addr != setup->i2c_address)
-               return -ENODEV;
-
-       client_template.adapter = adap;
-       client_template.addr = addr;
-
-       i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
-       ret = i2c_attach_client(i2c);
-       if (ret < 0) {
-               err("failed to attach codec at addr %x\n", addr);
-               goto err;
-       }
-
        ret = wm8990_init(socdev);
-       if (ret < 0) {
-               err("failed to initialise WM8990\n");
-               goto err;
-       }
-       return ret;
+       if (ret < 0)
+               pr_err("failed to initialise WM8990\n");
 
-err:
-       kfree(codec);
-       kfree(i2c);
        return ret;
 }
 
-static int wm8990_i2c_detach(struct i2c_client *client)
+static int wm8990_i2c_remove(struct i2c_client *client)
 {
        struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       i2c_detach_client(client);
        kfree(codec->reg_cache);
-       kfree(client);
        return 0;
 }
 
-static int wm8990_i2c_attach(struct i2c_adapter *adap)
-{
-       return i2c_probe(adap, &addr_data, wm8990_codec_probe);
-}
+static const struct i2c_device_id wm8990_i2c_id[] = {
+       { "wm8990", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
 
 static struct i2c_driver wm8990_i2c_driver = {
        .driver = {
                .name = "WM8990 I2C Codec",
                .owner = THIS_MODULE,
        },
-       .attach_adapter = wm8990_i2c_attach,
-       .detach_client =  wm8990_i2c_detach,
-       .command =        NULL,
+       .probe =    wm8990_i2c_probe,
+       .remove =   wm8990_i2c_remove,
+       .id_table = wm8990_i2c_id,
 };
 
-static struct i2c_client client_template = {
-       .name =   "WM8990",
-       .driver = &wm8990_i2c_driver,
-};
+static int wm8990_add_i2c_device(struct platform_device *pdev,
+                                const struct wm8990_setup_data *setup)
+{
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+       int ret;
+
+       ret = i2c_add_driver(&wm8990_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       strlcpy(info.type, "wm8990", I2C_NAME_SIZE);
+
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
+                       setup->i2c_bus);
+               goto err_driver;
+       }
+
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                       (unsigned int)info.addr);
+               goto err_driver;
+       }
+
+       return 0;
+
+err_driver:
+       i2c_del_driver(&wm8990_i2c_driver);
+       return -ENODEV;
+}
 #endif
 
 static int wm8990_probe(struct platform_device *pdev)
@@ -1577,9 +1578,9 @@ static int wm8990_probe(struct platform_device *pdev)
        struct wm8990_setup_data *setup;
        struct snd_soc_codec *codec;
        struct wm8990_priv *wm8990;
-       int ret = 0;
+       int ret;
 
-       info("WM8990 Audio Codec %s\n", WM8990_VERSION);
+       pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION);
 
        setup = socdev->codec_data;
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
@@ -1599,17 +1600,19 @@ static int wm8990_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&codec->dapm_paths);
        wm8990_socdev = socdev;
 
+       ret = -ENODEV;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        if (setup->i2c_address) {
-               normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = i2c_add_driver(&wm8990_i2c_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add i2c driver");
+               ret = wm8990_add_i2c_device(pdev, setup);
        }
-#else
-               /* Add other interfaces here */
 #endif
+
+       if (ret != 0) {
+               kfree(codec->private_data);
+               kfree(codec);
+       }
        return ret;
 }
 
@@ -1624,6 +1627,7 @@ static int wm8990_remove(struct platform_device *pdev)
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8990_i2c_driver);
 #endif
        kfree(codec->private_data);
@@ -1640,6 +1644,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8990 = {
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990);
 
+static int __init wm8990_modinit(void)
+{
+       return snd_soc_register_dai(&wm8990_dai);
+}
+module_init(wm8990_modinit);
+
+static void __exit wm8990_exit(void)
+{
+       snd_soc_unregister_dai(&wm8990_dai);
+}
+module_exit(wm8990_exit);
+
 MODULE_DESCRIPTION("ASoC WM8990 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");