140e0aa64SRichard Purdie /* 240e0aa64SRichard Purdie * wm8731.c -- WM8731 ALSA SoC Audio driver 340e0aa64SRichard Purdie * 440e0aa64SRichard Purdie * Copyright 2005 Openedhand Ltd. 540e0aa64SRichard Purdie * 640e0aa64SRichard Purdie * Author: Richard Purdie <richard@openedhand.com> 740e0aa64SRichard Purdie * 840e0aa64SRichard Purdie * Based on wm8753.c by Liam Girdwood 940e0aa64SRichard Purdie * 1040e0aa64SRichard Purdie * This program is free software; you can redistribute it and/or modify 1140e0aa64SRichard Purdie * it under the terms of the GNU General Public License version 2 as 1240e0aa64SRichard Purdie * published by the Free Software Foundation. 1340e0aa64SRichard Purdie */ 1440e0aa64SRichard Purdie 1540e0aa64SRichard Purdie #include <linux/module.h> 1640e0aa64SRichard Purdie #include <linux/moduleparam.h> 1740e0aa64SRichard Purdie #include <linux/init.h> 1840e0aa64SRichard Purdie #include <linux/delay.h> 1940e0aa64SRichard Purdie #include <linux/pm.h> 2040e0aa64SRichard Purdie #include <linux/i2c.h> 215a0e3ad6STejun Heo #include <linux/slab.h> 22*05d448e2SMark Brown #include <linux/regmap.h> 237dea7c01SMark Brown #include <linux/regulator/consumer.h> 24d2a40355SCliff Cai #include <linux/spi/spi.h> 25a7f96e4dSMark Brown #include <linux/of_device.h> 2640e0aa64SRichard Purdie #include <sound/core.h> 2740e0aa64SRichard Purdie #include <sound/pcm.h> 2840e0aa64SRichard Purdie #include <sound/pcm_params.h> 2940e0aa64SRichard Purdie #include <sound/soc.h> 3040e0aa64SRichard Purdie #include <sound/initval.h> 31d00efa64SMark Brown #include <sound/tlv.h> 3240e0aa64SRichard Purdie 3340e0aa64SRichard Purdie #include "wm8731.h" 3440e0aa64SRichard Purdie 357dea7c01SMark Brown #define WM8731_NUM_SUPPLIES 4 367dea7c01SMark Brown static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { 377dea7c01SMark Brown "AVDD", 387dea7c01SMark Brown "HPVDD", 397dea7c01SMark Brown "DCVDD", 407dea7c01SMark Brown "DBVDD", 417dea7c01SMark Brown }; 427dea7c01SMark Brown 43b36d61d4SFrank Mandarino /* codec private data */ 44b36d61d4SFrank Mandarino struct wm8731_priv { 45*05d448e2SMark Brown struct regmap *regmap; 467dea7c01SMark Brown struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; 47b36d61d4SFrank Mandarino unsigned int sysclk; 489745e824SMark Brown int sysclk_type; 49dd31b310SMark Brown int playback_fs; 50dd31b310SMark Brown bool deemph; 51b36d61d4SFrank Mandarino }; 52b36d61d4SFrank Mandarino 53a8035c8fSMark Brown 5440e0aa64SRichard Purdie /* 5540e0aa64SRichard Purdie * wm8731 register cache 5640e0aa64SRichard Purdie */ 57*05d448e2SMark Brown static const struct reg_default wm8731_reg_defaults[] = { 58*05d448e2SMark Brown { 0, 0x0097 }, 59*05d448e2SMark Brown { 1, 0x0097 }, 60*05d448e2SMark Brown { 2, 0x0079 }, 61*05d448e2SMark Brown { 3, 0x0079 }, 62*05d448e2SMark Brown { 4, 0x000a }, 63*05d448e2SMark Brown { 5, 0x0008 }, 64*05d448e2SMark Brown { 6, 0x009f }, 65*05d448e2SMark Brown { 7, 0x000a }, 66*05d448e2SMark Brown { 8, 0x0000 }, 67*05d448e2SMark Brown { 9, 0x0000 }, 6840e0aa64SRichard Purdie }; 6940e0aa64SRichard Purdie 70*05d448e2SMark Brown static bool wm8731_volatile(struct device *dev, unsigned int reg) 71*05d448e2SMark Brown { 72*05d448e2SMark Brown return reg == WM8731_RESET; 73*05d448e2SMark Brown } 74*05d448e2SMark Brown 75*05d448e2SMark Brown static bool wm8731_writeable(struct device *dev, unsigned int reg) 76*05d448e2SMark Brown { 77*05d448e2SMark Brown return reg <= WM8731_RESET; 78*05d448e2SMark Brown } 79*05d448e2SMark Brown 8017a52fd6SMark Brown #define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0) 8140e0aa64SRichard Purdie 8240e0aa64SRichard Purdie static const char *wm8731_input_select[] = {"Line In", "Mic"}; 8359f72970SMark Brown 8459f72970SMark Brown static const struct soc_enum wm8731_insel_enum = 8559f72970SMark Brown SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select); 8659f72970SMark Brown 87dd31b310SMark Brown static int wm8731_deemph[] = { 0, 32000, 44100, 48000 }; 8859f72970SMark Brown 89dd31b310SMark Brown static int wm8731_set_deemph(struct snd_soc_codec *codec) 90dd31b310SMark Brown { 91dd31b310SMark Brown struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 92dd31b310SMark Brown int val, i, best; 93dd31b310SMark Brown 94dd31b310SMark Brown /* If we're using deemphasis select the nearest available sample 95dd31b310SMark Brown * rate. 96dd31b310SMark Brown */ 97dd31b310SMark Brown if (wm8731->deemph) { 98dd31b310SMark Brown best = 1; 99dd31b310SMark Brown for (i = 2; i < ARRAY_SIZE(wm8731_deemph); i++) { 100dd31b310SMark Brown if (abs(wm8731_deemph[i] - wm8731->playback_fs) < 101dd31b310SMark Brown abs(wm8731_deemph[best] - wm8731->playback_fs)) 102dd31b310SMark Brown best = i; 103dd31b310SMark Brown } 104dd31b310SMark Brown 105dd31b310SMark Brown val = best << 1; 106dd31b310SMark Brown } else { 107dd31b310SMark Brown best = 0; 108dd31b310SMark Brown val = 0; 109dd31b310SMark Brown } 110dd31b310SMark Brown 111dd31b310SMark Brown dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n", 112dd31b310SMark Brown best, wm8731_deemph[best]); 113dd31b310SMark Brown 114dd31b310SMark Brown return snd_soc_update_bits(codec, WM8731_APDIGI, 0x6, val); 115dd31b310SMark Brown } 116dd31b310SMark Brown 117dd31b310SMark Brown static int wm8731_get_deemph(struct snd_kcontrol *kcontrol, 118dd31b310SMark Brown struct snd_ctl_elem_value *ucontrol) 119dd31b310SMark Brown { 120dd31b310SMark Brown struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 121dd31b310SMark Brown struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 122dd31b310SMark Brown 123dd31b310SMark Brown ucontrol->value.enumerated.item[0] = wm8731->deemph; 124dd31b310SMark Brown 125dd31b310SMark Brown return 0; 126dd31b310SMark Brown } 127dd31b310SMark Brown 128dd31b310SMark Brown static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, 129dd31b310SMark Brown struct snd_ctl_elem_value *ucontrol) 130dd31b310SMark Brown { 131dd31b310SMark Brown struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 132dd31b310SMark Brown struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 133dd31b310SMark Brown int deemph = ucontrol->value.enumerated.item[0]; 134dd31b310SMark Brown int ret = 0; 135dd31b310SMark Brown 136dd31b310SMark Brown if (deemph > 1) 137dd31b310SMark Brown return -EINVAL; 138dd31b310SMark Brown 139dd31b310SMark Brown mutex_lock(&codec->mutex); 140dd31b310SMark Brown if (wm8731->deemph != deemph) { 141dd31b310SMark Brown wm8731->deemph = deemph; 142dd31b310SMark Brown 143dd31b310SMark Brown wm8731_set_deemph(codec); 144dd31b310SMark Brown 145dd31b310SMark Brown ret = 1; 146dd31b310SMark Brown } 147dd31b310SMark Brown mutex_unlock(&codec->mutex); 148dd31b310SMark Brown 149dd31b310SMark Brown return ret; 150dd31b310SMark Brown } 15140e0aa64SRichard Purdie 152d00efa64SMark Brown static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0); 153d00efa64SMark Brown static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0); 154d00efa64SMark Brown static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); 155d921184eSMark Brown static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 2000, 0); 156d00efa64SMark Brown 15740e0aa64SRichard Purdie static const struct snd_kcontrol_new wm8731_snd_controls[] = { 15840e0aa64SRichard Purdie 159d00efa64SMark Brown SOC_DOUBLE_R_TLV("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, 160d00efa64SMark Brown 0, 127, 0, out_tlv), 161bd903b6eSLiam Girdwood SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, 162bd903b6eSLiam Girdwood 7, 1, 0), 16340e0aa64SRichard Purdie 164d00efa64SMark Brown SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0, 165d00efa64SMark Brown in_tlv), 16640e0aa64SRichard Purdie SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), 16740e0aa64SRichard Purdie 168d921184eSMark Brown SOC_SINGLE_TLV("Mic Boost Volume", WM8731_APANA, 0, 1, 0, mic_tlv), 169ef38ed88SMark Brown SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1), 17040e0aa64SRichard Purdie 171d00efa64SMark Brown SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1, 172d00efa64SMark Brown sidetone_tlv), 17340e0aa64SRichard Purdie 17440e0aa64SRichard Purdie SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1), 17540e0aa64SRichard Purdie SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), 17640e0aa64SRichard Purdie 177dd31b310SMark Brown SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0, 178dd31b310SMark Brown wm8731_get_deemph, wm8731_put_deemph), 17940e0aa64SRichard Purdie }; 18040e0aa64SRichard Purdie 18140e0aa64SRichard Purdie /* Output Mixer */ 18240e0aa64SRichard Purdie static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { 18340e0aa64SRichard Purdie SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), 18440e0aa64SRichard Purdie SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), 18540e0aa64SRichard Purdie SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), 18640e0aa64SRichard Purdie }; 18740e0aa64SRichard Purdie 18840e0aa64SRichard Purdie /* Input mux */ 18940e0aa64SRichard Purdie static const struct snd_kcontrol_new wm8731_input_mux_controls = 19059f72970SMark Brown SOC_DAPM_ENUM("Input Select", wm8731_insel_enum); 19140e0aa64SRichard Purdie 19240e0aa64SRichard Purdie static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { 1938a27bd9aSMark Brown SND_SOC_DAPM_SUPPLY("ACTIVE",WM8731_ACTIVE, 0, 0, NULL, 0), 1949745e824SMark Brown SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0), 19540e0aa64SRichard Purdie SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, 19640e0aa64SRichard Purdie &wm8731_output_mixer_controls[0], 19740e0aa64SRichard Purdie ARRAY_SIZE(wm8731_output_mixer_controls)), 19840e0aa64SRichard Purdie SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1), 19940e0aa64SRichard Purdie SND_SOC_DAPM_OUTPUT("LOUT"), 20040e0aa64SRichard Purdie SND_SOC_DAPM_OUTPUT("LHPOUT"), 20140e0aa64SRichard Purdie SND_SOC_DAPM_OUTPUT("ROUT"), 20240e0aa64SRichard Purdie SND_SOC_DAPM_OUTPUT("RHPOUT"), 20340e0aa64SRichard Purdie SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1), 20440e0aa64SRichard Purdie SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls), 20540e0aa64SRichard Purdie SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0), 20640e0aa64SRichard Purdie SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1), 20740e0aa64SRichard Purdie SND_SOC_DAPM_INPUT("MICIN"), 20840e0aa64SRichard Purdie SND_SOC_DAPM_INPUT("RLINEIN"), 20940e0aa64SRichard Purdie SND_SOC_DAPM_INPUT("LLINEIN"), 21040e0aa64SRichard Purdie }; 21140e0aa64SRichard Purdie 2129745e824SMark Brown static int wm8731_check_osc(struct snd_soc_dapm_widget *source, 2139745e824SMark Brown struct snd_soc_dapm_widget *sink) 2149745e824SMark Brown { 2159745e824SMark Brown struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec); 2169745e824SMark Brown 2175a195b44SNicolas Ferre return wm8731->sysclk_type == WM8731_SYSCLK_XTAL; 2189745e824SMark Brown } 2199745e824SMark Brown 2205e251aecSMark Brown static const struct snd_soc_dapm_route wm8731_intercon[] = { 2219745e824SMark Brown {"DAC", NULL, "OSC", wm8731_check_osc}, 2229745e824SMark Brown {"ADC", NULL, "OSC", wm8731_check_osc}, 2238a27bd9aSMark Brown {"DAC", NULL, "ACTIVE"}, 2248a27bd9aSMark Brown {"ADC", NULL, "ACTIVE"}, 2259745e824SMark Brown 22640e0aa64SRichard Purdie /* output mixer */ 22740e0aa64SRichard Purdie {"Output Mixer", "Line Bypass Switch", "Line Input"}, 22840e0aa64SRichard Purdie {"Output Mixer", "HiFi Playback Switch", "DAC"}, 22940e0aa64SRichard Purdie {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, 23040e0aa64SRichard Purdie 23140e0aa64SRichard Purdie /* outputs */ 23240e0aa64SRichard Purdie {"RHPOUT", NULL, "Output Mixer"}, 23340e0aa64SRichard Purdie {"ROUT", NULL, "Output Mixer"}, 23440e0aa64SRichard Purdie {"LHPOUT", NULL, "Output Mixer"}, 23540e0aa64SRichard Purdie {"LOUT", NULL, "Output Mixer"}, 23640e0aa64SRichard Purdie 23740e0aa64SRichard Purdie /* input mux */ 23840e0aa64SRichard Purdie {"Input Mux", "Line In", "Line Input"}, 23940e0aa64SRichard Purdie {"Input Mux", "Mic", "Mic Bias"}, 24040e0aa64SRichard Purdie {"ADC", NULL, "Input Mux"}, 24140e0aa64SRichard Purdie 24240e0aa64SRichard Purdie /* inputs */ 24340e0aa64SRichard Purdie {"Line Input", NULL, "LLINEIN"}, 24440e0aa64SRichard Purdie {"Line Input", NULL, "RLINEIN"}, 24540e0aa64SRichard Purdie {"Mic Bias", NULL, "MICIN"}, 24640e0aa64SRichard Purdie }; 24740e0aa64SRichard Purdie 24840e0aa64SRichard Purdie struct _coeff_div { 24940e0aa64SRichard Purdie u32 mclk; 25040e0aa64SRichard Purdie u32 rate; 25140e0aa64SRichard Purdie u16 fs; 25240e0aa64SRichard Purdie u8 sr:4; 25340e0aa64SRichard Purdie u8 bosr:1; 25440e0aa64SRichard Purdie u8 usb:1; 25540e0aa64SRichard Purdie }; 25640e0aa64SRichard Purdie 25740e0aa64SRichard Purdie /* codec mclk clock divider coefficients */ 25840e0aa64SRichard Purdie static const struct _coeff_div coeff_div[] = { 25940e0aa64SRichard Purdie /* 48k */ 26040e0aa64SRichard Purdie {12288000, 48000, 256, 0x0, 0x0, 0x0}, 26140e0aa64SRichard Purdie {18432000, 48000, 384, 0x0, 0x1, 0x0}, 26240e0aa64SRichard Purdie {12000000, 48000, 250, 0x0, 0x0, 0x1}, 26340e0aa64SRichard Purdie 26440e0aa64SRichard Purdie /* 32k */ 26540e0aa64SRichard Purdie {12288000, 32000, 384, 0x6, 0x0, 0x0}, 26640e0aa64SRichard Purdie {18432000, 32000, 576, 0x6, 0x1, 0x0}, 267298a2c75SFrank Mandarino {12000000, 32000, 375, 0x6, 0x0, 0x1}, 26840e0aa64SRichard Purdie 26940e0aa64SRichard Purdie /* 8k */ 27040e0aa64SRichard Purdie {12288000, 8000, 1536, 0x3, 0x0, 0x0}, 27140e0aa64SRichard Purdie {18432000, 8000, 2304, 0x3, 0x1, 0x0}, 27240e0aa64SRichard Purdie {11289600, 8000, 1408, 0xb, 0x0, 0x0}, 27340e0aa64SRichard Purdie {16934400, 8000, 2112, 0xb, 0x1, 0x0}, 27440e0aa64SRichard Purdie {12000000, 8000, 1500, 0x3, 0x0, 0x1}, 27540e0aa64SRichard Purdie 27640e0aa64SRichard Purdie /* 96k */ 27740e0aa64SRichard Purdie {12288000, 96000, 128, 0x7, 0x0, 0x0}, 27840e0aa64SRichard Purdie {18432000, 96000, 192, 0x7, 0x1, 0x0}, 27940e0aa64SRichard Purdie {12000000, 96000, 125, 0x7, 0x0, 0x1}, 28040e0aa64SRichard Purdie 28140e0aa64SRichard Purdie /* 44.1k */ 28240e0aa64SRichard Purdie {11289600, 44100, 256, 0x8, 0x0, 0x0}, 28340e0aa64SRichard Purdie {16934400, 44100, 384, 0x8, 0x1, 0x0}, 28440e0aa64SRichard Purdie {12000000, 44100, 272, 0x8, 0x1, 0x1}, 28540e0aa64SRichard Purdie 28640e0aa64SRichard Purdie /* 88.2k */ 28740e0aa64SRichard Purdie {11289600, 88200, 128, 0xf, 0x0, 0x0}, 28840e0aa64SRichard Purdie {16934400, 88200, 192, 0xf, 0x1, 0x0}, 28940e0aa64SRichard Purdie {12000000, 88200, 136, 0xf, 0x1, 0x1}, 29040e0aa64SRichard Purdie }; 29140e0aa64SRichard Purdie 29240e0aa64SRichard Purdie static inline int get_coeff(int mclk, int rate) 29340e0aa64SRichard Purdie { 29440e0aa64SRichard Purdie int i; 29540e0aa64SRichard Purdie 29640e0aa64SRichard Purdie for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { 29740e0aa64SRichard Purdie if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) 29840e0aa64SRichard Purdie return i; 29940e0aa64SRichard Purdie } 30040e0aa64SRichard Purdie return 0; 30140e0aa64SRichard Purdie } 30240e0aa64SRichard Purdie 303b36d61d4SFrank Mandarino static int wm8731_hw_params(struct snd_pcm_substream *substream, 304dee89c4dSMark Brown struct snd_pcm_hw_params *params, 305dee89c4dSMark Brown struct snd_soc_dai *dai) 30640e0aa64SRichard Purdie { 307f0fba2adSLiam Girdwood struct snd_soc_codec *codec = dai->codec; 308b2c812e2SMark Brown struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 30917a52fd6SMark Brown u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3; 310b36d61d4SFrank Mandarino int i = get_coeff(wm8731->sysclk, params_rate(params)); 311b36d61d4SFrank Mandarino u16 srate = (coeff_div[i].sr << 2) | 312b36d61d4SFrank Mandarino (coeff_div[i].bosr << 1) | coeff_div[i].usb; 31340e0aa64SRichard Purdie 314dd31b310SMark Brown wm8731->playback_fs = params_rate(params); 315dd31b310SMark Brown 31617a52fd6SMark Brown snd_soc_write(codec, WM8731_SRATE, srate); 31740e0aa64SRichard Purdie 318b36d61d4SFrank Mandarino /* bit size */ 319b36d61d4SFrank Mandarino switch (params_format(params)) { 320b36d61d4SFrank Mandarino case SNDRV_PCM_FORMAT_S16_LE: 321b36d61d4SFrank Mandarino break; 322b36d61d4SFrank Mandarino case SNDRV_PCM_FORMAT_S20_3LE: 323b36d61d4SFrank Mandarino iface |= 0x0004; 324b36d61d4SFrank Mandarino break; 325b36d61d4SFrank Mandarino case SNDRV_PCM_FORMAT_S24_LE: 326b36d61d4SFrank Mandarino iface |= 0x0008; 327b36d61d4SFrank Mandarino break; 328b36d61d4SFrank Mandarino } 329b36d61d4SFrank Mandarino 330dd31b310SMark Brown wm8731_set_deemph(codec); 331dd31b310SMark Brown 33217a52fd6SMark Brown snd_soc_write(codec, WM8731_IFACE, iface); 333b36d61d4SFrank Mandarino return 0; 33440e0aa64SRichard Purdie } 33540e0aa64SRichard Purdie 336e550e17fSLiam Girdwood static int wm8731_mute(struct snd_soc_dai *dai, int mute) 33740e0aa64SRichard Purdie { 338b36d61d4SFrank Mandarino struct snd_soc_codec *codec = dai->codec; 33917a52fd6SMark Brown u16 mute_reg = snd_soc_read(codec, WM8731_APDIGI) & 0xfff7; 340b36d61d4SFrank Mandarino 34140e0aa64SRichard Purdie if (mute) 34217a52fd6SMark Brown snd_soc_write(codec, WM8731_APDIGI, mute_reg | 0x8); 34340e0aa64SRichard Purdie else 34417a52fd6SMark Brown snd_soc_write(codec, WM8731_APDIGI, mute_reg); 34540e0aa64SRichard Purdie return 0; 34640e0aa64SRichard Purdie } 34740e0aa64SRichard Purdie 348e550e17fSLiam Girdwood static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, 349b36d61d4SFrank Mandarino int clk_id, unsigned int freq, int dir) 350b36d61d4SFrank Mandarino { 351b36d61d4SFrank Mandarino struct snd_soc_codec *codec = codec_dai->codec; 352b2c812e2SMark Brown struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 353b36d61d4SFrank Mandarino 3549745e824SMark Brown switch (clk_id) { 3559745e824SMark Brown case WM8731_SYSCLK_XTAL: 3569745e824SMark Brown case WM8731_SYSCLK_MCLK: 3579745e824SMark Brown wm8731->sysclk_type = clk_id; 3589745e824SMark Brown break; 3599745e824SMark Brown default: 3609745e824SMark Brown return -EINVAL; 3619745e824SMark Brown } 3629745e824SMark Brown 363b36d61d4SFrank Mandarino switch (freq) { 364b36d61d4SFrank Mandarino case 11289600: 365b36d61d4SFrank Mandarino case 12000000: 366b36d61d4SFrank Mandarino case 12288000: 367b36d61d4SFrank Mandarino case 16934400: 368b36d61d4SFrank Mandarino case 18432000: 369b36d61d4SFrank Mandarino wm8731->sysclk = freq; 3709745e824SMark Brown break; 3719745e824SMark Brown default: 372b36d61d4SFrank Mandarino return -EINVAL; 373b36d61d4SFrank Mandarino } 374b36d61d4SFrank Mandarino 375ce6120ccSLiam Girdwood snd_soc_dapm_sync(&codec->dapm); 3769745e824SMark Brown 3779745e824SMark Brown return 0; 3789745e824SMark Brown } 3799745e824SMark Brown 380b36d61d4SFrank Mandarino 381e550e17fSLiam Girdwood static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, 382b36d61d4SFrank Mandarino unsigned int fmt) 383b36d61d4SFrank Mandarino { 384b36d61d4SFrank Mandarino struct snd_soc_codec *codec = codec_dai->codec; 385b36d61d4SFrank Mandarino u16 iface = 0; 386b36d61d4SFrank Mandarino 387b36d61d4SFrank Mandarino /* set master/slave audio interface */ 388b36d61d4SFrank Mandarino switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 389b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_CBM_CFM: 390b36d61d4SFrank Mandarino iface |= 0x0040; 391b36d61d4SFrank Mandarino break; 392b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_CBS_CFS: 393b36d61d4SFrank Mandarino break; 394b36d61d4SFrank Mandarino default: 395b36d61d4SFrank Mandarino return -EINVAL; 396b36d61d4SFrank Mandarino } 397b36d61d4SFrank Mandarino 398b36d61d4SFrank Mandarino /* interface format */ 399b36d61d4SFrank Mandarino switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 400b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_I2S: 401b36d61d4SFrank Mandarino iface |= 0x0002; 402b36d61d4SFrank Mandarino break; 403b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_RIGHT_J: 404b36d61d4SFrank Mandarino break; 405b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_LEFT_J: 406b36d61d4SFrank Mandarino iface |= 0x0001; 407b36d61d4SFrank Mandarino break; 408b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_DSP_A: 409b36d61d4SFrank Mandarino iface |= 0x0003; 410b36d61d4SFrank Mandarino break; 411b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_DSP_B: 412b36d61d4SFrank Mandarino iface |= 0x0013; 413b36d61d4SFrank Mandarino break; 414b36d61d4SFrank Mandarino default: 415b36d61d4SFrank Mandarino return -EINVAL; 416b36d61d4SFrank Mandarino } 417b36d61d4SFrank Mandarino 418b36d61d4SFrank Mandarino /* clock inversion */ 419b36d61d4SFrank Mandarino switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 420b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_NB_NF: 421b36d61d4SFrank Mandarino break; 422b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_IB_IF: 423b36d61d4SFrank Mandarino iface |= 0x0090; 424b36d61d4SFrank Mandarino break; 425b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_IB_NF: 426b36d61d4SFrank Mandarino iface |= 0x0080; 427b36d61d4SFrank Mandarino break; 428b36d61d4SFrank Mandarino case SND_SOC_DAIFMT_NB_IF: 429b36d61d4SFrank Mandarino iface |= 0x0010; 430b36d61d4SFrank Mandarino break; 431b36d61d4SFrank Mandarino default: 432b36d61d4SFrank Mandarino return -EINVAL; 433b36d61d4SFrank Mandarino } 434b36d61d4SFrank Mandarino 435b36d61d4SFrank Mandarino /* set iface */ 43617a52fd6SMark Brown snd_soc_write(codec, WM8731_IFACE, iface); 437b36d61d4SFrank Mandarino return 0; 438b36d61d4SFrank Mandarino } 439b36d61d4SFrank Mandarino 4400be9898aSMark Brown static int wm8731_set_bias_level(struct snd_soc_codec *codec, 4410be9898aSMark Brown enum snd_soc_bias_level level) 44240e0aa64SRichard Purdie { 44306ae9988SMark Brown struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 4449bf311feSAxel Lin int ret; 44522d22ee5SMark Brown u16 reg; 44640e0aa64SRichard Purdie 4470be9898aSMark Brown switch (level) { 4480be9898aSMark Brown case SND_SOC_BIAS_ON: 44940e0aa64SRichard Purdie break; 4500be9898aSMark Brown case SND_SOC_BIAS_PREPARE: 45140e0aa64SRichard Purdie break; 4520be9898aSMark Brown case SND_SOC_BIAS_STANDBY: 453ce6120ccSLiam Girdwood if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { 45406ae9988SMark Brown ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), 45506ae9988SMark Brown wm8731->supplies); 45606ae9988SMark Brown if (ret != 0) 45706ae9988SMark Brown return ret; 45806ae9988SMark Brown 459*05d448e2SMark Brown regcache_sync(wm8731->regmap); 46006ae9988SMark Brown } 46106ae9988SMark Brown 46222d22ee5SMark Brown /* Clear PWROFF, gate CLKOUT, everything else as-is */ 46317a52fd6SMark Brown reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f; 46417a52fd6SMark Brown snd_soc_write(codec, WM8731_PWR, reg | 0x0040); 46540e0aa64SRichard Purdie break; 4660be9898aSMark Brown case SND_SOC_BIAS_OFF: 46717a52fd6SMark Brown snd_soc_write(codec, WM8731_PWR, 0xffff); 46806ae9988SMark Brown regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), 46906ae9988SMark Brown wm8731->supplies); 470*05d448e2SMark Brown regcache_mark_dirty(wm8731->regmap); 47140e0aa64SRichard Purdie break; 47240e0aa64SRichard Purdie } 473ce6120ccSLiam Girdwood codec->dapm.bias_level = level; 47440e0aa64SRichard Purdie return 0; 47540e0aa64SRichard Purdie } 47640e0aa64SRichard Purdie 477e135443eSBill Gatliff #define WM8731_RATES SNDRV_PCM_RATE_8000_96000 478b36d61d4SFrank Mandarino 479b36d61d4SFrank Mandarino #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 480b36d61d4SFrank Mandarino SNDRV_PCM_FMTBIT_S24_LE) 481b36d61d4SFrank Mandarino 48285e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8731_dai_ops = { 4836335d055SEric Miao .hw_params = wm8731_hw_params, 4846335d055SEric Miao .digital_mute = wm8731_mute, 4856335d055SEric Miao .set_sysclk = wm8731_set_dai_sysclk, 4866335d055SEric Miao .set_fmt = wm8731_set_dai_fmt, 4876335d055SEric Miao }; 4886335d055SEric Miao 489f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8731_dai = { 490f0fba2adSLiam Girdwood .name = "wm8731-hifi", 49140e0aa64SRichard Purdie .playback = { 49240e0aa64SRichard Purdie .stream_name = "Playback", 49340e0aa64SRichard Purdie .channels_min = 1, 49440e0aa64SRichard Purdie .channels_max = 2, 495b36d61d4SFrank Mandarino .rates = WM8731_RATES, 496b36d61d4SFrank Mandarino .formats = WM8731_FORMATS,}, 49740e0aa64SRichard Purdie .capture = { 49840e0aa64SRichard Purdie .stream_name = "Capture", 49940e0aa64SRichard Purdie .channels_min = 1, 50040e0aa64SRichard Purdie .channels_max = 2, 501b36d61d4SFrank Mandarino .rates = WM8731_RATES, 502b36d61d4SFrank Mandarino .formats = WM8731_FORMATS,}, 5036335d055SEric Miao .ops = &wm8731_dai_ops, 5044934482dSMark Brown .symmetric_rates = 1, 50540e0aa64SRichard Purdie }; 50640e0aa64SRichard Purdie 507b3b50b3fSMark Brown #ifdef CONFIG_PM 50884b315eeSLars-Peter Clausen static int wm8731_suspend(struct snd_soc_codec *codec) 50940e0aa64SRichard Purdie { 5100be9898aSMark Brown wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); 51106ae9988SMark Brown 51240e0aa64SRichard Purdie return 0; 51340e0aa64SRichard Purdie } 51440e0aa64SRichard Purdie 515f0fba2adSLiam Girdwood static int wm8731_resume(struct snd_soc_codec *codec) 51640e0aa64SRichard Purdie { 5170be9898aSMark Brown wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 5187dea7c01SMark Brown 51940e0aa64SRichard Purdie return 0; 52040e0aa64SRichard Purdie } 521b3b50b3fSMark Brown #else 522b3b50b3fSMark Brown #define wm8731_suspend NULL 523b3b50b3fSMark Brown #define wm8731_resume NULL 524b3b50b3fSMark Brown #endif 52540e0aa64SRichard Purdie 526f0fba2adSLiam Girdwood static int wm8731_probe(struct snd_soc_codec *codec) 52740e0aa64SRichard Purdie { 528f0fba2adSLiam Girdwood struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 529f0fba2adSLiam Girdwood int ret = 0, i; 53040e0aa64SRichard Purdie 531*05d448e2SMark Brown codec->control_data = wm8731->regmap; 532*05d448e2SMark Brown ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); 53317a52fd6SMark Brown if (ret < 0) { 53417a52fd6SMark Brown dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 535f0fba2adSLiam Girdwood return ret; 53617a52fd6SMark Brown } 53717a52fd6SMark Brown 5387dea7c01SMark Brown for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) 5397dea7c01SMark Brown wm8731->supplies[i].supply = wm8731_supply_names[i]; 5407dea7c01SMark Brown 5417dea7c01SMark Brown ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), 5427dea7c01SMark Brown wm8731->supplies); 5437dea7c01SMark Brown if (ret != 0) { 5447dea7c01SMark Brown dev_err(codec->dev, "Failed to request supplies: %d\n", ret); 545f0fba2adSLiam Girdwood return ret; 5467dea7c01SMark Brown } 5477dea7c01SMark Brown 5487dea7c01SMark Brown ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), 5497dea7c01SMark Brown wm8731->supplies); 5507dea7c01SMark Brown if (ret != 0) { 5517dea7c01SMark Brown dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 5527dea7c01SMark Brown goto err_regulator_get; 5537dea7c01SMark Brown } 5547dea7c01SMark Brown 555519cf2dfSMark Brown ret = wm8731_reset(codec); 556519cf2dfSMark Brown if (ret < 0) { 557fe5422fcSMark Brown dev_err(codec->dev, "Failed to issue reset: %d\n", ret); 5587dea7c01SMark Brown goto err_regulator_enable; 559519cf2dfSMark Brown } 560519cf2dfSMark Brown 5615998102bSMark Brown wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 5625998102bSMark Brown 5635998102bSMark Brown /* Latch the update bits */ 56417a52fd6SMark Brown snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0); 56517a52fd6SMark Brown snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0); 56617a52fd6SMark Brown snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0); 56717a52fd6SMark Brown snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0); 5685998102bSMark Brown 569ce3bdaa8SMark Brown /* Disable bypass path by default */ 5702062ea52SDimitris Papastamos snd_soc_update_bits(codec, WM8731_APANA, 0x8, 0); 571ce3bdaa8SMark Brown 57206ae9988SMark Brown /* Regulators will have been enabled by bias management */ 57306ae9988SMark Brown regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); 57406ae9988SMark Brown 575a8035c8fSMark Brown return 0; 576fe5422fcSMark Brown 5777dea7c01SMark Brown err_regulator_enable: 5787dea7c01SMark Brown regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); 5797dea7c01SMark Brown err_regulator_get: 5807dea7c01SMark Brown regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); 581f0fba2adSLiam Girdwood 582fe5422fcSMark Brown return ret; 583a8035c8fSMark Brown } 584a8035c8fSMark Brown 585f0fba2adSLiam Girdwood /* power down chip */ 586f0fba2adSLiam Girdwood static int wm8731_remove(struct snd_soc_codec *codec) 5875998102bSMark Brown { 588f0fba2adSLiam Girdwood struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 589f0fba2adSLiam Girdwood 590f0fba2adSLiam Girdwood wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); 591f0fba2adSLiam Girdwood 592f0fba2adSLiam Girdwood regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); 5937dea7c01SMark Brown regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); 594f0fba2adSLiam Girdwood 595f0fba2adSLiam Girdwood return 0; 5965998102bSMark Brown } 597a8035c8fSMark Brown 598f0fba2adSLiam Girdwood static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { 599f0fba2adSLiam Girdwood .probe = wm8731_probe, 600f0fba2adSLiam Girdwood .remove = wm8731_remove, 601f0fba2adSLiam Girdwood .suspend = wm8731_suspend, 602f0fba2adSLiam Girdwood .resume = wm8731_resume, 603f0fba2adSLiam Girdwood .set_bias_level = wm8731_set_bias_level, 6045e251aecSMark Brown .dapm_widgets = wm8731_dapm_widgets, 6055e251aecSMark Brown .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), 6065e251aecSMark Brown .dapm_routes = wm8731_intercon, 6075e251aecSMark Brown .num_dapm_routes = ARRAY_SIZE(wm8731_intercon), 608cb555318SMark Brown .controls = wm8731_snd_controls, 609cb555318SMark Brown .num_controls = ARRAY_SIZE(wm8731_snd_controls), 610f0fba2adSLiam Girdwood }; 611f0fba2adSLiam Girdwood 612a7f96e4dSMark Brown static const struct of_device_id wm8731_of_match[] = { 613a7f96e4dSMark Brown { .compatible = "wlf,wm8731", }, 614a7f96e4dSMark Brown { } 615a7f96e4dSMark Brown }; 616a7f96e4dSMark Brown 617a7f96e4dSMark Brown MODULE_DEVICE_TABLE(of, wm8731_of_match); 618a7f96e4dSMark Brown 619*05d448e2SMark Brown static const struct regmap_config wm8731_regmap = { 620*05d448e2SMark Brown .reg_bits = 7, 621*05d448e2SMark Brown .val_bits = 9, 622*05d448e2SMark Brown 623*05d448e2SMark Brown .max_register = WM8731_RESET, 624*05d448e2SMark Brown .volatile_reg = wm8731_volatile, 625*05d448e2SMark Brown .writeable_reg = wm8731_writeable, 626*05d448e2SMark Brown 627*05d448e2SMark Brown .cache_type = REGCACHE_RBTREE, 628*05d448e2SMark Brown .reg_defaults = wm8731_reg_defaults, 629*05d448e2SMark Brown .num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults), 630*05d448e2SMark Brown }; 631*05d448e2SMark Brown 6325998102bSMark Brown #if defined(CONFIG_SPI_MASTER) 6335998102bSMark Brown static int __devinit wm8731_spi_probe(struct spi_device *spi) 6345998102bSMark Brown { 6355998102bSMark Brown struct wm8731_priv *wm8731; 636f0fba2adSLiam Girdwood int ret; 6375998102bSMark Brown 6385998102bSMark Brown wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); 6395998102bSMark Brown if (wm8731 == NULL) 6405998102bSMark Brown return -ENOMEM; 6415998102bSMark Brown 642*05d448e2SMark Brown wm8731->regmap = regmap_init_spi(spi, &wm8731_regmap); 643*05d448e2SMark Brown if (IS_ERR(wm8731->regmap)) { 644*05d448e2SMark Brown ret = PTR_ERR(wm8731->regmap); 645*05d448e2SMark Brown dev_err(&spi->dev, "Failed to allocate register map: %d\n", 646*05d448e2SMark Brown ret); 647*05d448e2SMark Brown goto err; 648*05d448e2SMark Brown } 649*05d448e2SMark Brown 650f0fba2adSLiam Girdwood spi_set_drvdata(spi, wm8731); 6515998102bSMark Brown 652f0fba2adSLiam Girdwood ret = snd_soc_register_codec(&spi->dev, 653f0fba2adSLiam Girdwood &soc_codec_dev_wm8731, &wm8731_dai, 1); 654*05d448e2SMark Brown if (ret != 0) { 655*05d448e2SMark Brown dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret); 656*05d448e2SMark Brown goto err_regmap; 657*05d448e2SMark Brown } 658*05d448e2SMark Brown 659*05d448e2SMark Brown return 0; 660*05d448e2SMark Brown 661*05d448e2SMark Brown err_regmap: 662*05d448e2SMark Brown regmap_exit(wm8731->regmap); 663*05d448e2SMark Brown err: 664f0fba2adSLiam Girdwood kfree(wm8731); 665f0fba2adSLiam Girdwood return ret; 6665998102bSMark Brown } 6675998102bSMark Brown 6685998102bSMark Brown static int __devexit wm8731_spi_remove(struct spi_device *spi) 6695998102bSMark Brown { 670*05d448e2SMark Brown struct wm8731_priv *wm8731 = spi_get_drvdata(spi); 671*05d448e2SMark Brown 672f0fba2adSLiam Girdwood snd_soc_unregister_codec(&spi->dev); 673*05d448e2SMark Brown regmap_exit(wm8731->regmap); 674*05d448e2SMark Brown kfree(wm8731); 6755998102bSMark Brown return 0; 6765998102bSMark Brown } 6775998102bSMark Brown 6785998102bSMark Brown static struct spi_driver wm8731_spi_driver = { 6795998102bSMark Brown .driver = { 68099b59f3cSMark Brown .name = "wm8731", 6815998102bSMark Brown .owner = THIS_MODULE, 682a7f96e4dSMark Brown .of_match_table = wm8731_of_match, 6835998102bSMark Brown }, 6845998102bSMark Brown .probe = wm8731_spi_probe, 6855998102bSMark Brown .remove = __devexit_p(wm8731_spi_remove), 6865998102bSMark Brown }; 687a8035c8fSMark Brown #endif /* CONFIG_SPI_MASTER */ 688a8035c8fSMark Brown 689a8035c8fSMark Brown #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 690c6f29811SMark Brown static __devinit int wm8731_i2c_probe(struct i2c_client *i2c, 691a8035c8fSMark Brown const struct i2c_device_id *id) 692a8035c8fSMark Brown { 6935998102bSMark Brown struct wm8731_priv *wm8731; 694f0fba2adSLiam Girdwood int ret; 695a8035c8fSMark Brown 6965998102bSMark Brown wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); 6975998102bSMark Brown if (wm8731 == NULL) 6985998102bSMark Brown return -ENOMEM; 6995998102bSMark Brown 700*05d448e2SMark Brown wm8731->regmap = regmap_init_i2c(i2c, &wm8731_regmap); 701*05d448e2SMark Brown if (IS_ERR(wm8731->regmap)) { 702*05d448e2SMark Brown ret = PTR_ERR(wm8731->regmap); 703*05d448e2SMark Brown dev_err(&i2c->dev, "Failed to allocate register map: %d\n", 704*05d448e2SMark Brown ret); 705*05d448e2SMark Brown goto err; 706*05d448e2SMark Brown } 707*05d448e2SMark Brown 7085998102bSMark Brown i2c_set_clientdata(i2c, wm8731); 709a8035c8fSMark Brown 710f0fba2adSLiam Girdwood ret = snd_soc_register_codec(&i2c->dev, 711f0fba2adSLiam Girdwood &soc_codec_dev_wm8731, &wm8731_dai, 1); 712*05d448e2SMark Brown if (ret != 0) { 713*05d448e2SMark Brown dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); 714*05d448e2SMark Brown goto err_regmap; 715*05d448e2SMark Brown } 716*05d448e2SMark Brown 717*05d448e2SMark Brown return 0; 718*05d448e2SMark Brown 719*05d448e2SMark Brown err_regmap: 720*05d448e2SMark Brown regmap_exit(wm8731->regmap); 721*05d448e2SMark Brown err: 722f0fba2adSLiam Girdwood kfree(wm8731); 723f0fba2adSLiam Girdwood return ret; 724a8035c8fSMark Brown } 725a8035c8fSMark Brown 726c6f29811SMark Brown static __devexit int wm8731_i2c_remove(struct i2c_client *client) 727a8035c8fSMark Brown { 728*05d448e2SMark Brown struct wm8731_priv *wm8731 = i2c_get_clientdata(client); 729f0fba2adSLiam Girdwood snd_soc_unregister_codec(&client->dev); 730*05d448e2SMark Brown regmap_exit(wm8731->regmap); 731*05d448e2SMark Brown kfree(wm8731); 732a8035c8fSMark Brown return 0; 733a8035c8fSMark Brown } 734a8035c8fSMark Brown 735a8035c8fSMark Brown static const struct i2c_device_id wm8731_i2c_id[] = { 736a8035c8fSMark Brown { "wm8731", 0 }, 737a8035c8fSMark Brown { } 738a8035c8fSMark Brown }; 739a8035c8fSMark Brown MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); 740a8035c8fSMark Brown 741a8035c8fSMark Brown static struct i2c_driver wm8731_i2c_driver = { 742a8035c8fSMark Brown .driver = { 74399b59f3cSMark Brown .name = "wm8731", 744a8035c8fSMark Brown .owner = THIS_MODULE, 745a7f96e4dSMark Brown .of_match_table = wm8731_of_match, 746a8035c8fSMark Brown }, 747a8035c8fSMark Brown .probe = wm8731_i2c_probe, 748c6f29811SMark Brown .remove = __devexit_p(wm8731_i2c_remove), 749a8035c8fSMark Brown .id_table = wm8731_i2c_id, 750a8035c8fSMark Brown }; 751a8035c8fSMark Brown #endif 752a8035c8fSMark Brown 753c9b3a40fSTakashi Iwai static int __init wm8731_modinit(void) 75464089b84SMark Brown { 755f0fba2adSLiam Girdwood int ret = 0; 7565998102bSMark Brown #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 7575998102bSMark Brown ret = i2c_add_driver(&wm8731_i2c_driver); 7585998102bSMark Brown if (ret != 0) { 7595998102bSMark Brown printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n", 7605998102bSMark Brown ret); 7615998102bSMark Brown } 7625998102bSMark Brown #endif 7635998102bSMark Brown #if defined(CONFIG_SPI_MASTER) 7645998102bSMark Brown ret = spi_register_driver(&wm8731_spi_driver); 7655998102bSMark Brown if (ret != 0) { 7665998102bSMark Brown printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n", 7675998102bSMark Brown ret); 7685998102bSMark Brown } 7695998102bSMark Brown #endif 770f0fba2adSLiam Girdwood return ret; 77164089b84SMark Brown } 77264089b84SMark Brown module_init(wm8731_modinit); 77364089b84SMark Brown 77464089b84SMark Brown static void __exit wm8731_exit(void) 77564089b84SMark Brown { 7765998102bSMark Brown #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 7775998102bSMark Brown i2c_del_driver(&wm8731_i2c_driver); 7785998102bSMark Brown #endif 7795998102bSMark Brown #if defined(CONFIG_SPI_MASTER) 7805998102bSMark Brown spi_unregister_driver(&wm8731_spi_driver); 7815998102bSMark Brown #endif 78264089b84SMark Brown } 78364089b84SMark Brown module_exit(wm8731_exit); 78464089b84SMark Brown 78540e0aa64SRichard Purdie MODULE_DESCRIPTION("ASoC WM8731 driver"); 78640e0aa64SRichard Purdie MODULE_AUTHOR("Richard Purdie"); 78740e0aa64SRichard Purdie MODULE_LICENSE("GPL"); 788