From 0c0cc7a98a782bcf6342db4ec515f8c8112690c3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 23 Aug 2016 14:50:04 +0100 Subject: asoc: sa11x0/assabet: use gpiod APIs for some gpios Signed-off-by: Russell King --- arch/arm/mach-sa1100/assabet.c | 19 +++++++++ arch/arm/mach-sa1100/clock.c | 2 + sound/soc/sa11x0/assabet.c | 92 +++++++++++++++++++++++++----------------- 3 files changed, 75 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 2a267122b4a1..84649207dbb9 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -438,6 +438,22 @@ static struct resource neponset_resources[] = { }; #endif +static struct gpiod_lookup_table assabet_uda1341_gpio_table = { + .dev_id = "uda134x-codec", + .table = { + GPIO_LOOKUP("assabet", 21, "qmute", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table assabet_audio_gpio_table = { + .dev_id = "assabet-asoc", + .table = { + GPIO_LOOKUP("assabet", 23, "spkr-shtdn", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct gpiod_lookup_table assabet_cf_gpio_table = { .dev_id = "sa11x0-pcmcia.1", .table = { @@ -543,6 +559,9 @@ static struct gpiod_lookup_table assabet_uart3_gpio_table = { static void __init assabet_init(void) { + gpiod_add_lookup_table(&assabet_uda1341_gpio_table); + gpiod_add_lookup_table(&assabet_audio_gpio_table); + /* * Ensure that the power supply is in "high power" mode. */ diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c index 9ced1c559eca..a104cfa4b123 100644 --- a/arch/arm/mach-sa1100/clock.c +++ b/arch/arm/mach-sa1100/clock.c @@ -124,6 +124,8 @@ int __init sa11xx_clk_init(void) clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.1"); clk_hw_register_clkdev(hw, NULL, "1800"); + clk_hw_register_clkdev(hw, NULL, "assabet-asoc"); + hw = clk_hw_register_mux(NULL, "tucr-mux", clk_tucr_parents, ARRAY_SIZE(clk_tucr_parents), 0, (void __iomem *)&TUCR, FShft(TUCR_TSEL), diff --git a/sound/soc/sa11x0/assabet.c b/sound/soc/sa11x0/assabet.c index 0e8bbb34ffb6..d6c9cbefc1f6 100644 --- a/sound/soc/sa11x0/assabet.c +++ b/sound/soc/sa11x0/assabet.c @@ -27,9 +27,10 @@ * requested sample rate; the UDA1341 driver will just fail the preparation. * We rely on userspace (at present) to ask for the correct sample rate. */ -#include +#include #include #include +#include #include #include @@ -46,6 +47,8 @@ struct assabet_card { struct snd_soc_card card; + struct clk *clk_cpu; + struct gpio_desc *gpio_spkr_shtdn; }; #define GPIO_TXD 10 @@ -81,7 +84,7 @@ static void assabet_asoc_uda1341_power(int on) * Enable the power for the UDA1341 before fixing WS. * Also assert the mute signal. */ - ASSABET_BCR_set(ASSABET_BCR_AUDIO_ON | ASSABET_BCR_QMUTE); + ASSABET_BCR_set(ASSABET_BCR_AUDIO_ON); /* * Toggle SFRM with the codec reset signal held active. @@ -109,9 +112,6 @@ static void assabet_asoc_uda1341_power(int on) /* Finally, disable the audio power */ ASSABET_BCR_clear(ASSABET_BCR_AUDIO_ON); - - /* And lower the QMUTE signal to stop power draining */ - ASSABET_BCR_clear(ASSABET_BCR_QMUTE); } } @@ -155,11 +155,30 @@ static int assabet_asoc_resume_pre(struct snd_soc_card *card) return 0; } +/* + * Calculate the sysclk, which is the codec input clock. This is supplied + * from the SDRAM bank 2 clock, divided by 18 by the CPLD. This is then + * further divided by four by the CPLD, and supplied to the SA1110 GPIO19 + * to synchronously drive the SSP block. + * + * Ideally, we would lock cpufreq against any transitions which would upset + * the sample rate, or have userspace renegotiate the sample rate, but let's + * keep this simple. + * + * We intentionally lose some precision here to avoid the codec bombing out + * as it claims to only do standard rates. + */ +static unsigned int assabet_asoc_get_sysclk(struct assabet_card *ac) +{ + return (clk_get_rate(ac->clk_cpu) / 18000) * 1000; +} + static int assabet_asoc_rate_constraint(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { + struct assabet_card *ac = rule->private; struct snd_interval range, *p = hw_param_interval(params, rule->var); - unsigned int sysclk = (cpufreq_get(0) / 18) * 1000; + unsigned int sysclk = assabet_asoc_get_sysclk(ac); snd_interval_any(&range); range.min = UINT_MAX; @@ -180,12 +199,17 @@ assabet_asoc_rate_constraint(struct snd_pcm_hw_params *params, struct snd_pcm_hw static int assabet_asoc_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct assabet_card *ac = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret; if (!cpu_dai->active) { unsigned long flags; unsigned int sysclk; - int ret; + + ret = clk_prepare_enable(ac->clk_cpu); + if (ret) + return ret; /* * Hand the SFRM signal over to the SSP block as it is @@ -198,53 +222,36 @@ static int assabet_asoc_startup(struct snd_pcm_substream *substream) assabet_asoc_init_clk(); local_irq_restore(flags); - /* - * Calculate the sysclk, which is the codec input clock. - * This is supplied from the SDRAM bank 2 clock, divided by - * 18 by the CPLD. This is then further divided by four by - * the CPLD, and supplied to the SA1110 GPIO19 to - * synchronously drive the SSP block. - * - * Ideally, we would lock cpufreq against any transitions - * which would upset the sample rate, or have userspace - * renegotiate the sample rate, but let's keep this simple. - * - * We intentionally lose some precision here to avoid the - * codec bombing out as it claims to only do standard rates. - */ - sysclk = (cpufreq_get(0) / 18) * 1000; + sysclk = assabet_asoc_get_sysclk(ac); ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0, sysclk, SND_SOC_CLOCK_IN); if (ret < 0) - return ret; + goto err; ret = snd_soc_dai_set_sysclk(cpu_dai, SA11X0_SSP_CLK_EXT, sysclk / 4, SND_SOC_CLOCK_IN); if (ret < 0) - return ret; + goto err; } - /* Release the mute */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ASSABET_BCR_clear(ASSABET_BCR_QMUTE); - snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - assabet_asoc_rate_constraint, NULL, + assabet_asoc_rate_constraint, ac, SNDRV_PCM_HW_PARAM_RATE, -1); return 0; + +err: + clk_disable_unprepare(ac->clk_cpu); + return ret; } static void assabet_asoc_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct assabet_card *ac = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - /* Apply the output mute */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ASSABET_BCR_set(ASSABET_BCR_QMUTE); - if (!cpu_dai->active) { unsigned long flags; @@ -255,6 +262,8 @@ static void assabet_asoc_shutdown(struct snd_pcm_substream *substream) local_irq_save(flags); GAFR &= ~GPIO_SSP_SFRM; local_irq_restore(flags); + + clk_disable_unprepare(ac->clk_cpu); } } @@ -279,10 +288,9 @@ static int assabet_pwramp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - if (SND_SOC_DAPM_EVENT_ON(event)) - ASSABET_BCR_clear(ASSABET_BCR_SPK_OFF); - else - ASSABET_BCR_set(ASSABET_BCR_SPK_OFF); + struct assabet_card *ac = snd_soc_card_get_drvdata(w->dapm->card); + + gpiod_set_value(ac->gpio_spkr_shtdn, !SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -381,6 +389,15 @@ static int assabet_asoc_probe(struct platform_device *pdev) memcpy(&ac->card, &snd_soc_assabet, sizeof(ac->card)); ac->card.dev = &pdev->dev; + ac->clk_cpu = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ac->clk_cpu)) + return PTR_ERR(ac->clk_cpu); + + ac->gpio_spkr_shtdn = devm_gpiod_get(&pdev->dev, "spkr-shtdn", + GPIOD_OUT_HIGH); + if (IS_ERR(ac->gpio_spkr_shtdn)) + return PTR_ERR(ac->gpio_spkr_shtdn); + snd_soc_card_set_drvdata(&ac->card, ac); return snd_soc_register_card(&ac->card); @@ -434,7 +451,6 @@ static int assabet_init(void) * and it defaults to logic 1. So, first release the reset, * and then toggle the SFRM signal to set LRCK to zero. */ - ASSABET_BCR_set(ASSABET_BCR_SPK_OFF); ASSABET_BCR_clear(ASSABET_BCR_STEREO_LB); assabet_uda1341_reset(0); -- cgit