diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-09-22 18:47:58 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-09-22 18:47:58 -0400 |
commit | 2ef39e606bb43d6041b6d820e2a9156110a82d21 (patch) | |
tree | 7c4cb8bd147d962344d357569172dfbe35f098a6 /sound/soc/ux500 | |
parent | a89be93c28cd656d1c3c49fe627666b3bbecd45a (diff) | |
parent | b4cad7af6665743647f28119b689e1552326d4da (diff) | |
download | linux-2ef39e606bb43d6041b6d820e2a9156110a82d21.tar.bz2 |
Merge remote-tracking branch 'asoc/topic/ux500' into for-3.7
Diffstat (limited to 'sound/soc/ux500')
-rw-r--r-- | sound/soc/ux500/mop500.c | 47 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_dai.c | 6 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_i2s.c | 89 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_i2s.h | 8 |
4 files changed, 124 insertions, 26 deletions
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 772cb19d2fb3..be94bf9bf94f 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -833,10 +833,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 1b7c2f58ce13..b7c996e77570 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,20 +684,33 @@ 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 (!msp) return -ENOMEM; + 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; @@ -715,6 +747,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 { |