summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 18:28:06 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 18:28:06 -0700
commit2a2bf85f05e42b12ea6bfe821e2d19221cf93555 (patch)
tree11abcdaef6e4f8307574056998d306d21558b6ed /sound
parent11801e9de26992d37cb869cc74f389b6a7677e0e (diff)
parent99261fbad0a16f105b262d7525801697588ba526 (diff)
downloadlinux-2a2bf85f05e42b12ea6bfe821e2d19221cf93555.tar.bz2
Merge tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM soc device tree updates from Olof Johansson: "Device tree conversion and enablement branch. Mostly a bunch of new bindings and setup for various platforms, but the Via/Winchip VT8500 platform is also converted over from being 100% legacy to now use device tree for probing. More of that will come for 3.8." Trivial conflicts due to removal of vt8500 files, and one documentation file that was added with slightly different contents both here and in the USb tree. * tag 'dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (212 commits) arm: vt8500: Fixup for missing gpio.h ARM: LPC32xx: LED fix in PHY3250 DTS file ARM: dt: mmp-dma: add binding file arm: vt8500: Update arch-vt8500 to devicetree support. arm: vt8500: gpio: Devicetree support for arch-vt8500 arm: vt8500: doc: Add device tree bindings for arch-vt8500 devices arm: vt8500: clk: Add Common Clock Framework support video: vt8500: Add devicetree support for vt8500-fb and wm8505-fb serial: vt8500: Add devicetree support for vt8500-serial rtc: vt8500: Add devicetree support for vt8500-rtc arm: vt8500: Add device tree files for VIA/Wondermedia SoC's ARM: tegra: Add Avionic Design Tamonten Evaluation Carrier support ARM: tegra: Add Avionic Design Medcom-Wide support ARM: tegra: Add Avionic Design Plutux support ARM: tegra: Add Avionic Design Tamonten support ARM: tegra: dts: Add pwm label ARM: ux500: Fix SSP register address format ARM: ux500: Apply tc3589x's GPIO/IRQ properties to HREF's DT ARM: ux500: Remove redundant #gpio-cell properties from Snowball DT ARM: ux500: Add all encompassing sound node to the HREF Device Tree ...
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/ab8500-codec.c81
-rw-r--r--sound/soc/ux500/mop500.c47
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c6
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.c89
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.h8
5 files changed, 205 insertions, 26 deletions
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 23b40186f9b8..07abd09e0b1d 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -34,6 +34,7 @@
#include <linux/mfd/abx500/ab8500-sysctrl.h>
#include <linux/mfd/abx500/ab8500-codec.h>
#include <linux/regulator/consumer.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -2394,9 +2395,65 @@ struct snd_soc_dai_driver ab8500_codec_dai[] = {
}
};
+static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
+ struct ab8500_codec_platform_data *codec)
+{
+ u32 value;
+
+ if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL))
+ codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED;
+ else
+ codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL;
+
+ if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL))
+ codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED;
+ else
+ codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL;
+
+ /* Has a non-standard Vamic been requested? */
+ if (of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL))
+ codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2;
+ else
+ codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1;
+
+ if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL))
+ codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2;
+ else
+ codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1;
+
+ if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL))
+ codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1;
+ else
+ codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2;
+
+ if (!of_property_read_u32(np, "stericsson,earpeice-cmv", &value)) {
+ switch (value) {
+ case 950 :
+ codec->ear_cmv = EAR_CMV_0_95V;
+ break;
+ case 1100 :
+ codec->ear_cmv = EAR_CMV_1_10V;
+ break;
+ case 1270 :
+ codec->ear_cmv = EAR_CMV_1_27V;
+ break;
+ case 1580 :
+ codec->ear_cmv = EAR_CMV_1_58V;
+ break;
+ default :
+ codec->ear_cmv = EAR_CMV_UNKNOWN;
+ dev_err(dev, "Unsuitable earpiece voltage found in DT\n");
+ }
+ } else {
+ dev_warn(dev, "No earpiece voltage found in DT - using default\n");
+ codec->ear_cmv = EAR_CMV_0_95V;
+ }
+}
+
static int ab8500_codec_probe(struct snd_soc_codec *codec)
{
struct device *dev = codec->dev;
+ struct device_node *np = dev->of_node;
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
struct ab8500_platform_data *pdata;
struct filter_control *fc;
@@ -2410,6 +2467,30 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
/* Inform SoC Core that we have our own I/O arrangements. */
codec->control_data = (void *)true;
+ if (np) {
+ if (!pdata)
+ pdata = devm_kzalloc(dev,
+ sizeof(struct ab8500_platform_data),
+ GFP_KERNEL);
+
+ if (pdata && !pdata->codec)
+ pdata->codec
+ = devm_kzalloc(dev,
+ sizeof(struct ab8500_codec_platform_data),
+ GFP_KERNEL);
+
+ if (!(pdata && pdata->codec))
+ return -ENOMEM;
+
+ ab8500_codec_of_probe(dev, np, pdata->codec);
+
+ } else {
+ if (!(pdata && pdata->codec)) {
+ dev_err(dev, "No codec platform data or DT found\n");
+ return -EINVAL;
+ }
+ }
+
status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
if (status < 0) {
pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index 31c4d26d0359..356611d9654d 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
+#include <linux/of.h>
#include <sound/soc.h>
#include <sound/initval.h>
@@ -56,16 +57,47 @@ static struct snd_soc_card mop500_card = {
.num_links = ARRAY_SIZE(mop500_dai_links),
};
+static int __devinit mop500_of_probe(struct platform_device *pdev,
+ struct device_node *np)
+{
+ struct device_node *codec_np, *msp_np[2];
+ int i;
+
+ msp_np[0] = of_parse_phandle(np, "stericsson,cpu-dai", 0);
+ msp_np[1] = of_parse_phandle(np, "stericsson,cpu-dai", 1);
+ codec_np = of_parse_phandle(np, "stericsson,audio-codec", 0);
+
+ if (!(msp_np[0] && msp_np[1] && codec_np)) {
+ dev_err(&pdev->dev, "Phandle missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 2; i++) {
+ mop500_dai_links[i].cpu_of_node = msp_np[i];
+ mop500_dai_links[i].cpu_dai_name = NULL;
+ mop500_dai_links[i].codec_of_node = codec_np;
+ mop500_dai_links[i].codec_name = NULL;
+ }
+
+ snd_soc_of_parse_card_name(&mop500_card, "stericsson,card-name");
+
+ return 0;
+}
static int __devinit mop500_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
int ret;
- pr_debug("%s: Enter.\n", __func__);
-
dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
mop500_card.dev = &pdev->dev;
+ if (np) {
+ ret = mop500_of_probe(pdev, np);
+ if (ret)
+ return ret;
+ }
+
dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n",
__func__, mop500_card.name);
platform_set_drvdata(pdev, &mop500_card);
@@ -83,8 +115,7 @@ static int __devinit mop500_probe(struct platform_device *pdev)
ret = snd_soc_register_card(&mop500_card);
if (ret)
dev_err(&pdev->dev,
- "Error: snd_soc_register_card failed (%d)!\n",
- ret);
+ "Error: snd_soc_register_card failed (%d)!\n", ret);
return ret;
}
@@ -97,14 +128,20 @@ static int __devexit mop500_remove(struct platform_device *pdev)
snd_soc_unregister_card(mop500_card);
mop500_ab8500_remove(mop500_card);
-
+
return 0;
}
+static const struct of_device_id snd_soc_mop500_match[] = {
+ { .compatible = "stericsson,snd-soc-mop500", },
+ {},
+};
+
static struct platform_driver snd_soc_mop500_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "snd-soc-mop500",
+ .of_match_table = snd_soc_mop500_match,
},
.probe = mop500_probe,
.remove = __devexit_p(mop500_remove),
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 057e28ef770e..45e43b4057b0 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -830,10 +830,16 @@ static int __devexit ux500_msp_drv_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id ux500_msp_i2s_match[] = {
+ { .compatible = "stericsson,ux500-msp-i2s", },
+ {},
+};
+
static struct platform_driver msp_i2s_driver = {
.driver = {
.name = "ux500-msp-i2s",
.owner = THIS_MODULE,
+ .of_match_table = ux500_msp_i2s_match,
},
.probe = ux500_msp_drv_probe,
.remove = ux500_msp_drv_remove,
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
index eb85113d472a..e5c79ca42518 100644
--- a/sound/soc/ux500/ux500_msp_i2s.c
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -15,8 +15,10 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <mach/hardware.h>
#include <mach/msp.h>
@@ -25,6 +27,9 @@
#include "ux500_msp_i2s.h"
+/* MSP1/3 Tx/Rx usage protection */
+static DEFINE_SPINLOCK(msp_rxtx_lock);
+
/* Protocol desciptors */
static const struct msp_protdesc prot_descs[] = {
{ /* I2S */
@@ -352,17 +357,23 @@ static int configure_multichannel(struct ux500_msp *msp,
static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
{
- int status = 0;
+ int status = 0, retval = 0;
u32 reg_val_DMACR, reg_val_GCR;
+ unsigned long flags;
/* Check msp state whether in RUN or CONFIGURED Mode */
- if ((msp->msp_state == MSP_STATE_IDLE) && (msp->plat_init)) {
- status = msp->plat_init();
- if (status) {
- dev_err(msp->dev, "%s: ERROR: Failed to init MSP (%d)!\n",
- __func__, status);
- return status;
+ if (msp->msp_state == MSP_STATE_IDLE) {
+ spin_lock_irqsave(&msp_rxtx_lock, flags);
+ if (msp->pinctrl_rxtx_ref == 0 &&
+ !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_def))) {
+ retval = pinctrl_select_state(msp->pinctrl_p,
+ msp->pinctrl_def);
+ if (retval)
+ pr_err("could not set MSP defstate\n");
}
+ if (!retval)
+ msp->pinctrl_rxtx_ref++;
+ spin_unlock_irqrestore(&msp_rxtx_lock, flags);
}
/* Configure msp with protocol dependent settings */
@@ -620,7 +631,8 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
{
- int status = 0;
+ int status = 0, retval = 0;
+ unsigned long flags;
dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
@@ -631,12 +643,19 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
writel((readl(msp->registers + MSP_GCR) &
(~(FRAME_GEN_ENABLE | SRG_ENABLE))),
msp->registers + MSP_GCR);
- if (msp->plat_exit)
- status = msp->plat_exit();
- if (status)
- dev_warn(msp->dev,
- "%s: WARN: ux500_msp_i2s_exit failed (%d)!\n",
- __func__, status);
+
+ spin_lock_irqsave(&msp_rxtx_lock, flags);
+ WARN_ON(!msp->pinctrl_rxtx_ref);
+ msp->pinctrl_rxtx_ref--;
+ if (msp->pinctrl_rxtx_ref == 0 &&
+ !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_sleep))) {
+ retval = pinctrl_select_state(msp->pinctrl_p,
+ msp->pinctrl_sleep);
+ if (retval)
+ pr_err("could not set MSP sleepstate\n");
+ }
+ spin_unlock_irqrestore(&msp_rxtx_lock, flags);
+
writel(0, msp->registers + MSP_GCR);
writel(0, msp->registers + MSP_TCF);
writel(0, msp->registers + MSP_RCF);
@@ -665,18 +684,31 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
{
struct resource *res = NULL;
struct i2s_controller *i2s_cont;
+ struct device_node *np = pdev->dev.of_node;
struct ux500_msp *msp;
- dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
- pdev->name, platform_data->id);
-
*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
msp = *msp_p;
+ if (np) {
+ if (!platform_data) {
+ platform_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct msp_i2s_platform_data), GFP_KERNEL);
+ if (!platform_data)
+ ret = -ENOMEM;
+ }
+ } else
+ if (!platform_data)
+ ret = -EINVAL;
+
+ if (ret)
+ goto err_res;
+
+ dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
+ pdev->name, platform_data->id);
+
msp->id = platform_data->id;
msp->dev = &pdev->dev;
- msp->plat_init = platform_data->msp_i2s_init;
- msp->plat_exit = platform_data->msp_i2s_exit;
msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
@@ -713,6 +745,25 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
msp->i2s_cont = i2s_cont;
+ msp->pinctrl_p = pinctrl_get(msp->dev);
+ if (IS_ERR(msp->pinctrl_p))
+ dev_err(&pdev->dev, "could not get MSP pinctrl\n");
+ else {
+ msp->pinctrl_def = pinctrl_lookup_state(msp->pinctrl_p,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(msp->pinctrl_def)) {
+ dev_err(&pdev->dev,
+ "could not get MSP defstate (%li)\n",
+ PTR_ERR(msp->pinctrl_def));
+ }
+ msp->pinctrl_sleep = pinctrl_lookup_state(msp->pinctrl_p,
+ PINCTRL_STATE_SLEEP);
+ if (IS_ERR(msp->pinctrl_sleep))
+ dev_err(&pdev->dev,
+ "could not get MSP idlestate (%li)\n",
+ PTR_ERR(msp->pinctrl_def));
+ }
+
return 0;
}
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
index 2d9136da9865..1311c0df7628 100644
--- a/sound/soc/ux500/ux500_msp_i2s.h
+++ b/sound/soc/ux500/ux500_msp_i2s.h
@@ -524,14 +524,18 @@ struct ux500_msp {
struct dma_chan *rx_pipeid;
enum msp_state msp_state;
int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
- int (*plat_init) (void);
- int (*plat_exit) (void);
struct timer_list notify_timer;
int def_elem_len;
unsigned int dir_busy;
int loopback_enable;
u32 backup_regs[MAX_MSP_BACKUP_REGS];
unsigned int f_bitclk;
+ /* Pin modes */
+ struct pinctrl *pinctrl_p;
+ struct pinctrl_state *pinctrl_def;
+ struct pinctrl_state *pinctrl_sleep;
+ /* Reference Count */
+ int pinctrl_rxtx_ref;
};
struct ux500_msp_dma_params {