162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Socionext UniPhier AIO ALSA CPU DAI driver. 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2016-2018 Socionext Inc. 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/of.h> 1362306a36Sopenharmony_ci#include <linux/of_platform.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/reset.h> 1662306a36Sopenharmony_ci#include <sound/core.h> 1762306a36Sopenharmony_ci#include <sound/pcm.h> 1862306a36Sopenharmony_ci#include <sound/pcm_params.h> 1962306a36Sopenharmony_ci#include <sound/soc.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "aio.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct device *dev = &chip->pdev->dev; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci if (pll_id < 0 || chip->num_plls <= pll_id) { 2862306a36Sopenharmony_ci dev_err(dev, "PLL(%d) is not supported\n", pll_id); 2962306a36Sopenharmony_ci return false; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci return chip->plls[pll_id].enable; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/** 3662306a36Sopenharmony_ci * find_volume - find volume supported HW port by HW port number 3762306a36Sopenharmony_ci * @chip: the AIO chip pointer 3862306a36Sopenharmony_ci * @oport_hw: HW port number, one of AUD_HW_XXXX 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Find AIO device from device list by HW port number. Volume feature is 4162306a36Sopenharmony_ci * available only in Output and PCM ports, this limitation comes from HW 4262306a36Sopenharmony_ci * specifications. 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * Return: The pointer of AIO substream if successful, otherwise NULL on error. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistatic struct uniphier_aio_sub *find_volume(struct uniphier_aio_chip *chip, 4762306a36Sopenharmony_ci int oport_hw) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci int i; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci for (i = 0; i < chip->num_aios; i++) { 5262306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &chip->aios[i].sub[0]; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (!sub->swm) 5562306a36Sopenharmony_ci continue; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (sub->swm->oport.hw == oport_hw) 5862306a36Sopenharmony_ci return sub; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return NULL; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic bool match_spec(const struct uniphier_aio_spec *spec, 6562306a36Sopenharmony_ci const char *name, int dir) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci if (dir == SNDRV_PCM_STREAM_PLAYBACK && 6862306a36Sopenharmony_ci spec->swm.dir != PORT_DIR_OUTPUT) { 6962306a36Sopenharmony_ci return false; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (dir == SNDRV_PCM_STREAM_CAPTURE && 7362306a36Sopenharmony_ci spec->swm.dir != PORT_DIR_INPUT) { 7462306a36Sopenharmony_ci return false; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (spec->name && strcmp(spec->name, name) == 0) 7862306a36Sopenharmony_ci return true; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (spec->gname && strcmp(spec->gname, name) == 0) 8162306a36Sopenharmony_ci return true; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return false; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/** 8762306a36Sopenharmony_ci * find_spec - find HW specification info by name 8862306a36Sopenharmony_ci * @aio: the AIO device pointer 8962306a36Sopenharmony_ci * @name: name of device 9062306a36Sopenharmony_ci * @direction: the direction of substream, SNDRV_PCM_STREAM_* 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * Find hardware specification information from list by device name. This 9362306a36Sopenharmony_ci * information is used for telling the difference of SoCs to driver. 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Specification list is array of 'struct uniphier_aio_spec' which is defined 9662306a36Sopenharmony_ci * in each drivers (see: aio-i2s.c). 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * Return: The pointer of hardware specification of AIO if successful, 9962306a36Sopenharmony_ci * otherwise NULL on error. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_cistatic const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio, 10262306a36Sopenharmony_ci const char *name, 10362306a36Sopenharmony_ci int direction) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec; 10662306a36Sopenharmony_ci int i; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci for (i = 0; i < chip_spec->num_specs; i++) { 10962306a36Sopenharmony_ci const struct uniphier_aio_spec *spec = &chip_spec->specs[i]; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (match_spec(spec, name, direction)) 11262306a36Sopenharmony_ci return spec; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return NULL; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/** 11962306a36Sopenharmony_ci * find_divider - find clock divider by frequency 12062306a36Sopenharmony_ci * @aio: the AIO device pointer 12162306a36Sopenharmony_ci * @pll_id: PLL ID, should be AUD_PLL_XX 12262306a36Sopenharmony_ci * @freq: required frequency 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * Find suitable clock divider by frequency. 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * Return: The ID of PLL if successful, otherwise negative error value. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_cistatic int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct uniphier_aio_pll *pll; 13162306a36Sopenharmony_ci static const int mul[] = { 1, 1, 1, 2, }; 13262306a36Sopenharmony_ci static const int div[] = { 2, 3, 1, 3, }; 13362306a36Sopenharmony_ci int i; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (!is_valid_pll(aio->chip, pll_id)) 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci pll = &aio->chip->plls[pll_id]; 13962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mul); i++) 14062306a36Sopenharmony_ci if (pll->freq * mul[i] / div[i] == freq) 14162306a36Sopenharmony_ci return i; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return -ENOTSUPP; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id, 14762306a36Sopenharmony_ci unsigned int freq, int dir) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 15062306a36Sopenharmony_ci struct device *dev = &aio->chip->pdev->dev; 15162306a36Sopenharmony_ci bool pll_auto = false; 15262306a36Sopenharmony_ci int pll_id, div_id; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci switch (clk_id) { 15562306a36Sopenharmony_ci case AUD_CLK_IO: 15662306a36Sopenharmony_ci return -ENOTSUPP; 15762306a36Sopenharmony_ci case AUD_CLK_A1: 15862306a36Sopenharmony_ci pll_id = AUD_PLL_A1; 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci case AUD_CLK_F1: 16162306a36Sopenharmony_ci pll_id = AUD_PLL_F1; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci case AUD_CLK_A2: 16462306a36Sopenharmony_ci pll_id = AUD_PLL_A2; 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci case AUD_CLK_F2: 16762306a36Sopenharmony_ci pll_id = AUD_PLL_F2; 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci case AUD_CLK_A: 17062306a36Sopenharmony_ci pll_id = AUD_PLL_A1; 17162306a36Sopenharmony_ci pll_auto = true; 17262306a36Sopenharmony_ci break; 17362306a36Sopenharmony_ci case AUD_CLK_F: 17462306a36Sopenharmony_ci pll_id = AUD_PLL_F1; 17562306a36Sopenharmony_ci pll_auto = true; 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci case AUD_CLK_APLL: 17862306a36Sopenharmony_ci pll_id = AUD_PLL_APLL; 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci case AUD_CLK_RX0: 18162306a36Sopenharmony_ci pll_id = AUD_PLL_RX0; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci case AUD_CLK_USB0: 18462306a36Sopenharmony_ci pll_id = AUD_PLL_USB0; 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci case AUD_CLK_HSC0: 18762306a36Sopenharmony_ci pll_id = AUD_PLL_HSC0; 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci default: 19062306a36Sopenharmony_ci dev_err(dev, "Sysclk(%d) is not supported\n", clk_id); 19162306a36Sopenharmony_ci return -EINVAL; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (pll_auto) { 19562306a36Sopenharmony_ci for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) { 19662306a36Sopenharmony_ci div_id = find_divider(aio, pll_id, freq); 19762306a36Sopenharmony_ci if (div_id >= 0) { 19862306a36Sopenharmony_ci aio->plldiv = div_id; 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci if (pll_id == aio->chip->num_plls) { 20362306a36Sopenharmony_ci dev_err(dev, "Sysclk frequency is not supported(%d)\n", 20462306a36Sopenharmony_ci freq); 20562306a36Sopenharmony_ci return -EINVAL; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (dir == SND_SOC_CLOCK_OUT) 21062306a36Sopenharmony_ci aio->pll_out = pll_id; 21162306a36Sopenharmony_ci else 21262306a36Sopenharmony_ci aio->pll_in = pll_id; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id, 21862306a36Sopenharmony_ci int source, unsigned int freq_in, 21962306a36Sopenharmony_ci unsigned int freq_out) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 22262306a36Sopenharmony_ci int ret; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (!is_valid_pll(aio->chip, pll_id)) 22562306a36Sopenharmony_ci return -EINVAL; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ret = aio_chip_set_pll(aio->chip, pll_id, freq_out); 22862306a36Sopenharmony_ci if (ret < 0) 22962306a36Sopenharmony_ci return ret; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 23762306a36Sopenharmony_ci struct device *dev = &aio->chip->pdev->dev; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 24062306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 24162306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 24262306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 24362306a36Sopenharmony_ci aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci default: 24662306a36Sopenharmony_ci dev_err(dev, "Format is not supported(%d)\n", 24762306a36Sopenharmony_ci fmt & SND_SOC_DAIFMT_FORMAT_MASK); 24862306a36Sopenharmony_ci return -EINVAL; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int uniphier_aio_startup(struct snd_pcm_substream *substream, 25562306a36Sopenharmony_ci struct snd_soc_dai *dai) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 25862306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci sub->substream = substream; 26162306a36Sopenharmony_ci sub->pass_through = 0; 26262306a36Sopenharmony_ci sub->use_mmap = true; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return aio_init(sub); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic void uniphier_aio_shutdown(struct snd_pcm_substream *substream, 26862306a36Sopenharmony_ci struct snd_soc_dai *dai) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 27162306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci sub->substream = NULL; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int uniphier_aio_hw_params(struct snd_pcm_substream *substream, 27762306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 27862306a36Sopenharmony_ci struct snd_soc_dai *dai) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 28162306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 28262306a36Sopenharmony_ci struct device *dev = &aio->chip->pdev->dev; 28362306a36Sopenharmony_ci int freq, ret; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci switch (params_rate(params)) { 28662306a36Sopenharmony_ci case 48000: 28762306a36Sopenharmony_ci case 32000: 28862306a36Sopenharmony_ci case 24000: 28962306a36Sopenharmony_ci freq = 12288000; 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci case 44100: 29262306a36Sopenharmony_ci case 22050: 29362306a36Sopenharmony_ci freq = 11289600; 29462306a36Sopenharmony_ci break; 29562306a36Sopenharmony_ci default: 29662306a36Sopenharmony_ci dev_err(dev, "Rate is not supported(%d)\n", 29762306a36Sopenharmony_ci params_rate(params)); 29862306a36Sopenharmony_ci return -EINVAL; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A, 30162306a36Sopenharmony_ci freq, SND_SOC_CLOCK_OUT); 30262306a36Sopenharmony_ci if (ret) 30362306a36Sopenharmony_ci return ret; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci sub->params = *params; 30662306a36Sopenharmony_ci sub->setting = 1; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci aio_port_reset(sub); 30962306a36Sopenharmony_ci aio_port_set_volume(sub, sub->vol); 31062306a36Sopenharmony_ci aio_src_reset(sub); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int uniphier_aio_hw_free(struct snd_pcm_substream *substream, 31662306a36Sopenharmony_ci struct snd_soc_dai *dai) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 31962306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci sub->setting = 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int uniphier_aio_prepare(struct snd_pcm_substream *substream, 32762306a36Sopenharmony_ci struct snd_soc_dai *dai) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 33062306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; 33162306a36Sopenharmony_ci int ret; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ret = aio_port_set_param(sub, sub->pass_through, &sub->params); 33462306a36Sopenharmony_ci if (ret) 33562306a36Sopenharmony_ci return ret; 33662306a36Sopenharmony_ci ret = aio_src_set_param(sub, &sub->params); 33762306a36Sopenharmony_ci if (ret) 33862306a36Sopenharmony_ci return ret; 33962306a36Sopenharmony_ci aio_port_set_enable(sub, 1); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = aio_if_set_param(sub, sub->pass_through); 34262306a36Sopenharmony_ci if (ret) 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (sub->swm->type == PORT_TYPE_CONV) { 34662306a36Sopenharmony_ci ret = aio_srcif_set_param(sub); 34762306a36Sopenharmony_ci if (ret) 34862306a36Sopenharmony_ci return ret; 34962306a36Sopenharmony_ci ret = aio_srcch_set_param(sub); 35062306a36Sopenharmony_ci if (ret) 35162306a36Sopenharmony_ci return ret; 35262306a36Sopenharmony_ci aio_srcch_set_enable(sub, 1); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int uniphier_aio_dai_probe(struct snd_soc_dai *dai) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 36162306a36Sopenharmony_ci int i; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aio->sub); i++) { 36462306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[i]; 36562306a36Sopenharmony_ci const struct uniphier_aio_spec *spec; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci spec = find_spec(aio, dai->name, i); 36862306a36Sopenharmony_ci if (!spec) 36962306a36Sopenharmony_ci continue; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci sub->swm = &spec->swm; 37262306a36Sopenharmony_ci sub->spec = spec; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci sub->vol = AUD_VOL_INIT; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci aio_iecout_set_enable(aio->chip, true); 37862306a36Sopenharmony_ci aio_chip_init(aio->chip); 37962306a36Sopenharmony_ci aio->chip->active = 1; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int uniphier_aio_dai_remove(struct snd_soc_dai *dai) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci aio->chip->active = 0; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return 0; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int uniphier_aio_ld11_probe(struct snd_soc_dai *dai) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci int ret; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ret = uniphier_aio_dai_probe(dai); 39862306a36Sopenharmony_ci if (ret < 0) 39962306a36Sopenharmony_ci return ret; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); 40262306a36Sopenharmony_ci if (ret < 0) 40362306a36Sopenharmony_ci return ret; 40462306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); 40562306a36Sopenharmony_ci if (ret < 0) 40662306a36Sopenharmony_ci return ret; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); 40962306a36Sopenharmony_ci if (ret < 0) 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); 41262306a36Sopenharmony_ci if (ret < 0) 41362306a36Sopenharmony_ci return ret; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci int ret; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci ret = uniphier_aio_dai_probe(dai); 42362306a36Sopenharmony_ci if (ret < 0) 42462306a36Sopenharmony_ci return ret; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000); 42762306a36Sopenharmony_ci if (ret < 0) 42862306a36Sopenharmony_ci return ret; 42962306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000); 43062306a36Sopenharmony_ci if (ret < 0) 43162306a36Sopenharmony_ci return ret; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800); 43462306a36Sopenharmony_ci if (ret < 0) 43562306a36Sopenharmony_ci return ret; 43662306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800); 43762306a36Sopenharmony_ci if (ret < 0) 43862306a36Sopenharmony_ci return ret; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return 0; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = { 44462306a36Sopenharmony_ci .probe = uniphier_aio_ld11_probe, 44562306a36Sopenharmony_ci .remove = uniphier_aio_dai_remove, 44662306a36Sopenharmony_ci .set_sysclk = uniphier_aio_set_sysclk, 44762306a36Sopenharmony_ci .set_pll = uniphier_aio_set_pll, 44862306a36Sopenharmony_ci .set_fmt = uniphier_aio_set_fmt, 44962306a36Sopenharmony_ci .startup = uniphier_aio_startup, 45062306a36Sopenharmony_ci .shutdown = uniphier_aio_shutdown, 45162306a36Sopenharmony_ci .hw_params = uniphier_aio_hw_params, 45262306a36Sopenharmony_ci .hw_free = uniphier_aio_hw_free, 45362306a36Sopenharmony_ci .prepare = uniphier_aio_prepare, 45462306a36Sopenharmony_ci}; 45562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = { 45862306a36Sopenharmony_ci .probe = uniphier_aio_ld11_probe, 45962306a36Sopenharmony_ci .remove = uniphier_aio_dai_remove, 46062306a36Sopenharmony_ci .set_sysclk = uniphier_aio_set_sysclk, 46162306a36Sopenharmony_ci .set_pll = uniphier_aio_set_pll, 46262306a36Sopenharmony_ci .startup = uniphier_aio_startup, 46362306a36Sopenharmony_ci .shutdown = uniphier_aio_shutdown, 46462306a36Sopenharmony_ci .hw_params = uniphier_aio_hw_params, 46562306a36Sopenharmony_ci .hw_free = uniphier_aio_hw_free, 46662306a36Sopenharmony_ci .prepare = uniphier_aio_prepare, 46762306a36Sopenharmony_ci}; 46862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = { 47162306a36Sopenharmony_ci .probe = uniphier_aio_ld11_probe, 47262306a36Sopenharmony_ci .remove = uniphier_aio_dai_remove, 47362306a36Sopenharmony_ci .set_sysclk = uniphier_aio_set_sysclk, 47462306a36Sopenharmony_ci .set_pll = uniphier_aio_set_pll, 47562306a36Sopenharmony_ci .startup = uniphier_aio_startup, 47662306a36Sopenharmony_ci .shutdown = uniphier_aio_shutdown, 47762306a36Sopenharmony_ci .hw_params = uniphier_aio_hw_params, 47862306a36Sopenharmony_ci .hw_free = uniphier_aio_hw_free, 47962306a36Sopenharmony_ci .prepare = uniphier_aio_prepare, 48062306a36Sopenharmony_ci .compress_new = snd_soc_new_compress, 48162306a36Sopenharmony_ci}; 48262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = { 48562306a36Sopenharmony_ci .probe = uniphier_aio_pxs2_probe, 48662306a36Sopenharmony_ci .remove = uniphier_aio_dai_remove, 48762306a36Sopenharmony_ci .set_sysclk = uniphier_aio_set_sysclk, 48862306a36Sopenharmony_ci .set_pll = uniphier_aio_set_pll, 48962306a36Sopenharmony_ci .set_fmt = uniphier_aio_set_fmt, 49062306a36Sopenharmony_ci .startup = uniphier_aio_startup, 49162306a36Sopenharmony_ci .shutdown = uniphier_aio_shutdown, 49262306a36Sopenharmony_ci .hw_params = uniphier_aio_hw_params, 49362306a36Sopenharmony_ci .hw_free = uniphier_aio_hw_free, 49462306a36Sopenharmony_ci .prepare = uniphier_aio_prepare, 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = { 49962306a36Sopenharmony_ci .probe = uniphier_aio_pxs2_probe, 50062306a36Sopenharmony_ci .remove = uniphier_aio_dai_remove, 50162306a36Sopenharmony_ci .set_sysclk = uniphier_aio_set_sysclk, 50262306a36Sopenharmony_ci .set_pll = uniphier_aio_set_pll, 50362306a36Sopenharmony_ci .startup = uniphier_aio_startup, 50462306a36Sopenharmony_ci .shutdown = uniphier_aio_shutdown, 50562306a36Sopenharmony_ci .hw_params = uniphier_aio_hw_params, 50662306a36Sopenharmony_ci .hw_free = uniphier_aio_hw_free, 50762306a36Sopenharmony_ci .prepare = uniphier_aio_prepare, 50862306a36Sopenharmony_ci}; 50962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ciconst struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = { 51262306a36Sopenharmony_ci .probe = uniphier_aio_pxs2_probe, 51362306a36Sopenharmony_ci .remove = uniphier_aio_dai_remove, 51462306a36Sopenharmony_ci .set_sysclk = uniphier_aio_set_sysclk, 51562306a36Sopenharmony_ci .set_pll = uniphier_aio_set_pll, 51662306a36Sopenharmony_ci .startup = uniphier_aio_startup, 51762306a36Sopenharmony_ci .shutdown = uniphier_aio_shutdown, 51862306a36Sopenharmony_ci .hw_params = uniphier_aio_hw_params, 51962306a36Sopenharmony_ci .hw_free = uniphier_aio_hw_free, 52062306a36Sopenharmony_ci .prepare = uniphier_aio_prepare, 52162306a36Sopenharmony_ci .compress_new = snd_soc_new_compress, 52262306a36Sopenharmony_ci}; 52362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic void uniphier_aio_dai_suspend(struct snd_soc_dai *dai) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!snd_soc_dai_active(dai)) 53062306a36Sopenharmony_ci return; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci aio->chip->num_wup_aios--; 53362306a36Sopenharmony_ci if (!aio->chip->num_wup_aios) { 53462306a36Sopenharmony_ci reset_control_assert(aio->chip->rst); 53562306a36Sopenharmony_ci clk_disable_unprepare(aio->chip->clk); 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int uniphier_aio_suspend(struct snd_soc_component *component) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct snd_soc_dai *dai; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci for_each_component_dais(component, dai) 54462306a36Sopenharmony_ci uniphier_aio_dai_suspend(dai); 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int uniphier_aio_dai_resume(struct snd_soc_dai *dai) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(dai); 55162306a36Sopenharmony_ci int ret, i; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (!snd_soc_dai_active(dai)) 55462306a36Sopenharmony_ci return 0; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (!aio->chip->active) 55762306a36Sopenharmony_ci return 0; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (!aio->chip->num_wup_aios) { 56062306a36Sopenharmony_ci ret = clk_prepare_enable(aio->chip->clk); 56162306a36Sopenharmony_ci if (ret) 56262306a36Sopenharmony_ci return ret; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ret = reset_control_deassert(aio->chip->rst); 56562306a36Sopenharmony_ci if (ret) 56662306a36Sopenharmony_ci goto err_out_clock; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci aio_iecout_set_enable(aio->chip, true); 57062306a36Sopenharmony_ci aio_chip_init(aio->chip); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aio->sub); i++) { 57362306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[i]; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (!sub->spec || !sub->substream) 57662306a36Sopenharmony_ci continue; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ret = aio_init(sub); 57962306a36Sopenharmony_ci if (ret) 58062306a36Sopenharmony_ci goto err_out_reset; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!sub->setting) 58362306a36Sopenharmony_ci continue; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci aio_port_reset(sub); 58662306a36Sopenharmony_ci aio_src_reset(sub); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci aio->chip->num_wup_aios++; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cierr_out_reset: 59362306a36Sopenharmony_ci if (!aio->chip->num_wup_aios) 59462306a36Sopenharmony_ci reset_control_assert(aio->chip->rst); 59562306a36Sopenharmony_cierr_out_clock: 59662306a36Sopenharmony_ci if (!aio->chip->num_wup_aios) 59762306a36Sopenharmony_ci clk_disable_unprepare(aio->chip->clk); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return ret; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int uniphier_aio_resume(struct snd_soc_component *component) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct snd_soc_dai *dai; 60562306a36Sopenharmony_ci int ret = 0; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci for_each_component_dais(component, dai) 60862306a36Sopenharmony_ci ret |= uniphier_aio_dai_resume(dai); 60962306a36Sopenharmony_ci return ret; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int uniphier_aio_vol_info(struct snd_kcontrol *kcontrol, 61362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 61662306a36Sopenharmony_ci uinfo->count = 1; 61762306a36Sopenharmony_ci uinfo->value.integer.min = 0; 61862306a36Sopenharmony_ci uinfo->value.integer.max = AUD_VOL_MAX; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int uniphier_aio_vol_get(struct snd_kcontrol *kcontrol, 62462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 62762306a36Sopenharmony_ci struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp); 62862306a36Sopenharmony_ci struct uniphier_aio_sub *sub; 62962306a36Sopenharmony_ci int oport_hw = kcontrol->private_value; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci sub = find_volume(chip, oport_hw); 63262306a36Sopenharmony_ci if (!sub) 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = sub->vol; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int uniphier_aio_vol_put(struct snd_kcontrol *kcontrol, 64162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 64462306a36Sopenharmony_ci struct uniphier_aio_chip *chip = snd_soc_component_get_drvdata(comp); 64562306a36Sopenharmony_ci struct uniphier_aio_sub *sub; 64662306a36Sopenharmony_ci int oport_hw = kcontrol->private_value; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci sub = find_volume(chip, oport_hw); 64962306a36Sopenharmony_ci if (!sub) 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (sub->vol == ucontrol->value.integer.value[0]) 65362306a36Sopenharmony_ci return 0; 65462306a36Sopenharmony_ci sub->vol = ucontrol->value.integer.value[0]; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci aio_port_set_volume(sub, sub->vol); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic const struct snd_kcontrol_new uniphier_aio_controls[] = { 66262306a36Sopenharmony_ci { 66362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 66462306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 66562306a36Sopenharmony_ci .name = "HPCMOUT1 Volume", 66662306a36Sopenharmony_ci .info = uniphier_aio_vol_info, 66762306a36Sopenharmony_ci .get = uniphier_aio_vol_get, 66862306a36Sopenharmony_ci .put = uniphier_aio_vol_put, 66962306a36Sopenharmony_ci .private_value = AUD_HW_HPCMOUT1, 67062306a36Sopenharmony_ci }, 67162306a36Sopenharmony_ci { 67262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 67362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 67462306a36Sopenharmony_ci .name = "PCMOUT1 Volume", 67562306a36Sopenharmony_ci .info = uniphier_aio_vol_info, 67662306a36Sopenharmony_ci .get = uniphier_aio_vol_get, 67762306a36Sopenharmony_ci .put = uniphier_aio_vol_put, 67862306a36Sopenharmony_ci .private_value = AUD_HW_PCMOUT1, 67962306a36Sopenharmony_ci }, 68062306a36Sopenharmony_ci { 68162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 68262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 68362306a36Sopenharmony_ci .name = "PCMOUT2 Volume", 68462306a36Sopenharmony_ci .info = uniphier_aio_vol_info, 68562306a36Sopenharmony_ci .get = uniphier_aio_vol_get, 68662306a36Sopenharmony_ci .put = uniphier_aio_vol_put, 68762306a36Sopenharmony_ci .private_value = AUD_HW_PCMOUT2, 68862306a36Sopenharmony_ci }, 68962306a36Sopenharmony_ci { 69062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 69162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 69262306a36Sopenharmony_ci .name = "PCMOUT3 Volume", 69362306a36Sopenharmony_ci .info = uniphier_aio_vol_info, 69462306a36Sopenharmony_ci .get = uniphier_aio_vol_get, 69562306a36Sopenharmony_ci .put = uniphier_aio_vol_put, 69662306a36Sopenharmony_ci .private_value = AUD_HW_PCMOUT3, 69762306a36Sopenharmony_ci }, 69862306a36Sopenharmony_ci { 69962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 70062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 70162306a36Sopenharmony_ci .name = "HIECOUT1 Volume", 70262306a36Sopenharmony_ci .info = uniphier_aio_vol_info, 70362306a36Sopenharmony_ci .get = uniphier_aio_vol_get, 70462306a36Sopenharmony_ci .put = uniphier_aio_vol_put, 70562306a36Sopenharmony_ci .private_value = AUD_HW_HIECOUT1, 70662306a36Sopenharmony_ci }, 70762306a36Sopenharmony_ci { 70862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 70962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 71062306a36Sopenharmony_ci .name = "IECOUT1 Volume", 71162306a36Sopenharmony_ci .info = uniphier_aio_vol_info, 71262306a36Sopenharmony_ci .get = uniphier_aio_vol_get, 71362306a36Sopenharmony_ci .put = uniphier_aio_vol_put, 71462306a36Sopenharmony_ci .private_value = AUD_HW_IECOUT1, 71562306a36Sopenharmony_ci }, 71662306a36Sopenharmony_ci}; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic const struct snd_soc_component_driver uniphier_aio_component = { 71962306a36Sopenharmony_ci .name = "uniphier-aio", 72062306a36Sopenharmony_ci .controls = uniphier_aio_controls, 72162306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(uniphier_aio_controls), 72262306a36Sopenharmony_ci .suspend = uniphier_aio_suspend, 72362306a36Sopenharmony_ci .resume = uniphier_aio_resume, 72462306a36Sopenharmony_ci}; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ciint uniphier_aio_probe(struct platform_device *pdev) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct uniphier_aio_chip *chip; 72962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 73062306a36Sopenharmony_ci int ret, i, j; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 73362306a36Sopenharmony_ci if (!chip) 73462306a36Sopenharmony_ci return -ENOMEM; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci chip->chip_spec = of_device_get_match_data(dev); 73762306a36Sopenharmony_ci if (!chip->chip_spec) 73862306a36Sopenharmony_ci return -EINVAL; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node, 74162306a36Sopenharmony_ci "socionext,syscon"); 74262306a36Sopenharmony_ci if (IS_ERR(chip->regmap_sg)) { 74362306a36Sopenharmony_ci if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER) 74462306a36Sopenharmony_ci return -EPROBE_DEFER; 74562306a36Sopenharmony_ci chip->regmap_sg = NULL; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci chip->clk = devm_clk_get(dev, "aio"); 74962306a36Sopenharmony_ci if (IS_ERR(chip->clk)) 75062306a36Sopenharmony_ci return PTR_ERR(chip->clk); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci chip->rst = devm_reset_control_get_shared(dev, "aio"); 75362306a36Sopenharmony_ci if (IS_ERR(chip->rst)) 75462306a36Sopenharmony_ci return PTR_ERR(chip->rst); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci chip->num_aios = chip->chip_spec->num_dais; 75762306a36Sopenharmony_ci chip->num_wup_aios = chip->num_aios; 75862306a36Sopenharmony_ci chip->aios = devm_kcalloc(dev, 75962306a36Sopenharmony_ci chip->num_aios, sizeof(struct uniphier_aio), 76062306a36Sopenharmony_ci GFP_KERNEL); 76162306a36Sopenharmony_ci if (!chip->aios) 76262306a36Sopenharmony_ci return -ENOMEM; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci chip->num_plls = chip->chip_spec->num_plls; 76562306a36Sopenharmony_ci chip->plls = devm_kcalloc(dev, 76662306a36Sopenharmony_ci chip->num_plls, 76762306a36Sopenharmony_ci sizeof(struct uniphier_aio_pll), 76862306a36Sopenharmony_ci GFP_KERNEL); 76962306a36Sopenharmony_ci if (!chip->plls) 77062306a36Sopenharmony_ci return -ENOMEM; 77162306a36Sopenharmony_ci memcpy(chip->plls, chip->chip_spec->plls, 77262306a36Sopenharmony_ci sizeof(struct uniphier_aio_pll) * chip->num_plls); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci for (i = 0; i < chip->num_aios; i++) { 77562306a36Sopenharmony_ci struct uniphier_aio *aio = &chip->aios[i]; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci aio->chip = chip; 77862306a36Sopenharmony_ci aio->fmt = SND_SOC_DAIFMT_I2S; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(aio->sub); j++) { 78162306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[j]; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci sub->aio = aio; 78462306a36Sopenharmony_ci spin_lock_init(&sub->lock); 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci chip->pdev = pdev; 78962306a36Sopenharmony_ci platform_set_drvdata(pdev, chip); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ret = clk_prepare_enable(chip->clk); 79262306a36Sopenharmony_ci if (ret) 79362306a36Sopenharmony_ci return ret; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci ret = reset_control_deassert(chip->rst); 79662306a36Sopenharmony_ci if (ret) 79762306a36Sopenharmony_ci goto err_out_clock; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &uniphier_aio_component, 80062306a36Sopenharmony_ci chip->chip_spec->dais, 80162306a36Sopenharmony_ci chip->chip_spec->num_dais); 80262306a36Sopenharmony_ci if (ret) { 80362306a36Sopenharmony_ci dev_err(dev, "Register component failed.\n"); 80462306a36Sopenharmony_ci goto err_out_reset; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci ret = uniphier_aiodma_soc_register_platform(pdev); 80862306a36Sopenharmony_ci if (ret) { 80962306a36Sopenharmony_ci dev_err(dev, "Register platform failed.\n"); 81062306a36Sopenharmony_ci goto err_out_reset; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return 0; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cierr_out_reset: 81662306a36Sopenharmony_ci reset_control_assert(chip->rst); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cierr_out_clock: 81962306a36Sopenharmony_ci clk_disable_unprepare(chip->clk); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return ret; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_probe); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ciint uniphier_aio_remove(struct platform_device *pdev) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct uniphier_aio_chip *chip = platform_get_drvdata(pdev); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci reset_control_assert(chip->rst); 83062306a36Sopenharmony_ci clk_disable_unprepare(chip->clk); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci return 0; 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(uniphier_aio_remove); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ciMODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>"); 83762306a36Sopenharmony_ciMODULE_DESCRIPTION("UniPhier AIO CPU DAI driver."); 83862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 839