summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWallace Wang <r59996@freescale.com>2009-10-13 15:15:31 -0500
committerAlan Tull <r80115@freescale.com>2010-08-25 11:51:30 -0500
commit9e4e14c7eed692134bd4c76e1333acfc36752927 (patch)
tree8edf67a3eff8b1dc61adf8ba36f6dc116d9d6215
parentb23468da828e3cbbe73c26af081c98c7595240b5 (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.c126
-rw-r--r--sound/soc/codecs/wm8580.h9
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