diff options
author | Wallace Wang <r59996@freescale.com> | 2009-10-13 15:15:31 -0500 |
---|---|---|
committer | Alan Tull <r80115@freescale.com> | 2010-08-25 11:51:30 -0500 |
commit | 9e4e14c7eed692134bd4c76e1333acfc36752927 (patch) | |
tree | 8edf67a3eff8b1dc61adf8ba36f6dc116d9d6215 | |
parent | b23468da828e3cbbe73c26af081c98c7595240b5 (diff) |
soc: add wm8580 spi support
Add spi interface support to wm8580 codec.
Signed-off-by: Wallace Wang <r59996@freescale.com>
-rw-r--r-- | sound/soc/codecs/wm8580.c | 126 | ||||
-rw-r--r-- | sound/soc/codecs/wm8580.h | 9 |
2 files changed, 133 insertions, 2 deletions
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index c3571ee5c11b..6a0b6c23b6ce 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/spi/spi.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -163,6 +164,8 @@ #define WM8580_DAC_CONTROL5_MUTEALL 0x10 +#define WM8580_REG_DATA_LENGTH 9 + /* * wm8580 register cache * We can't read the WM8580 register space when we @@ -259,7 +262,6 @@ SOC_WM8580_OUT_DOUBLE_R_TLV("DAC3 Playback Volume", WM8580_DIGITAL_ATTENUATION_DACL3, WM8580_DIGITAL_ATTENUATION_DACR3, 0, 0xff, 0, dac_tlv), - SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0), SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0), SOC_SINGLE("DAC3 Deemphasis Switch", WM8580_DAC_CONTROL3, 2, 1, 0), @@ -463,7 +465,7 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); reg = snd_soc_read(codec, WM8580_PLLA4 + offset); - reg &= ~0x1b; + reg &= ~0x3b; reg |= pll_div.prescale | pll_div.postscale << 1 | pll_div.freqmode << 3; @@ -679,6 +681,33 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, return 0; } +static int wm8580_set_paif_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + unsigned int reg; + + switch (clk_id) { + case WM8580_BCLK_CLKDIV: + reg = wm8580_read(codec, WM8580_PAIF1) & + ~WM8580_AIF_BCLKSEL_MASK; + wm8580_write(codec, WM8580_PAIF1, reg | freq); + reg = wm8580_read(codec, WM8580_PAIF2) & + ~WM8580_AIF_BCLKSEL_MASK; + wm8580_write(codec, WM8580_PAIF2, reg | freq); + break; + case WM8580_LRCLK_CLKDIV: + reg = wm8580_read(codec, WM8580_PAIF1) & ~0x07; + wm8580_write(codec, WM8580_PAIF1, reg | freq); + break; + + default: + return -EINVAL; + } + + return 0; +} + static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) { struct snd_soc_codec *codec = codec_dai->codec; @@ -734,6 +763,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, static struct snd_soc_dai_ops wm8580_dai_ops_playback = { .hw_params = wm8580_paif_hw_params, .set_fmt = wm8580_set_paif_dai_fmt, + .set_sysclk = wm8580_set_paif_dai_sysclk, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, .digital_mute = wm8580_digital_mute, @@ -970,6 +1000,87 @@ static struct i2c_driver wm8580_i2c_driver = { }; #endif +#if defined(CONFIG_SPI) || defined(CONFIG_SPI_MODULE) + /*! + * This function is called to transfer data to WM8580 on SPI. + * + * @param spi the SPI slave device(WM8580) + * @param buf the pointer to the data buffer + * @param len the length of the data to be transferred + * + * @return Returns 0 on success -1 on failure. + */ +static inline int spi_rw(void *control_data, char *data, int length) +{ + struct spi_transfer t = { + .tx_buf = (const void *)data, + .rx_buf = (void *)data, + .len = length / 2, + .cs_change = 0, + .delay_usecs = 0, + }; + struct spi_message m; + u8 temp = data[0]; + data[0] = data[1]; + data[1] = temp; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + return spi_sync((struct spi_device *)control_data, &m); + +} + +/*! + * This function is called whenever the SPI slave device is detected. + * + * @param spi the SPI slave device + * + * @return Returns 0 on SUCCESS and error on FAILURE. + */ +static int __devinit wm8580_spi_probe(struct spi_device *spi) +{ + struct wm8580_priv *wm8580; + struct snd_soc_codec *codec; + + wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); + if (wm8580 == NULL) + return -ENOMEM; + + codec = &wm8580->codec; + + spi->bits_per_word = 16; + spi->mode = SPI_MODE_2; + + spi_setup(spi); + + spi_set_drvdata(spi, wm8580); + codec->hw_write = (hw_write_t) spi_rw; + codec->hw_read = (hw_read_t) spi_rw; + codec->control_data = spi; + + codec->dev = &spi->dev; + + return wm8580_register(wm8580); +} + +static int __devinit wm8580_spi_remove(struct spi_device *spi) +{ + struct wm8580_priv *wm8580 = spi_get_drvdata(spi); + wm8580_unregister(wm8580); + return 0; +} + +static struct spi_driver wm8580_spi_driver = { + .driver = { + .name = "wm8580_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm8580_spi_probe, + .remove = __devexit_p(wm8580_spi_remove), +}; +#endif + static int __init wm8580_modinit(void) { int ret; @@ -981,6 +1092,13 @@ static int __init wm8580_modinit(void) } #endif +#if defined(CONFIG_SPI) || defined(CONFIG_SPI_MODULE) + spi_register_driver(&wm8580_spi_driver); + if (ret != 0) { + pr_err("Failed to register WM8580 SPI driver: %d\n", ret); + } +#endif + return 0; } module_init(wm8580_modinit); @@ -990,6 +1108,10 @@ static void __exit wm8580_exit(void) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8580_i2c_driver); #endif + +#if defined(CONFIG_SPI) || defined(CONFIG_SPI_MODULE) + spi_unregister_driver(&wm8580_spi_driver); +#endif } module_exit(wm8580_exit); diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h index 0dfb5ddde6a2..0c51ede6b13b 100644 --- a/sound/soc/codecs/wm8580.h +++ b/sound/soc/codecs/wm8580.h @@ -28,6 +28,15 @@ #define WM8580_CLKSRC_OSC 4 #define WM8580_CLKSRC_NONE 5 +/*clock divider id's */ +#define WM8580_BCLK_CLKDIV 0 +#define WM8580_LRCLK_CLKDIV 1 + +struct wm8580_setup_data { + unsigned short spi; + unsigned short i2c_address; +}; + #define WM8580_DAI_PAIFRX 0 #define WM8580_DAI_PAIFTX 1 |