18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Socionext UniPhier AIO ALSA CPU DAI driver. 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (c) 2016-2018 Socionext Inc. 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/errno.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/reset.h> 168c2ecf20Sopenharmony_ci#include <sound/core.h> 178c2ecf20Sopenharmony_ci#include <sound/pcm.h> 188c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 198c2ecf20Sopenharmony_ci#include <sound/soc.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "aio.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct device *dev = &chip->pdev->dev; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci if (pll_id < 0 || chip->num_plls <= pll_id) { 288c2ecf20Sopenharmony_ci dev_err(dev, "PLL(%d) is not supported\n", pll_id); 298c2ecf20Sopenharmony_ci return false; 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci return chip->plls[pll_id].enable; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * find_volume - find volume supported HW port by HW port number 378c2ecf20Sopenharmony_ci * @chip: the AIO chip pointer 388c2ecf20Sopenharmony_ci * @oport_hw: HW port number, one of AUD_HW_XXXX 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * Find AIO device from device list by HW port number. Volume feature is 418c2ecf20Sopenharmony_ci * available only in Output and PCM ports, this limitation comes from HW 428c2ecf20Sopenharmony_ci * specifications. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Return: The pointer of AIO substream if successful, otherwise NULL on error. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip, 478c2ecf20Sopenharmony_ci int oport_hw) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci int i; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci for (i = 0; i < chip->num_aios; i++) { 528c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &chip->aios[i].sub[0]; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (!sub->swm) 558c2ecf20Sopenharmony_ci continue; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (sub->swm->oport.hw == oport_hw) 588c2ecf20Sopenharmony_ci return sub; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return NULL; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic bool match_spec(const struct uniphier_aio_spec *spec, 658c2ecf20Sopenharmony_ci const char *name, int dir) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci if (dir == SNDRV_PCM_STREAM_PLAYBACK && 688c2ecf20Sopenharmony_ci spec->swm.dir != PORT_DIR_OUTPUT) { 698c2ecf20Sopenharmony_ci return false; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (dir == SNDRV_PCM_STREAM_CAPTURE && 738c2ecf20Sopenharmony_ci spec->swm.dir != PORT_DIR_INPUT) { 748c2ecf20Sopenharmony_ci return false; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (spec->name && strcmp(spec->name, name) == 0) 788c2ecf20Sopenharmony_ci return true; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (spec->gname && strcmp(spec->gname, name) == 0) 818c2ecf20Sopenharmony_ci return true; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return false; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/** 878c2ecf20Sopenharmony_ci * find_spec - find HW specification info by name 888c2ecf20Sopenharmony_ci * @aio: the AIO device pointer 898c2ecf20Sopenharmony_ci * @name: name of device 908c2ecf20Sopenharmony_ci * @direction: the direction of substream, SNDRV_PCM_STREAM_* 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * Find hardware specification information from list by device name. This 938c2ecf20Sopenharmony_ci * information is used for telling the difference of SoCs to driver. 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * Specification list is array of 'struct uniphier_aio_spec' which is defined 968c2ecf20Sopenharmony_ci * in each drivers (see: aio-i2s.c). 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * Return: The pointer of hardware specification of AIO if successful, 998c2ecf20Sopenharmony_ci * otherwise NULL on error. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistatic const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio, 1028c2ecf20Sopenharmony_ci const char *name, 1038c2ecf20Sopenharmony_ci int direction) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec; 1068c2ecf20Sopenharmony_ci int i; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci for (i = 0; i < chip_spec->num_specs; i++) { 1098c2ecf20Sopenharmony_ci const struct uniphier_aio_spec *spec = &chip_spec->specs[i]; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (match_spec(spec, name, direction)) 1128c2ecf20Sopenharmony_ci return spec; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return NULL; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * find_divider - find clock divider by frequency 1208c2ecf20Sopenharmony_ci * @aio: the AIO device pointer 1218c2ecf20Sopenharmony_ci * @pll_id: PLL ID, should be AUD_PLL_XX 1228c2ecf20Sopenharmony_ci * @freq: required frequency 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * Find suitable clock divider by frequency. 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * Return: The ID of PLL if successful, otherwise negative error value. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_cistatic int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct uniphier_aio_pll *pll; 1318c2ecf20Sopenharmony_ci int mul[] = { 1, 1, 1, 2, }; 1328c2ecf20Sopenharmony_ci int div[] = { 2, 3, 1, 3, }; 1338c2ecf20Sopenharmony_ci int i; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!is_valid_pll(aio->chip, pll_id)) 1368c2ecf20Sopenharmony_ci return -EINVAL; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci pll = &aio->chip->plls[pll_id]; 1398c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mul); i++) 1408c2ecf20Sopenharmony_ci if (pll->freq * mul[i] / div[i] == freq) 1418c2ecf20Sopenharmony_ci return i; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return -ENOTSUPP; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id, 1478c2ecf20Sopenharmony_ci unsigned int freq, int dir) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 1508c2ecf20Sopenharmony_ci struct device *dev = &aio->chip->pdev->dev; 1518c2ecf20Sopenharmony_ci bool pll_auto = false; 1528c2ecf20Sopenharmony_ci int pll_id, div_id; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci switch (clk_id) { 1558c2ecf20Sopenharmony_ci case AUD_CLK_IO: 1568c2ecf20Sopenharmony_ci return -ENOTSUPP; 1578c2ecf20Sopenharmony_ci case AUD_CLK_A1: 1588c2ecf20Sopenharmony_ci pll_id = AUD_PLL_A1; 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci case AUD_CLK_F1: 1618c2ecf20Sopenharmony_ci pll_id = AUD_PLL_F1; 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci case AUD_CLK_A2: 1648c2ecf20Sopenharmony_ci pll_id = AUD_PLL_A2; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci case AUD_CLK_F2: 1678c2ecf20Sopenharmony_ci pll_id = AUD_PLL_F2; 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci case AUD_CLK_A: 1708c2ecf20Sopenharmony_ci pll_id = AUD_PLL_A1; 1718c2ecf20Sopenharmony_ci pll_auto = true; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case AUD_CLK_F: 1748c2ecf20Sopenharmony_ci pll_id = AUD_PLL_F1; 1758c2ecf20Sopenharmony_ci pll_auto = true; 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case AUD_CLK_APLL: 1788c2ecf20Sopenharmony_ci pll_id = AUD_PLL_APLL; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci case AUD_CLK_RX0: 1818c2ecf20Sopenharmony_ci pll_id = AUD_PLL_RX0; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case AUD_CLK_USB0: 1848c2ecf20Sopenharmony_ci pll_id = AUD_PLL_USB0; 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci case AUD_CLK_HSC0: 1878c2ecf20Sopenharmony_ci pll_id = AUD_PLL_HSC0; 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci default: 1908c2ecf20Sopenharmony_ci dev_err(dev, "Sysclk(%d) is not supported\n", clk_id); 1918c2ecf20Sopenharmony_ci return -EINVAL; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (pll_auto) { 1958c2ecf20Sopenharmony_ci for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) { 1968c2ecf20Sopenharmony_ci div_id = find_divider(aio, pll_id, freq); 1978c2ecf20Sopenharmony_ci if (div_id >= 0) { 1988c2ecf20Sopenharmony_ci aio->plldiv = div_id; 1998c2ecf20Sopenharmony_ci break; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci if (pll_id == aio->chip->num_plls) { 2038c2ecf20Sopenharmony_ci dev_err(dev, "Sysclk frequency is not supported(%d)\n", 2048c2ecf20Sopenharmony_ci freq); 2058c2ecf20Sopenharmony_ci return -EINVAL; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (dir == SND_SOC_CLOCK_OUT) 2108c2ecf20Sopenharmony_ci aio->pll_out = pll_id; 2118c2ecf20Sopenharmony_ci else 2128c2ecf20Sopenharmony_ci aio->pll_in = pll_id; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return 0; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id, 2188c2ecf20Sopenharmony_ci int source, unsigned int freq_in, 2198c2ecf20Sopenharmony_ci unsigned int freq_out) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 2228c2ecf20Sopenharmony_ci int ret; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (!is_valid_pll(aio->chip, pll_id)) 2258c2ecf20Sopenharmony_ci return -EINVAL; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ret = aio_chip_set_pll(aio->chip, pll_id, freq_out); 2288c2ecf20Sopenharmony_ci if (ret < 0) 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 2378c2ecf20Sopenharmony_ci struct device *dev = &aio->chip->pdev->dev; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 2408c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 2418c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 2428c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 2438c2ecf20Sopenharmony_ci aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci default: 2468c2ecf20Sopenharmony_ci dev_err(dev, "Format is not supported(%d)\n", 2478c2ecf20Sopenharmony_ci fmt & SND_SOC_DAIFMT_FORMAT_MASK); 2488c2ecf20Sopenharmony_ci return -EINVAL; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int uniphier_aio_startup(struct snd_pcm_substream *substream, 2558c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 2588c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 2598c2ecf20Sopenharmony_ci int ret; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci sub->substream = substream; 2628c2ecf20Sopenharmony_ci sub->pass_through = 0; 2638c2ecf20Sopenharmony_ci sub->use_mmap = true; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci ret = aio_init(sub); 2668c2ecf20Sopenharmony_ci if (ret) 2678c2ecf20Sopenharmony_ci return ret; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic void uniphier_aio_shutdown(struct snd_pcm_substream *substream, 2738c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 2768c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci sub->substream = NULL; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int uniphier_aio_hw_params(struct snd_pcm_substream *substream, 2828c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 2838c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 2868c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 2878c2ecf20Sopenharmony_ci struct device *dev = &aio->chip->pdev->dev; 2888c2ecf20Sopenharmony_ci int freq, ret; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci switch (params_rate(params)) { 2918c2ecf20Sopenharmony_ci case 48000: 2928c2ecf20Sopenharmony_ci case 32000: 2938c2ecf20Sopenharmony_ci case 24000: 2948c2ecf20Sopenharmony_ci freq = 12288000; 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case 44100: 2978c2ecf20Sopenharmony_ci case 22050: 2988c2ecf20Sopenharmony_ci freq = 11289600; 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci default: 3018c2ecf20Sopenharmony_ci dev_err(dev, "Rate is not supported(%d)\n", 3028c2ecf20Sopenharmony_ci params_rate(params)); 3038c2ecf20Sopenharmony_ci return -EINVAL; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A, 3068c2ecf20Sopenharmony_ci freq, SND_SOC_CLOCK_OUT); 3078c2ecf20Sopenharmony_ci if (ret) 3088c2ecf20Sopenharmony_ci return ret; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci sub->params = *params; 3118c2ecf20Sopenharmony_ci sub->setting = 1; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci aio_port_reset(sub); 3148c2ecf20Sopenharmony_ci aio_port_set_volume(sub, sub->vol); 3158c2ecf20Sopenharmony_ci aio_src_reset(sub); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int uniphier_aio_hw_free(struct snd_pcm_substream *substream, 3218c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 3248c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci sub->setting = 0; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic int uniphier_aio_prepare(struct snd_pcm_substream *substream, 3328c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 3358c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 3368c2ecf20Sopenharmony_ci int ret; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = aio_port_set_param(sub, sub->pass_through, &sub->params); 3398c2ecf20Sopenharmony_ci if (ret) 3408c2ecf20Sopenharmony_ci return ret; 3418c2ecf20Sopenharmony_ci ret = aio_src_set_param(sub, &sub->params); 3428c2ecf20Sopenharmony_ci if (ret) 3438c2ecf20Sopenharmony_ci return ret; 3448c2ecf20Sopenharmony_ci aio_port_set_enable(sub, 1); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ret = aio_if_set_param(sub, sub->pass_through); 3478c2ecf20Sopenharmony_ci if (ret) 3488c2ecf20Sopenharmony_ci return ret; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (sub->swm->type == PORT_TYPE_CONV) { 3518c2ecf20Sopenharmony_ci ret = aio_srcif_set_param(sub); 3528c2ecf20Sopenharmony_ci if (ret) 3538c2ecf20Sopenharmony_ci return ret; 3548c2ecf20Sopenharmony_ci ret = aio_srcch_set_param(sub); 3558c2ecf20Sopenharmony_ci if (ret) 3568c2ecf20Sopenharmony_ci return ret; 3578c2ecf20Sopenharmony_ci aio_srcch_set_enable(sub, 1); 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_i2s_ops = { 3648c2ecf20Sopenharmony_ci .set_sysclk = uniphier_aio_set_sysclk, 3658c2ecf20Sopenharmony_ci .set_pll = uniphier_aio_set_pll, 3668c2ecf20Sopenharmony_ci .set_fmt = uniphier_aio_set_fmt, 3678c2ecf20Sopenharmony_ci .startup = uniphier_aio_startup, 3688c2ecf20Sopenharmony_ci .shutdown = uniphier_aio_shutdown, 3698c2ecf20Sopenharmony_ci .hw_params = uniphier_aio_hw_params, 3708c2ecf20Sopenharmony_ci .hw_free = uniphier_aio_hw_free, 3718c2ecf20Sopenharmony_ci .prepare = uniphier_aio_prepare, 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_ops = { 3768c2ecf20Sopenharmony_ci .set_sysclk = uniphier_aio_set_sysclk, 3778c2ecf20Sopenharmony_ci .set_pll = uniphier_aio_set_pll, 3788c2ecf20Sopenharmony_ci .startup = uniphier_aio_startup, 3798c2ecf20Sopenharmony_ci .shutdown = uniphier_aio_shutdown, 3808c2ecf20Sopenharmony_ci .hw_params = uniphier_aio_hw_params, 3818c2ecf20Sopenharmony_ci .hw_free = uniphier_aio_hw_free, 3828c2ecf20Sopenharmony_ci .prepare = uniphier_aio_prepare, 3838c2ecf20Sopenharmony_ci}; 3848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ciint uniphier_aio_dai_probe(struct snd_soc_dai *dai) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 3898c2ecf20Sopenharmony_ci int i; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aio->sub); i++) { 3928c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[i]; 3938c2ecf20Sopenharmony_ci const struct uniphier_aio_spec *spec; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci spec = find_spec(aio, dai->name, i); 3968c2ecf20Sopenharmony_ci if (!spec) 3978c2ecf20Sopenharmony_ci continue; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci sub->swm = &spec->swm; 4008c2ecf20Sopenharmony_ci sub->spec = spec; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci sub->vol = AUD_VOL_INIT; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci aio_iecout_set_enable(aio->chip, true); 4068c2ecf20Sopenharmony_ci aio_chip_init(aio->chip); 4078c2ecf20Sopenharmony_ci aio->chip->active = 1; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_dai_probe); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ciint uniphier_aio_dai_remove(struct snd_soc_dai *dai) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci aio->chip->active = 0; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_dai_remove); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic void uniphier_aio_dai_suspend(struct snd_soc_dai *dai) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (!snd_soc_dai_active(dai)) 4288c2ecf20Sopenharmony_ci return; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci aio->chip->num_wup_aios--; 4318c2ecf20Sopenharmony_ci if (!aio->chip->num_wup_aios) { 4328c2ecf20Sopenharmony_ci reset_control_assert(aio->chip->rst); 4338c2ecf20Sopenharmony_ci clk_disable_unprepare(aio->chip->clk); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int uniphier_aio_suspend(struct snd_soc_component *component) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct snd_soc_dai *dai; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci for_each_component_dais(component, dai) 4428c2ecf20Sopenharmony_ci uniphier_aio_dai_suspend(dai); 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int uniphier_aio_dai_resume(struct snd_soc_dai *dai) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 4498c2ecf20Sopenharmony_ci int ret, i; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!snd_soc_dai_active(dai)) 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (!aio->chip->active) 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (!aio->chip->num_wup_aios) { 4588c2ecf20Sopenharmony_ci ret = clk_prepare_enable(aio->chip->clk); 4598c2ecf20Sopenharmony_ci if (ret) 4608c2ecf20Sopenharmony_ci return ret; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci ret = reset_control_deassert(aio->chip->rst); 4638c2ecf20Sopenharmony_ci if (ret) 4648c2ecf20Sopenharmony_ci goto err_out_clock; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci aio_iecout_set_enable(aio->chip, true); 4688c2ecf20Sopenharmony_ci aio_chip_init(aio->chip); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aio->sub); i++) { 4718c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[i]; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (!sub->spec || !sub->substream) 4748c2ecf20Sopenharmony_ci continue; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ret = aio_init(sub); 4778c2ecf20Sopenharmony_ci if (ret) 4788c2ecf20Sopenharmony_ci goto err_out_reset; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (!sub->setting) 4818c2ecf20Sopenharmony_ci continue; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci aio_port_reset(sub); 4848c2ecf20Sopenharmony_ci aio_src_reset(sub); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci aio->chip->num_wup_aios++; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cierr_out_reset: 4918c2ecf20Sopenharmony_ci if (!aio->chip->num_wup_aios) 4928c2ecf20Sopenharmony_ci reset_control_assert(aio->chip->rst); 4938c2ecf20Sopenharmony_cierr_out_clock: 4948c2ecf20Sopenharmony_ci if (!aio->chip->num_wup_aios) 4958c2ecf20Sopenharmony_ci clk_disable_unprepare(aio->chip->clk); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return ret; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int uniphier_aio_resume(struct snd_soc_component *component) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct snd_soc_dai *dai; 5038c2ecf20Sopenharmony_ci int ret = 0; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci for_each_component_dais(component, dai) 5068c2ecf20Sopenharmony_ci ret |= uniphier_aio_dai_resume(dai); 5078c2ecf20Sopenharmony_ci return ret; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol, 5118c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 5148c2ecf20Sopenharmony_ci uinfo->count = 1; 5158c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 5168c2ecf20Sopenharmony_ci uinfo->value.integer.max = AUD_VOL_MAX; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol, 5228c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 5258c2ecf20Sopenharmony_ci struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp); 5268c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub; 5278c2ecf20Sopenharmony_ci int oport_hw = kcontrol->private_value; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci sub = find_volume(chip, oport_hw); 5308c2ecf20Sopenharmony_ci if (!sub) 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = sub->vol; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return 0; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol, 5398c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 5428c2ecf20Sopenharmony_ci struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp); 5438c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub; 5448c2ecf20Sopenharmony_ci int oport_hw = kcontrol->private_value; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci sub = find_volume(chip, oport_hw); 5478c2ecf20Sopenharmony_ci if (!sub) 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (sub->vol == ucontrol->value.integer.value[0]) 5518c2ecf20Sopenharmony_ci return 0; 5528c2ecf20Sopenharmony_ci sub->vol = ucontrol->value.integer.value[0]; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci aio_port_set_volume(sub, sub->vol); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return 0; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new uniphier_aio_controls[] = { 5608c2ecf20Sopenharmony_ci { 5618c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5628c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 5638c2ecf20Sopenharmony_ci .name = "HPCMOUT1 Volume", 5648c2ecf20Sopenharmony_ci .info = uniphier_aio_vol_info, 5658c2ecf20Sopenharmony_ci .get = uniphier_aio_vol_get, 5668c2ecf20Sopenharmony_ci .put = uniphier_aio_vol_put, 5678c2ecf20Sopenharmony_ci .private_value = AUD_HW_HPCMOUT1, 5688c2ecf20Sopenharmony_ci }, 5698c2ecf20Sopenharmony_ci { 5708c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5718c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 5728c2ecf20Sopenharmony_ci .name = "PCMOUT1 Volume", 5738c2ecf20Sopenharmony_ci .info = uniphier_aio_vol_info, 5748c2ecf20Sopenharmony_ci .get = uniphier_aio_vol_get, 5758c2ecf20Sopenharmony_ci .put = uniphier_aio_vol_put, 5768c2ecf20Sopenharmony_ci .private_value = AUD_HW_PCMOUT1, 5778c2ecf20Sopenharmony_ci }, 5788c2ecf20Sopenharmony_ci { 5798c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5808c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 5818c2ecf20Sopenharmony_ci .name = "PCMOUT2 Volume", 5828c2ecf20Sopenharmony_ci .info = uniphier_aio_vol_info, 5838c2ecf20Sopenharmony_ci .get = uniphier_aio_vol_get, 5848c2ecf20Sopenharmony_ci .put = uniphier_aio_vol_put, 5858c2ecf20Sopenharmony_ci .private_value = AUD_HW_PCMOUT2, 5868c2ecf20Sopenharmony_ci }, 5878c2ecf20Sopenharmony_ci { 5888c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5898c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 5908c2ecf20Sopenharmony_ci .name = "PCMOUT3 Volume", 5918c2ecf20Sopenharmony_ci .info = uniphier_aio_vol_info, 5928c2ecf20Sopenharmony_ci .get = uniphier_aio_vol_get, 5938c2ecf20Sopenharmony_ci .put = uniphier_aio_vol_put, 5948c2ecf20Sopenharmony_ci .private_value = AUD_HW_PCMOUT3, 5958c2ecf20Sopenharmony_ci }, 5968c2ecf20Sopenharmony_ci { 5978c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5988c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 5998c2ecf20Sopenharmony_ci .name = "HIECOUT1 Volume", 6008c2ecf20Sopenharmony_ci .info = uniphier_aio_vol_info, 6018c2ecf20Sopenharmony_ci .get = uniphier_aio_vol_get, 6028c2ecf20Sopenharmony_ci .put = uniphier_aio_vol_put, 6038c2ecf20Sopenharmony_ci .private_value = AUD_HW_HIECOUT1, 6048c2ecf20Sopenharmony_ci }, 6058c2ecf20Sopenharmony_ci { 6068c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 6078c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 6088c2ecf20Sopenharmony_ci .name = "IECOUT1 Volume", 6098c2ecf20Sopenharmony_ci .info = uniphier_aio_vol_info, 6108c2ecf20Sopenharmony_ci .get = uniphier_aio_vol_get, 6118c2ecf20Sopenharmony_ci .put = uniphier_aio_vol_put, 6128c2ecf20Sopenharmony_ci .private_value = AUD_HW_IECOUT1, 6138c2ecf20Sopenharmony_ci }, 6148c2ecf20Sopenharmony_ci}; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver uniphier_aio_component = { 6178c2ecf20Sopenharmony_ci .name = "uniphier-aio", 6188c2ecf20Sopenharmony_ci .controls = uniphier_aio_controls, 6198c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(uniphier_aio_controls), 6208c2ecf20Sopenharmony_ci .suspend = uniphier_aio_suspend, 6218c2ecf20Sopenharmony_ci .resume = uniphier_aio_resume, 6228c2ecf20Sopenharmony_ci}; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ciint uniphier_aio_probe(struct platform_device *pdev) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct uniphier_aio_chip *chip; 6278c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6288c2ecf20Sopenharmony_ci int ret, i, j; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 6318c2ecf20Sopenharmony_ci if (!chip) 6328c2ecf20Sopenharmony_ci return -ENOMEM; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci chip->chip_spec = of_device_get_match_data(dev); 6358c2ecf20Sopenharmony_ci if (!chip->chip_spec) 6368c2ecf20Sopenharmony_ci return -EINVAL; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node, 6398c2ecf20Sopenharmony_ci "socionext,syscon"); 6408c2ecf20Sopenharmony_ci if (IS_ERR(chip->regmap_sg)) { 6418c2ecf20Sopenharmony_ci if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER) 6428c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 6438c2ecf20Sopenharmony_ci chip->regmap_sg = NULL; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci chip->clk = devm_clk_get(dev, "aio"); 6478c2ecf20Sopenharmony_ci if (IS_ERR(chip->clk)) 6488c2ecf20Sopenharmony_ci return PTR_ERR(chip->clk); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci chip->rst = devm_reset_control_get_shared(dev, "aio"); 6518c2ecf20Sopenharmony_ci if (IS_ERR(chip->rst)) 6528c2ecf20Sopenharmony_ci return PTR_ERR(chip->rst); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci chip->num_aios = chip->chip_spec->num_dais; 6558c2ecf20Sopenharmony_ci chip->num_wup_aios = chip->num_aios; 6568c2ecf20Sopenharmony_ci chip->aios = devm_kcalloc(dev, 6578c2ecf20Sopenharmony_ci chip->num_aios, sizeof(struct uniphier_aio), 6588c2ecf20Sopenharmony_ci GFP_KERNEL); 6598c2ecf20Sopenharmony_ci if (!chip->aios) 6608c2ecf20Sopenharmony_ci return -ENOMEM; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci chip->num_plls = chip->chip_spec->num_plls; 6638c2ecf20Sopenharmony_ci chip->plls = devm_kcalloc(dev, 6648c2ecf20Sopenharmony_ci chip->num_plls, 6658c2ecf20Sopenharmony_ci sizeof(struct uniphier_aio_pll), 6668c2ecf20Sopenharmony_ci GFP_KERNEL); 6678c2ecf20Sopenharmony_ci if (!chip->plls) 6688c2ecf20Sopenharmony_ci return -ENOMEM; 6698c2ecf20Sopenharmony_ci memcpy(chip->plls, chip->chip_spec->plls, 6708c2ecf20Sopenharmony_ci sizeof(struct uniphier_aio_pll) * chip->num_plls); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci for (i = 0; i < chip->num_aios; i++) { 6738c2ecf20Sopenharmony_ci struct uniphier_aio *aio = &chip->aios[i]; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci aio->chip = chip; 6768c2ecf20Sopenharmony_ci aio->fmt = SND_SOC_DAIFMT_I2S; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(aio->sub); j++) { 6798c2ecf20Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[j]; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci sub->aio = aio; 6828c2ecf20Sopenharmony_ci spin_lock_init(&sub->lock); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci chip->pdev = pdev; 6878c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, chip); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci ret = clk_prepare_enable(chip->clk); 6908c2ecf20Sopenharmony_ci if (ret) 6918c2ecf20Sopenharmony_ci return ret; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci ret = reset_control_deassert(chip->rst); 6948c2ecf20Sopenharmony_ci if (ret) 6958c2ecf20Sopenharmony_ci goto err_out_clock; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &uniphier_aio_component, 6988c2ecf20Sopenharmony_ci chip->chip_spec->dais, 6998c2ecf20Sopenharmony_ci chip->chip_spec->num_dais); 7008c2ecf20Sopenharmony_ci if (ret) { 7018c2ecf20Sopenharmony_ci dev_err(dev, "Register component failed.\n"); 7028c2ecf20Sopenharmony_ci goto err_out_reset; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci ret = uniphier_aiodma_soc_register_platform(pdev); 7068c2ecf20Sopenharmony_ci if (ret) { 7078c2ecf20Sopenharmony_ci dev_err(dev, "Register platform failed.\n"); 7088c2ecf20Sopenharmony_ci goto err_out_reset; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return 0; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cierr_out_reset: 7148c2ecf20Sopenharmony_ci reset_control_assert(chip->rst); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cierr_out_clock: 7178c2ecf20Sopenharmony_ci clk_disable_unprepare(chip->clk); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return ret; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_probe); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ciint uniphier_aio_remove(struct platform_device *pdev) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct uniphier_aio_chip *chip = platform_get_drvdata(pdev); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci reset_control_assert(chip->rst); 7288c2ecf20Sopenharmony_ci clk_disable_unprepare(chip->clk); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_remove); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ciMODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>"); 7358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("UniPhier AIO CPU DAI driver."); 7368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 737