brintos

brintos / linux-shallow public Read only

0
0
Text · 16.3 KiB · 3044d9a Raw
613 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * mtk-afe-fe-dais.c  --  Mediatek afe fe dai operator4 *5 * Copyright (c) 2016 MediaTek Inc.6 * Author: Garlic Tseng <garlic.tseng@mediatek.com>7 */8 9#include <linux/io.h>10#include <linux/module.h>11#include <linux/pm_runtime.h>12#include <linux/regmap.h>13#include <sound/soc.h>14#include "mtk-afe-platform-driver.h"15#include <sound/pcm_params.h>16#include "mtk-afe-fe-dai.h"17#include "mtk-base-afe.h"18 19#define AFE_BASE_END_OFFSET 820 21static int mtk_regmap_update_bits(struct regmap *map, int reg,22			   unsigned int mask,23			   unsigned int val, int shift)24{25	if (reg < 0 || WARN_ON_ONCE(shift < 0))26		return 0;27	return regmap_update_bits(map, reg, mask << shift, val << shift);28}29 30static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)31{32	if (reg < 0)33		return 0;34	return regmap_write(map, reg, val);35}36 37int mtk_afe_fe_startup(struct snd_pcm_substream *substream,38		       struct snd_soc_dai *dai)39{40	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);41	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);42	struct snd_pcm_runtime *runtime = substream->runtime;43	int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;44	struct mtk_base_afe_memif *memif = &afe->memif[memif_num];45	const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;46	int ret;47 48	memif->substream = substream;49 50	snd_pcm_hw_constraint_step(substream->runtime, 0,51				   SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);52	/* enable agent */53	mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,54			       1, 0, memif->data->agent_disable_shift);55 56	snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);57 58	/*59	 * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be60	 * smaller than period_size due to AFE's internal buffer.61	 * This easily leads to overrun when avail_min is period_size.62	 * One more period can hold the possible unread buffer.63	 */64	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {65		int periods_max = mtk_afe_hardware->periods_max;66 67		ret = snd_pcm_hw_constraint_minmax(runtime,68						   SNDRV_PCM_HW_PARAM_PERIODS,69						   3, periods_max);70		if (ret < 0) {71			dev_err(afe->dev, "hw_constraint_minmax failed\n");72			return ret;73		}74	}75 76	ret = snd_pcm_hw_constraint_integer(runtime,77					    SNDRV_PCM_HW_PARAM_PERIODS);78	if (ret < 0)79		dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");80 81	/* dynamic allocate irq to memif */82	if (memif->irq_usage < 0) {83		int irq_id = mtk_dynamic_irq_acquire(afe);84 85		if (irq_id != afe->irqs_size) {86			/* link */87			memif->irq_usage = irq_id;88		} else {89			dev_err(afe->dev, "%s() error: no more asys irq\n",90				__func__);91			ret = -EBUSY;92		}93	}94	return ret;95}96EXPORT_SYMBOL_GPL(mtk_afe_fe_startup);97 98void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,99			 struct snd_soc_dai *dai)100{101	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);102	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);103	struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id];104	int irq_id;105 106	irq_id = memif->irq_usage;107 108	mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,109			       1, 1, memif->data->agent_disable_shift);110 111	if (!memif->const_irq) {112		mtk_dynamic_irq_release(afe, irq_id);113		memif->irq_usage = -1;114		memif->substream = NULL;115	}116}117EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown);118 119int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,120			 struct snd_pcm_hw_params *params,121			 struct snd_soc_dai *dai)122{123	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);124	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);125	int id = snd_soc_rtd_to_cpu(rtd, 0)->id;126	struct mtk_base_afe_memif *memif = &afe->memif[id];127	int ret;128	unsigned int channels = params_channels(params);129	unsigned int rate = params_rate(params);130	snd_pcm_format_t format = params_format(params);131 132	if (afe->request_dram_resource)133		afe->request_dram_resource(afe->dev);134 135	dev_dbg(afe->dev, "%s(), %s, ch %d, rate %d, fmt %d, dma_addr %pad, dma_area %p, dma_bytes 0x%zx\n",136		__func__, memif->data->name,137		channels, rate, format,138		&substream->runtime->dma_addr,139		substream->runtime->dma_area,140		substream->runtime->dma_bytes);141 142	memset_io((void __force __iomem *)substream->runtime->dma_area, 0,143		  substream->runtime->dma_bytes);144 145	/* set addr */146	ret = mtk_memif_set_addr(afe, id,147				 substream->runtime->dma_area,148				 substream->runtime->dma_addr,149				 substream->runtime->dma_bytes);150	if (ret) {151		dev_err(afe->dev, "%s(), error, id %d, set addr, ret %d\n",152			__func__, id, ret);153		return ret;154	}155 156	/* set channel */157	ret = mtk_memif_set_channel(afe, id, channels);158	if (ret) {159		dev_err(afe->dev, "%s(), error, id %d, set channel %d, ret %d\n",160			__func__, id, channels, ret);161		return ret;162	}163 164	/* set rate */165	ret = mtk_memif_set_rate_substream(substream, id, rate);166	if (ret) {167		dev_err(afe->dev, "%s(), error, id %d, set rate %d, ret %d\n",168			__func__, id, rate, ret);169		return ret;170	}171 172	/* set format */173	ret = mtk_memif_set_format(afe, id, format);174	if (ret) {175		dev_err(afe->dev, "%s(), error, id %d, set format %d, ret %d\n",176			__func__, id, format, ret);177		return ret;178	}179 180	return 0;181}182EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params);183 184int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,185		       struct snd_soc_dai *dai)186{187	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);188 189	if (afe->release_dram_resource)190		afe->release_dram_resource(afe->dev);191 192	return 0;193}194EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);195 196int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,197		       struct snd_soc_dai *dai)198{199	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);200	struct snd_pcm_runtime * const runtime = substream->runtime;201	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);202	int id = snd_soc_rtd_to_cpu(rtd, 0)->id;203	struct mtk_base_afe_memif *memif = &afe->memif[id];204	struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];205	const struct mtk_base_irq_data *irq_data = irqs->irq_data;206	unsigned int counter = runtime->period_size;207	int fs;208	int ret;209 210	dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);211 212	switch (cmd) {213	case SNDRV_PCM_TRIGGER_START:214	case SNDRV_PCM_TRIGGER_RESUME:215		ret = mtk_memif_set_enable(afe, id);216		if (ret) {217			dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",218				__func__, id, ret);219			return ret;220		}221 222		/* set irq counter */223		mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,224				       irq_data->irq_cnt_maskbit, counter,225				       irq_data->irq_cnt_shift);226 227		/* set irq fs */228		fs = afe->irq_fs(substream, runtime->rate);229 230		if (fs < 0)231			return -EINVAL;232 233		mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,234				       irq_data->irq_fs_maskbit, fs,235				       irq_data->irq_fs_shift);236 237		/* enable interrupt */238		mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,239				       1, 1, irq_data->irq_en_shift);240 241		return 0;242	case SNDRV_PCM_TRIGGER_STOP:243	case SNDRV_PCM_TRIGGER_SUSPEND:244		ret = mtk_memif_set_disable(afe, id);245		if (ret) {246			dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",247				__func__, id, ret);248		}249 250		/* disable interrupt */251		mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,252				       1, 0, irq_data->irq_en_shift);253		/* and clear pending IRQ */254		mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,255				 1 << irq_data->irq_clr_shift);256		return ret;257	default:258		return -EINVAL;259	}260}261EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger);262 263int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,264		       struct snd_soc_dai *dai)265{266	struct snd_soc_pcm_runtime *rtd  = snd_soc_substream_to_rtd(substream);267	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);268	int id = snd_soc_rtd_to_cpu(rtd, 0)->id;269	int pbuf_size;270 271	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {272		if (afe->get_memif_pbuf_size) {273			pbuf_size = afe->get_memif_pbuf_size(substream);274			mtk_memif_set_pbuf_size(afe, id, pbuf_size);275		}276	}277	return 0;278}279EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);280 281const struct snd_soc_dai_ops mtk_afe_fe_ops = {282	.startup	= mtk_afe_fe_startup,283	.shutdown	= mtk_afe_fe_shutdown,284	.hw_params	= mtk_afe_fe_hw_params,285	.hw_free	= mtk_afe_fe_hw_free,286	.prepare	= mtk_afe_fe_prepare,287	.trigger	= mtk_afe_fe_trigger,288};289EXPORT_SYMBOL_GPL(mtk_afe_fe_ops);290 291int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe)292{293	int i;294 295	mutex_lock(&afe->irq_alloc_lock);296	for (i = 0; i < afe->irqs_size; ++i) {297		if (afe->irqs[i].irq_occupyed == 0) {298			afe->irqs[i].irq_occupyed = 1;299			mutex_unlock(&afe->irq_alloc_lock);300			return i;301		}302	}303	mutex_unlock(&afe->irq_alloc_lock);304	return afe->irqs_size;305}306EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire);307 308int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id)309{310	mutex_lock(&afe->irq_alloc_lock);311	if (irq_id >= 0 && irq_id < afe->irqs_size) {312		afe->irqs[irq_id].irq_occupyed = 0;313		mutex_unlock(&afe->irq_alloc_lock);314		return 0;315	}316	mutex_unlock(&afe->irq_alloc_lock);317	return -EINVAL;318}319EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);320 321int mtk_afe_suspend(struct snd_soc_component *component)322{323	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);324	struct device *dev = afe->dev;325	struct regmap *regmap = afe->regmap;326	int i;327 328	if (pm_runtime_status_suspended(dev) || afe->suspended)329		return 0;330 331	if (!afe->reg_back_up)332		afe->reg_back_up =333			devm_kcalloc(dev, afe->reg_back_up_list_num,334				     sizeof(unsigned int), GFP_KERNEL);335 336	if (afe->reg_back_up) {337		for (i = 0; i < afe->reg_back_up_list_num; i++)338			regmap_read(regmap, afe->reg_back_up_list[i],339				    &afe->reg_back_up[i]);340	}341 342	afe->suspended = true;343	afe->runtime_suspend(dev);344	return 0;345}346EXPORT_SYMBOL_GPL(mtk_afe_suspend);347 348int mtk_afe_resume(struct snd_soc_component *component)349{350	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);351	struct device *dev = afe->dev;352	struct regmap *regmap = afe->regmap;353	int i;354 355	if (pm_runtime_status_suspended(dev) || !afe->suspended)356		return 0;357 358	afe->runtime_resume(dev);359 360	if (!afe->reg_back_up) {361		dev_dbg(dev, "%s no reg_backup\n", __func__);362	} else {363		for (i = 0; i < afe->reg_back_up_list_num; i++)364			mtk_regmap_write(regmap, afe->reg_back_up_list[i],365					 afe->reg_back_up[i]);366	}367 368	afe->suspended = false;369	return 0;370}371EXPORT_SYMBOL_GPL(mtk_afe_resume);372 373int mtk_memif_set_enable(struct mtk_base_afe *afe, int id)374{375	struct mtk_base_afe_memif *memif = &afe->memif[id];376 377	if (memif->data->enable_shift < 0) {378		dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",379			 __func__, id);380		return 0;381	}382	return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,383				      1, 1, memif->data->enable_shift);384}385EXPORT_SYMBOL_GPL(mtk_memif_set_enable);386 387int mtk_memif_set_disable(struct mtk_base_afe *afe, int id)388{389	struct mtk_base_afe_memif *memif = &afe->memif[id];390 391	if (memif->data->enable_shift < 0) {392		dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",393			 __func__, id);394		return 0;395	}396	return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,397				      1, 0, memif->data->enable_shift);398}399EXPORT_SYMBOL_GPL(mtk_memif_set_disable);400 401int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,402		       unsigned char *dma_area,403		       dma_addr_t dma_addr,404		       size_t dma_bytes)405{406	struct mtk_base_afe_memif *memif = &afe->memif[id];407	int msb_at_bit33 = upper_32_bits(dma_addr) ? 1 : 0;408	unsigned int phys_buf_addr = lower_32_bits(dma_addr);409	unsigned int phys_buf_addr_upper_32 = upper_32_bits(dma_addr);410 411	memif->dma_area = dma_area;412	memif->dma_addr = dma_addr;413	memif->dma_bytes = dma_bytes;414 415	/* start */416	mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,417			 phys_buf_addr);418	/* end */419	if (memif->data->reg_ofs_end)420		mtk_regmap_write(afe->regmap,421				 memif->data->reg_ofs_end,422				 phys_buf_addr + dma_bytes - 1);423	else424		mtk_regmap_write(afe->regmap,425				 memif->data->reg_ofs_base +426				 AFE_BASE_END_OFFSET,427				 phys_buf_addr + dma_bytes - 1);428 429	/* set start, end, upper 32 bits */430	if (memif->data->reg_ofs_base_msb) {431		mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base_msb,432				 phys_buf_addr_upper_32);433		mtk_regmap_write(afe->regmap,434				 memif->data->reg_ofs_end_msb,435				 phys_buf_addr_upper_32);436	}437 438	/*439	 * set MSB to 33-bit, for memif address440	 * only for memif base address, if msb_end_reg exists441	 */442	if (memif->data->msb_reg)443		mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,444				       1, msb_at_bit33, memif->data->msb_shift);445 446	/* set MSB to 33-bit, for memif end address */447	if (memif->data->msb_end_reg)448		mtk_regmap_update_bits(afe->regmap, memif->data->msb_end_reg,449				       1, msb_at_bit33,450				       memif->data->msb_end_shift);451 452	return 0;453}454EXPORT_SYMBOL_GPL(mtk_memif_set_addr);455 456int mtk_memif_set_channel(struct mtk_base_afe *afe,457			  int id, unsigned int channel)458{459	struct mtk_base_afe_memif *memif = &afe->memif[id];460	unsigned int mono;461 462	if (memif->data->mono_shift < 0)463		return 0;464 465	if (memif->data->quad_ch_mask) {466		unsigned int quad_ch = (channel == 4) ? 1 : 0;467 468		mtk_regmap_update_bits(afe->regmap, memif->data->quad_ch_reg,469				       memif->data->quad_ch_mask,470				       quad_ch, memif->data->quad_ch_shift);471	}472 473	if (memif->data->mono_invert)474		mono = (channel == 1) ? 0 : 1;475	else476		mono = (channel == 1) ? 1 : 0;477 478	/* for specific configuration of memif mono mode */479	if (memif->data->int_odd_flag_reg)480		mtk_regmap_update_bits(afe->regmap,481				       memif->data->int_odd_flag_reg,482				       1, mono,483				       memif->data->int_odd_flag_shift);484 485	return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,486				      1, mono, memif->data->mono_shift);487}488EXPORT_SYMBOL_GPL(mtk_memif_set_channel);489 490static int mtk_memif_set_rate_fs(struct mtk_base_afe *afe,491				 int id, int fs)492{493	struct mtk_base_afe_memif *memif = &afe->memif[id];494 495	if (memif->data->fs_shift >= 0)496		mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,497				       memif->data->fs_maskbit,498				       fs, memif->data->fs_shift);499 500	return 0;501}502 503int mtk_memif_set_rate(struct mtk_base_afe *afe,504		       int id, unsigned int rate)505{506	int fs = 0;507 508	if (!afe->get_dai_fs) {509		dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n",510			__func__);511		return -EINVAL;512	}513 514	fs = afe->get_dai_fs(afe, id, rate);515 516	if (fs < 0)517		return -EINVAL;518 519	return mtk_memif_set_rate_fs(afe, id, fs);520}521EXPORT_SYMBOL_GPL(mtk_memif_set_rate);522 523int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,524				 int id, unsigned int rate)525{526	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);527	struct snd_soc_component *component =528		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);529	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);530 531	int fs = 0;532 533	if (!afe->memif_fs) {534		dev_err(afe->dev, "%s(), error, afe->memif_fs == NULL\n",535			__func__);536		return -EINVAL;537	}538 539	fs = afe->memif_fs(substream, rate);540 541	if (fs < 0)542		return -EINVAL;543 544	return mtk_memif_set_rate_fs(afe, id, fs);545}546EXPORT_SYMBOL_GPL(mtk_memif_set_rate_substream);547 548int mtk_memif_set_format(struct mtk_base_afe *afe,549			 int id, snd_pcm_format_t format)550{551	struct mtk_base_afe_memif *memif = &afe->memif[id];552	int hd_audio = 0;553	int hd_align = 0;554 555	/* set hd mode */556	switch (format) {557	case SNDRV_PCM_FORMAT_S16_LE:558	case SNDRV_PCM_FORMAT_U16_LE:559		hd_audio = 0;560		break;561	case SNDRV_PCM_FORMAT_S32_LE:562	case SNDRV_PCM_FORMAT_U32_LE:563		if (afe->memif_32bit_supported) {564			hd_audio = 2;565			hd_align = 0;566		} else {567			hd_audio = 1;568			hd_align = 1;569		}570		break;571	case SNDRV_PCM_FORMAT_S24_LE:572	case SNDRV_PCM_FORMAT_U24_LE:573		hd_audio = 1;574		break;575	default:576		dev_err(afe->dev, "%s() error: unsupported format %d\n",577			__func__, format);578		break;579	}580 581	mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,582			       0x3, hd_audio, memif->data->hd_shift);583 584	mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,585			       0x1, hd_align, memif->data->hd_align_mshift);586 587	return 0;588}589EXPORT_SYMBOL_GPL(mtk_memif_set_format);590 591int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe,592			    int id, int pbuf_size)593{594	const struct mtk_base_memif_data *memif_data = afe->memif[id].data;595 596	if (memif_data->pbuf_mask == 0 || memif_data->minlen_mask == 0)597		return 0;598 599	mtk_regmap_update_bits(afe->regmap, memif_data->pbuf_reg,600			       memif_data->pbuf_mask,601			       pbuf_size, memif_data->pbuf_shift);602 603	mtk_regmap_update_bits(afe->regmap, memif_data->minlen_reg,604			       memif_data->minlen_mask,605			       pbuf_size, memif_data->minlen_shift);606	return 0;607}608EXPORT_SYMBOL_GPL(mtk_memif_set_pbuf_size);609 610MODULE_DESCRIPTION("Mediatek simple fe dai operator");611MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");612MODULE_LICENSE("GPL v2");613