diff options
Diffstat (limited to 'sound/soc/dwc')
| -rw-r--r-- | sound/soc/dwc/designware_i2s.c | 123 | 
1 files changed, 86 insertions, 37 deletions
| diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index ba34252b7bba..6e6a70c5c2bd 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -282,23 +282,25 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,  	config->sample_rate = params_rate(params); -	if (dev->i2s_clk_cfg) { -		ret = dev->i2s_clk_cfg(config); -		if (ret < 0) { -			dev_err(dev->dev, "runtime audio clk config fail\n"); -			return ret; -		} -	} else { -		u32 bitclk = config->sample_rate * config->data_width * 2; - -		ret = clk_set_rate(dev->clk, bitclk); -		if (ret) { -			dev_err(dev->dev, "Can't set I2S clock rate: %d\n", -				ret); -			return ret; +	if (dev->capability & DW_I2S_MASTER) { +		if (dev->i2s_clk_cfg) { +			ret = dev->i2s_clk_cfg(config); +			if (ret < 0) { +				dev_err(dev->dev, "runtime audio clk config fail\n"); +				return ret; +			} +		} else { +			u32 bitclk = config->sample_rate * +					config->data_width * 2; + +			ret = clk_set_rate(dev->clk, bitclk); +			if (ret) { +				dev_err(dev->dev, "Can't set I2S clock rate: %d\n", +					ret); +				return ret; +			}  		}  	} -  	return 0;  } @@ -348,12 +350,43 @@ static int dw_i2s_trigger(struct snd_pcm_substream *substream,  	return ret;  } +static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ +	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); +	int ret = 0; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		if (dev->capability & DW_I2S_SLAVE) +			ret = 0; +		else +			ret = -EINVAL; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		if (dev->capability & DW_I2S_MASTER) +			ret = 0; +		else +			ret = -EINVAL; +		break; +	case SND_SOC_DAIFMT_CBM_CFS: +	case SND_SOC_DAIFMT_CBS_CFM: +		ret = -EINVAL; +		break; +	default: +		dev_dbg(dev->dev, "dwc : Invalid master/slave format\n"); +		ret = -EINVAL; +		break; +	} +	return ret; +} +  static struct snd_soc_dai_ops dw_i2s_dai_ops = {  	.startup	= dw_i2s_startup,  	.shutdown	= dw_i2s_shutdown,  	.hw_params	= dw_i2s_hw_params,  	.prepare	= dw_i2s_prepare,  	.trigger	= dw_i2s_trigger, +	.set_fmt	= dw_i2s_set_fmt,  };  static const struct snd_soc_component_driver dw_i2s_component = { @@ -366,7 +399,8 @@ static int dw_i2s_suspend(struct snd_soc_dai *dai)  {  	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -	clk_disable(dev->clk); +	if (dev->capability & DW_I2S_MASTER) +		clk_disable(dev->clk);  	return 0;  } @@ -374,7 +408,8 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)  {  	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -	clk_enable(dev->clk); +	if (dev->capability & DW_I2S_MASTER) +		clk_enable(dev->clk);  	return 0;  } @@ -452,6 +487,14 @@ static int dw_configure_dai(struct dw_i2s_dev *dev,  		dw_i2s_dai->capture.rates = rates;  	} +	if (COMP1_MODE_EN(comp1)) { +		dev_dbg(dev->dev, "designware: i2s master mode supported\n"); +		dev->capability |= DW_I2S_MASTER; +	} else { +		dev_dbg(dev->dev, "designware: i2s slave mode supported\n"); +		dev->capability |= DW_I2S_SLAVE; +	} +  	return 0;  } @@ -538,6 +581,7 @@ static int dw_i2s_probe(struct platform_device *pdev)  	struct resource *res;  	int ret;  	struct snd_soc_dai_driver *dw_i2s_dai; +	const char *clk_id;  	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);  	if (!dev) { @@ -559,32 +603,35 @@ static int dw_i2s_probe(struct platform_device *pdev)  		return PTR_ERR(dev->i2s_base);  	dev->dev = &pdev->dev; +  	if (pdata) { +		dev->capability = pdata->cap; +		clk_id = NULL;  		ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); -		if (ret < 0) -			return ret; +	} else { +		clk_id = "i2sclk"; +		ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res); +	} +	if (ret < 0) +		return ret; -		dev->capability = pdata->cap; -		dev->i2s_clk_cfg = pdata->i2s_clk_cfg; -		if (!dev->i2s_clk_cfg) { -			dev_err(&pdev->dev, "no clock configure method\n"); -			return -ENODEV; +	if (dev->capability & DW_I2S_MASTER) { +		if (pdata) { +			dev->i2s_clk_cfg = pdata->i2s_clk_cfg; +			if (!dev->i2s_clk_cfg) { +				dev_err(&pdev->dev, "no clock configure method\n"); +				return -ENODEV; +			}  		} +		dev->clk = devm_clk_get(&pdev->dev, clk_id); -		dev->clk = devm_clk_get(&pdev->dev, NULL); -	} else { -		ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res); +		if (IS_ERR(dev->clk)) +			return PTR_ERR(dev->clk); + +		ret = clk_prepare_enable(dev->clk);  		if (ret < 0)  			return ret; - -		dev->clk = devm_clk_get(&pdev->dev, "i2sclk");  	} -	if (IS_ERR(dev->clk)) -		return PTR_ERR(dev->clk); - -	ret = clk_prepare_enable(dev->clk); -	if (ret < 0) -		return ret;  	dev_set_drvdata(&pdev->dev, dev);  	ret = devm_snd_soc_register_component(&pdev->dev, &dw_i2s_component, @@ -606,7 +653,8 @@ static int dw_i2s_probe(struct platform_device *pdev)  	return 0;  err_clk_disable: -	clk_disable_unprepare(dev->clk); +	if (dev->capability & DW_I2S_MASTER) +		clk_disable_unprepare(dev->clk);  	return ret;  } @@ -614,7 +662,8 @@ static int dw_i2s_remove(struct platform_device *pdev)  {  	struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); -	clk_disable_unprepare(dev->clk); +	if (dev->capability & DW_I2S_MASTER) +		clk_disable_unprepare(dev->clk);  	return 0;  } |