1 // SPDX-License-Identifier: GPL-2.0
3 // Socionext UniPhier AIO ALSA CPU DAI driver.
5 // Copyright (c) 2016-2018 Socionext Inc.
8 #include <linux/errno.h>
9 #include <linux/kernel.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/module.h>
13 #include <linux/of_platform.h>
14 #include <linux/platform_device.h>
15 #include <linux/reset.h>
16 #include <sound/core.h>
17 #include <sound/pcm.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
23 static bool is_valid_pll(struct uniphier_aio_chip
*chip
, int pll_id
)
25 struct device
*dev
= &chip
->pdev
->dev
;
27 if (pll_id
< 0 || chip
->num_plls
<= pll_id
) {
28 dev_err(dev
, "PLL(%d) is not supported\n", pll_id
);
32 return chip
->plls
[pll_id
].enable
;
36 * find_volume - find volume supported HW port by HW port number
37 * @chip: the AIO chip pointer
38 * @oport_hw: HW port number, one of AUD_HW_XXXX
40 * Find AIO device from device list by HW port number. Volume feature is
41 * available only in Output and PCM ports, this limitation comes from HW
44 * Return: The pointer of AIO substream if successful, otherwise NULL on error.
46 static struct uniphier_aio_sub
*find_volume(struct uniphier_aio_chip
*chip
,
51 for (i
= 0; i
< chip
->num_aios
; i
++) {
52 struct uniphier_aio_sub
*sub
= &chip
->aios
[i
].sub
[0];
57 if (sub
->swm
->oport
.hw
== oport_hw
)
64 static bool match_spec(const struct uniphier_aio_spec
*spec
,
65 const char *name
, int dir
)
67 if (dir
== SNDRV_PCM_STREAM_PLAYBACK
&&
68 spec
->swm
.dir
!= PORT_DIR_OUTPUT
) {
72 if (dir
== SNDRV_PCM_STREAM_CAPTURE
&&
73 spec
->swm
.dir
!= PORT_DIR_INPUT
) {
77 if (spec
->name
&& strcmp(spec
->name
, name
) == 0)
80 if (spec
->gname
&& strcmp(spec
->gname
, name
) == 0)
87 * find_spec - find HW specification info by name
88 * @aio: the AIO device pointer
89 * @name: name of device
90 * @direction: the direction of substream, SNDRV_PCM_STREAM_*
92 * Find hardware specification information from list by device name. This
93 * information is used for telling the difference of SoCs to driver.
95 * Specification list is array of 'struct uniphier_aio_spec' which is defined
96 * in each drivers (see: aio-i2s.c).
98 * Return: The pointer of hardware specification of AIO if successful,
99 * otherwise NULL on error.
101 static const struct uniphier_aio_spec
*find_spec(struct uniphier_aio
*aio
,
105 const struct uniphier_aio_chip_spec
*chip_spec
= aio
->chip
->chip_spec
;
108 for (i
= 0; i
< chip_spec
->num_specs
; i
++) {
109 const struct uniphier_aio_spec
*spec
= &chip_spec
->specs
[i
];
111 if (match_spec(spec
, name
, direction
))
119 * find_divider - find clock divider by frequency
120 * @aio: the AIO device pointer
121 * @pll_id: PLL ID, should be AUD_PLL_XX
122 * @freq: required frequency
124 * Find suitable clock divider by frequency.
126 * Return: The ID of PLL if successful, otherwise negative error value.
128 static int find_divider(struct uniphier_aio
*aio
, int pll_id
, unsigned int freq
)
130 struct uniphier_aio_pll
*pll
;
131 int mul
[] = { 1, 1, 1, 2, };
132 int div
[] = { 2, 3, 1, 3, };
135 if (!is_valid_pll(aio
->chip
, pll_id
))
138 pll
= &aio
->chip
->plls
[pll_id
];
139 for (i
= 0; i
< ARRAY_SIZE(mul
); i
++)
140 if (pll
->freq
* mul
[i
] / div
[i
] == freq
)
146 static int uniphier_aio_set_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
147 unsigned int freq
, int dir
)
149 struct uniphier_aio
*aio
= uniphier_priv(dai
);
150 struct device
*dev
= &aio
->chip
->pdev
->dev
;
151 bool pll_auto
= false;
178 pll_id
= AUD_PLL_APLL
;
181 pll_id
= AUD_PLL_RX0
;
184 pll_id
= AUD_PLL_USB0
;
187 pll_id
= AUD_PLL_HSC0
;
190 dev_err(dev
, "Sysclk(%d) is not supported\n", clk_id
);
195 for (pll_id
= 0; pll_id
< aio
->chip
->num_plls
; pll_id
++) {
196 div_id
= find_divider(aio
, pll_id
, freq
);
198 aio
->plldiv
= div_id
;
202 if (pll_id
== aio
->chip
->num_plls
) {
203 dev_err(dev
, "Sysclk frequency is not supported(%d)\n",
209 if (dir
== SND_SOC_CLOCK_OUT
)
210 aio
->pll_out
= pll_id
;
212 aio
->pll_in
= pll_id
;
217 static int uniphier_aio_set_pll(struct snd_soc_dai
*dai
, int pll_id
,
218 int source
, unsigned int freq_in
,
219 unsigned int freq_out
)
221 struct uniphier_aio
*aio
= uniphier_priv(dai
);
222 struct device
*dev
= &aio
->chip
->pdev
->dev
;
225 if (!is_valid_pll(aio
->chip
, pll_id
))
227 if (!aio
->chip
->plls
[pll_id
].enable
) {
228 dev_err(dev
, "PLL(%d) is not implemented\n", pll_id
);
232 ret
= aio_chip_set_pll(aio
->chip
, pll_id
, freq_out
);
239 static int uniphier_aio_set_fmt(struct snd_soc_dai
*dai
, unsigned int fmt
)
241 struct uniphier_aio
*aio
= uniphier_priv(dai
);
242 struct device
*dev
= &aio
->chip
->pdev
->dev
;
244 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
245 case SND_SOC_DAIFMT_LEFT_J
:
246 case SND_SOC_DAIFMT_RIGHT_J
:
247 case SND_SOC_DAIFMT_I2S
:
248 aio
->fmt
= fmt
& SND_SOC_DAIFMT_FORMAT_MASK
;
251 dev_err(dev
, "Format is not supported(%d)\n",
252 fmt
& SND_SOC_DAIFMT_FORMAT_MASK
);
259 static int uniphier_aio_startup(struct snd_pcm_substream
*substream
,
260 struct snd_soc_dai
*dai
)
262 struct uniphier_aio
*aio
= uniphier_priv(dai
);
263 struct uniphier_aio_sub
*sub
= &aio
->sub
[substream
->stream
];
266 sub
->substream
= substream
;
267 sub
->pass_through
= 0;
268 sub
->use_mmap
= true;
277 static void uniphier_aio_shutdown(struct snd_pcm_substream
*substream
,
278 struct snd_soc_dai
*dai
)
280 struct uniphier_aio
*aio
= uniphier_priv(dai
);
281 struct uniphier_aio_sub
*sub
= &aio
->sub
[substream
->stream
];
283 sub
->substream
= NULL
;
286 static int uniphier_aio_hw_params(struct snd_pcm_substream
*substream
,
287 struct snd_pcm_hw_params
*params
,
288 struct snd_soc_dai
*dai
)
290 struct uniphier_aio
*aio
= uniphier_priv(dai
);
291 struct uniphier_aio_sub
*sub
= &aio
->sub
[substream
->stream
];
292 struct device
*dev
= &aio
->chip
->pdev
->dev
;
295 switch (params_rate(params
)) {
306 dev_err(dev
, "Rate is not supported(%d)\n",
307 params_rate(params
));
310 ret
= snd_soc_dai_set_sysclk(dai
, AUD_CLK_A
,
311 freq
, SND_SOC_CLOCK_OUT
);
315 sub
->params
= *params
;
319 aio_port_set_volume(sub
, sub
->vol
);
325 static int uniphier_aio_hw_free(struct snd_pcm_substream
*substream
,
326 struct snd_soc_dai
*dai
)
328 struct uniphier_aio
*aio
= uniphier_priv(dai
);
329 struct uniphier_aio_sub
*sub
= &aio
->sub
[substream
->stream
];
336 static int uniphier_aio_prepare(struct snd_pcm_substream
*substream
,
337 struct snd_soc_dai
*dai
)
339 struct uniphier_aio
*aio
= uniphier_priv(dai
);
340 struct uniphier_aio_sub
*sub
= &aio
->sub
[substream
->stream
];
343 ret
= aio_port_set_param(sub
, sub
->pass_through
, &sub
->params
);
346 ret
= aio_src_set_param(sub
, &sub
->params
);
349 aio_port_set_enable(sub
, 1);
351 ret
= aio_if_set_param(sub
, sub
->pass_through
);
355 if (sub
->swm
->type
== PORT_TYPE_CONV
) {
356 ret
= aio_srcif_set_param(sub
);
359 ret
= aio_srcch_set_param(sub
);
362 aio_srcch_set_enable(sub
, 1);
368 const struct snd_soc_dai_ops uniphier_aio_i2s_ops
= {
369 .set_sysclk
= uniphier_aio_set_sysclk
,
370 .set_pll
= uniphier_aio_set_pll
,
371 .set_fmt
= uniphier_aio_set_fmt
,
372 .startup
= uniphier_aio_startup
,
373 .shutdown
= uniphier_aio_shutdown
,
374 .hw_params
= uniphier_aio_hw_params
,
375 .hw_free
= uniphier_aio_hw_free
,
376 .prepare
= uniphier_aio_prepare
,
378 EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops
);
380 const struct snd_soc_dai_ops uniphier_aio_spdif_ops
= {
381 .set_sysclk
= uniphier_aio_set_sysclk
,
382 .set_pll
= uniphier_aio_set_pll
,
383 .startup
= uniphier_aio_startup
,
384 .shutdown
= uniphier_aio_shutdown
,
385 .hw_params
= uniphier_aio_hw_params
,
386 .hw_free
= uniphier_aio_hw_free
,
387 .prepare
= uniphier_aio_prepare
,
389 EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops
);
391 int uniphier_aio_dai_probe(struct snd_soc_dai
*dai
)
393 struct uniphier_aio
*aio
= uniphier_priv(dai
);
396 for (i
= 0; i
< ARRAY_SIZE(aio
->sub
); i
++) {
397 struct uniphier_aio_sub
*sub
= &aio
->sub
[i
];
398 const struct uniphier_aio_spec
*spec
;
400 spec
= find_spec(aio
, dai
->name
, i
);
404 sub
->swm
= &spec
->swm
;
407 sub
->vol
= AUD_VOL_INIT
;
410 aio_iecout_set_enable(aio
->chip
, true);
411 aio_chip_init(aio
->chip
);
412 aio
->chip
->active
= 1;
416 EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe
);
418 int uniphier_aio_dai_remove(struct snd_soc_dai
*dai
)
420 struct uniphier_aio
*aio
= uniphier_priv(dai
);
422 aio
->chip
->active
= 0;
426 EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove
);
428 int uniphier_aio_dai_suspend(struct snd_soc_dai
*dai
)
430 struct uniphier_aio
*aio
= uniphier_priv(dai
);
432 reset_control_assert(aio
->chip
->rst
);
433 clk_disable_unprepare(aio
->chip
->clk
);
437 EXPORT_SYMBOL_GPL(uniphier_aio_dai_suspend
);
439 int uniphier_aio_dai_resume(struct snd_soc_dai
*dai
)
441 struct uniphier_aio
*aio
= uniphier_priv(dai
);
444 if (!aio
->chip
->active
)
447 ret
= clk_prepare_enable(aio
->chip
->clk
);
451 ret
= reset_control_deassert(aio
->chip
->rst
);
455 aio_iecout_set_enable(aio
->chip
, true);
456 aio_chip_init(aio
->chip
);
458 for (i
= 0; i
< ARRAY_SIZE(aio
->sub
); i
++) {
459 struct uniphier_aio_sub
*sub
= &aio
->sub
[i
];
461 if (!sub
->spec
|| !sub
->substream
)
478 clk_disable_unprepare(aio
->chip
->clk
);
482 EXPORT_SYMBOL_GPL(uniphier_aio_dai_resume
);
484 static int uniphier_aio_vol_info(struct snd_kcontrol
*kcontrol
,
485 struct snd_ctl_elem_info
*uinfo
)
487 uinfo
->type
= SNDRV_CTL_ELEM_TYPE_INTEGER
;
489 uinfo
->value
.integer
.min
= 0;
490 uinfo
->value
.integer
.max
= AUD_VOL_MAX
;
495 static int uniphier_aio_vol_get(struct snd_kcontrol
*kcontrol
,
496 struct snd_ctl_elem_value
*ucontrol
)
498 struct snd_soc_component
*comp
= snd_soc_kcontrol_component(kcontrol
);
499 struct uniphier_aio_chip
*chip
= snd_soc_component_get_drvdata(comp
);
500 struct uniphier_aio_sub
*sub
;
501 int oport_hw
= kcontrol
->private_value
;
503 sub
= find_volume(chip
, oport_hw
);
507 ucontrol
->value
.integer
.value
[0] = sub
->vol
;
512 static int uniphier_aio_vol_put(struct snd_kcontrol
*kcontrol
,
513 struct snd_ctl_elem_value
*ucontrol
)
515 struct snd_soc_component
*comp
= snd_soc_kcontrol_component(kcontrol
);
516 struct uniphier_aio_chip
*chip
= snd_soc_component_get_drvdata(comp
);
517 struct uniphier_aio_sub
*sub
;
518 int oport_hw
= kcontrol
->private_value
;
520 sub
= find_volume(chip
, oport_hw
);
524 if (sub
->vol
== ucontrol
->value
.integer
.value
[0])
526 sub
->vol
= ucontrol
->value
.integer
.value
[0];
528 aio_port_set_volume(sub
, sub
->vol
);
533 static const struct snd_kcontrol_new uniphier_aio_controls
[] = {
535 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
536 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
537 .name
= "HPCMOUT1 Volume",
538 .info
= uniphier_aio_vol_info
,
539 .get
= uniphier_aio_vol_get
,
540 .put
= uniphier_aio_vol_put
,
541 .private_value
= AUD_HW_HPCMOUT1
,
544 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
545 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
546 .name
= "PCMOUT1 Volume",
547 .info
= uniphier_aio_vol_info
,
548 .get
= uniphier_aio_vol_get
,
549 .put
= uniphier_aio_vol_put
,
550 .private_value
= AUD_HW_PCMOUT1
,
553 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
554 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
555 .name
= "PCMOUT2 Volume",
556 .info
= uniphier_aio_vol_info
,
557 .get
= uniphier_aio_vol_get
,
558 .put
= uniphier_aio_vol_put
,
559 .private_value
= AUD_HW_PCMOUT2
,
562 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
563 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
564 .name
= "PCMOUT3 Volume",
565 .info
= uniphier_aio_vol_info
,
566 .get
= uniphier_aio_vol_get
,
567 .put
= uniphier_aio_vol_put
,
568 .private_value
= AUD_HW_PCMOUT3
,
571 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
572 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
573 .name
= "HIECOUT1 Volume",
574 .info
= uniphier_aio_vol_info
,
575 .get
= uniphier_aio_vol_get
,
576 .put
= uniphier_aio_vol_put
,
577 .private_value
= AUD_HW_HIECOUT1
,
580 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
581 .access
= SNDRV_CTL_ELEM_ACCESS_READWRITE
,
582 .name
= "IECOUT1 Volume",
583 .info
= uniphier_aio_vol_info
,
584 .get
= uniphier_aio_vol_get
,
585 .put
= uniphier_aio_vol_put
,
586 .private_value
= AUD_HW_IECOUT1
,
590 static const struct snd_soc_component_driver uniphier_aio_component
= {
591 .name
= "uniphier-aio",
592 .controls
= uniphier_aio_controls
,
593 .num_controls
= ARRAY_SIZE(uniphier_aio_controls
),
596 int uniphier_aio_probe(struct platform_device
*pdev
)
598 struct uniphier_aio_chip
*chip
;
599 struct device
*dev
= &pdev
->dev
;
602 chip
= devm_kzalloc(dev
, sizeof(*chip
), GFP_KERNEL
);
606 chip
->chip_spec
= of_device_get_match_data(dev
);
607 if (!chip
->chip_spec
)
610 chip
->regmap_sg
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
612 if (IS_ERR(chip
->regmap_sg
)) {
613 if (PTR_ERR(chip
->regmap_sg
) == -EPROBE_DEFER
)
614 return -EPROBE_DEFER
;
615 chip
->regmap_sg
= NULL
;
618 chip
->clk
= devm_clk_get(dev
, "aio");
619 if (IS_ERR(chip
->clk
))
620 return PTR_ERR(chip
->clk
);
622 chip
->rst
= devm_reset_control_get_shared(dev
, "aio");
623 if (IS_ERR(chip
->rst
))
624 return PTR_ERR(chip
->rst
);
626 chip
->num_aios
= chip
->chip_spec
->num_dais
;
627 chip
->aios
= devm_kcalloc(dev
,
628 chip
->num_aios
, sizeof(struct uniphier_aio
),
633 chip
->num_plls
= chip
->chip_spec
->num_plls
;
634 chip
->plls
= devm_kcalloc(dev
,
636 sizeof(struct uniphier_aio_pll
),
640 memcpy(chip
->plls
, chip
->chip_spec
->plls
,
641 sizeof(struct uniphier_aio_pll
) * chip
->num_plls
);
643 for (i
= 0; i
< chip
->num_aios
; i
++) {
644 struct uniphier_aio
*aio
= &chip
->aios
[i
];
647 aio
->fmt
= SND_SOC_DAIFMT_I2S
;
649 for (j
= 0; j
< ARRAY_SIZE(aio
->sub
); j
++) {
650 struct uniphier_aio_sub
*sub
= &aio
->sub
[j
];
653 spin_lock_init(&sub
->lock
);
658 platform_set_drvdata(pdev
, chip
);
660 ret
= clk_prepare_enable(chip
->clk
);
664 ret
= reset_control_deassert(chip
->rst
);
668 ret
= devm_snd_soc_register_component(dev
, &uniphier_aio_component
,
669 chip
->chip_spec
->dais
,
670 chip
->chip_spec
->num_dais
);
672 dev_err(dev
, "Register component failed.\n");
676 ret
= uniphier_aiodma_soc_register_platform(pdev
);
678 dev_err(dev
, "Register platform failed.\n");
685 reset_control_assert(chip
->rst
);
688 clk_disable_unprepare(chip
->clk
);
692 EXPORT_SYMBOL_GPL(uniphier_aio_probe
);
694 int uniphier_aio_remove(struct platform_device
*pdev
)
696 struct uniphier_aio_chip
*chip
= platform_get_drvdata(pdev
);
698 reset_control_assert(chip
->rst
);
699 clk_disable_unprepare(chip
->clk
);
703 EXPORT_SYMBOL_GPL(uniphier_aio_remove
);
705 MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
706 MODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
707 MODULE_LICENSE("GPL v2");