Path: blob/master/sound/soc/mediatek/common/mtk-afe-fe-dai.c
26450 views
// SPDX-License-Identifier: GPL-2.01/*2* mtk-afe-fe-dais.c -- Mediatek afe fe dai operator3*4* Copyright (c) 2016 MediaTek Inc.5* Author: Garlic Tseng <[email protected]>6*/78#include <linux/io.h>9#include <linux/module.h>10#include <linux/pm_runtime.h>11#include <linux/regmap.h>12#include <sound/soc.h>13#include "mtk-afe-platform-driver.h"14#include <sound/pcm_params.h>15#include "mtk-afe-fe-dai.h"16#include "mtk-base-afe.h"1718#define AFE_BASE_END_OFFSET 81920static int mtk_regmap_update_bits(struct regmap *map, int reg,21unsigned int mask,22unsigned int val, int shift)23{24if (reg < 0 || WARN_ON_ONCE(shift < 0))25return 0;26return regmap_update_bits(map, reg, mask << shift, val << shift);27}2829static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)30{31if (reg < 0)32return 0;33return regmap_write(map, reg, val);34}3536int mtk_afe_fe_startup(struct snd_pcm_substream *substream,37struct snd_soc_dai *dai)38{39struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);40struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);41struct snd_pcm_runtime *runtime = substream->runtime;42int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;43struct mtk_base_afe_memif *memif = &afe->memif[memif_num];44const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;45int ret;4647memif->substream = substream;4849snd_pcm_hw_constraint_step(substream->runtime, 0,50SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);51/* enable agent */52mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,531, 0, memif->data->agent_disable_shift);5455snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);5657/*58* Capture cannot use ping-pong buffer since hw_ptr at IRQ may be59* smaller than period_size due to AFE's internal buffer.60* This easily leads to overrun when avail_min is period_size.61* One more period can hold the possible unread buffer.62*/63if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {64int periods_max = mtk_afe_hardware->periods_max;6566ret = snd_pcm_hw_constraint_minmax(runtime,67SNDRV_PCM_HW_PARAM_PERIODS,683, periods_max);69if (ret < 0) {70dev_err(afe->dev, "hw_constraint_minmax failed\n");71return ret;72}73}7475ret = snd_pcm_hw_constraint_integer(runtime,76SNDRV_PCM_HW_PARAM_PERIODS);77if (ret < 0)78dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");7980/* dynamic allocate irq to memif */81if (memif->irq_usage < 0) {82int irq_id = mtk_dynamic_irq_acquire(afe);8384if (irq_id != afe->irqs_size) {85/* link */86memif->irq_usage = irq_id;87} else {88dev_err(afe->dev, "%s() error: no more asys irq\n",89__func__);90ret = -EBUSY;91}92}93return ret;94}95EXPORT_SYMBOL_GPL(mtk_afe_fe_startup);9697void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,98struct snd_soc_dai *dai)99{100struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);101struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);102struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id];103int irq_id;104105irq_id = memif->irq_usage;106107mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,1081, 1, memif->data->agent_disable_shift);109110if (!memif->const_irq) {111mtk_dynamic_irq_release(afe, irq_id);112memif->irq_usage = -1;113memif->substream = NULL;114}115}116EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown);117118int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,119struct snd_pcm_hw_params *params,120struct snd_soc_dai *dai)121{122struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);123struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);124int id = snd_soc_rtd_to_cpu(rtd, 0)->id;125struct mtk_base_afe_memif *memif = &afe->memif[id];126int ret;127unsigned int channels = params_channels(params);128unsigned int rate = params_rate(params);129snd_pcm_format_t format = params_format(params);130131if (afe->request_dram_resource)132afe->request_dram_resource(afe->dev);133134dev_dbg(afe->dev, "%s(), %s, ch %d, rate %d, fmt %d, dma_addr %pad, dma_area %p, dma_bytes 0x%zx\n",135__func__, memif->data->name,136channels, rate, format,137&substream->runtime->dma_addr,138substream->runtime->dma_area,139substream->runtime->dma_bytes);140141memset_io((void __force __iomem *)substream->runtime->dma_area, 0,142substream->runtime->dma_bytes);143144/* set addr */145ret = mtk_memif_set_addr(afe, id,146substream->runtime->dma_area,147substream->runtime->dma_addr,148substream->runtime->dma_bytes);149if (ret) {150dev_err(afe->dev, "%s(), error, id %d, set addr, ret %d\n",151__func__, id, ret);152return ret;153}154155/* set channel */156ret = mtk_memif_set_channel(afe, id, channels);157if (ret) {158dev_err(afe->dev, "%s(), error, id %d, set channel %d, ret %d\n",159__func__, id, channels, ret);160return ret;161}162163/* set rate */164ret = mtk_memif_set_rate_substream(substream, id, rate);165if (ret) {166dev_err(afe->dev, "%s(), error, id %d, set rate %d, ret %d\n",167__func__, id, rate, ret);168return ret;169}170171/* set format */172ret = mtk_memif_set_format(afe, id, format);173if (ret) {174dev_err(afe->dev, "%s(), error, id %d, set format %d, ret %d\n",175__func__, id, format, ret);176return ret;177}178179return 0;180}181EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params);182183int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,184struct snd_soc_dai *dai)185{186struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);187188if (afe->release_dram_resource)189afe->release_dram_resource(afe->dev);190191return 0;192}193EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);194195int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,196struct snd_soc_dai *dai)197{198struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);199struct snd_pcm_runtime * const runtime = substream->runtime;200struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);201int id = snd_soc_rtd_to_cpu(rtd, 0)->id;202struct mtk_base_afe_memif *memif = &afe->memif[id];203struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];204const struct mtk_base_irq_data *irq_data = irqs->irq_data;205unsigned int counter = runtime->period_size;206int fs;207int ret;208209dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);210211switch (cmd) {212case SNDRV_PCM_TRIGGER_START:213case SNDRV_PCM_TRIGGER_RESUME:214ret = mtk_memif_set_enable(afe, id);215if (ret) {216dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",217__func__, id, ret);218return ret;219}220221/* set irq counter */222mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,223irq_data->irq_cnt_maskbit, counter,224irq_data->irq_cnt_shift);225226/* set irq fs */227fs = afe->irq_fs(substream, runtime->rate);228229if (fs < 0)230return -EINVAL;231232mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,233irq_data->irq_fs_maskbit, fs,234irq_data->irq_fs_shift);235236/* enable interrupt */237mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,2381, 1, irq_data->irq_en_shift);239240return 0;241case SNDRV_PCM_TRIGGER_STOP:242case SNDRV_PCM_TRIGGER_SUSPEND:243ret = mtk_memif_set_disable(afe, id);244if (ret) {245dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",246__func__, id, ret);247}248249/* disable interrupt */250mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,2511, 0, irq_data->irq_en_shift);252/* and clear pending IRQ */253mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,2541 << irq_data->irq_clr_shift);255return ret;256default:257return -EINVAL;258}259}260EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger);261262int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,263struct snd_soc_dai *dai)264{265struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);266struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);267int id = snd_soc_rtd_to_cpu(rtd, 0)->id;268int pbuf_size;269270if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {271if (afe->get_memif_pbuf_size) {272pbuf_size = afe->get_memif_pbuf_size(substream);273mtk_memif_set_pbuf_size(afe, id, pbuf_size);274}275}276return 0;277}278EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);279280const struct snd_soc_dai_ops mtk_afe_fe_ops = {281.startup = mtk_afe_fe_startup,282.shutdown = mtk_afe_fe_shutdown,283.hw_params = mtk_afe_fe_hw_params,284.hw_free = mtk_afe_fe_hw_free,285.prepare = mtk_afe_fe_prepare,286.trigger = mtk_afe_fe_trigger,287};288EXPORT_SYMBOL_GPL(mtk_afe_fe_ops);289290int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe)291{292int i;293294mutex_lock(&afe->irq_alloc_lock);295for (i = 0; i < afe->irqs_size; ++i) {296if (afe->irqs[i].irq_occupyed == 0) {297afe->irqs[i].irq_occupyed = 1;298mutex_unlock(&afe->irq_alloc_lock);299return i;300}301}302mutex_unlock(&afe->irq_alloc_lock);303return afe->irqs_size;304}305EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire);306307int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id)308{309mutex_lock(&afe->irq_alloc_lock);310if (irq_id >= 0 && irq_id < afe->irqs_size) {311afe->irqs[irq_id].irq_occupyed = 0;312mutex_unlock(&afe->irq_alloc_lock);313return 0;314}315mutex_unlock(&afe->irq_alloc_lock);316return -EINVAL;317}318EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);319320int mtk_afe_suspend(struct snd_soc_component *component)321{322struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);323struct device *dev = afe->dev;324struct regmap *regmap = afe->regmap;325int i;326327if (pm_runtime_status_suspended(dev) || afe->suspended)328return 0;329330if (!afe->reg_back_up)331afe->reg_back_up =332devm_kcalloc(dev, afe->reg_back_up_list_num,333sizeof(unsigned int), GFP_KERNEL);334335if (afe->reg_back_up) {336for (i = 0; i < afe->reg_back_up_list_num; i++)337regmap_read(regmap, afe->reg_back_up_list[i],338&afe->reg_back_up[i]);339}340341afe->suspended = true;342afe->runtime_suspend(dev);343return 0;344}345EXPORT_SYMBOL_GPL(mtk_afe_suspend);346347int mtk_afe_resume(struct snd_soc_component *component)348{349struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);350struct device *dev = afe->dev;351struct regmap *regmap = afe->regmap;352int i;353354if (pm_runtime_status_suspended(dev) || !afe->suspended)355return 0;356357afe->runtime_resume(dev);358359if (!afe->reg_back_up) {360dev_dbg(dev, "%s no reg_backup\n", __func__);361} else {362for (i = 0; i < afe->reg_back_up_list_num; i++)363mtk_regmap_write(regmap, afe->reg_back_up_list[i],364afe->reg_back_up[i]);365}366367afe->suspended = false;368return 0;369}370EXPORT_SYMBOL_GPL(mtk_afe_resume);371372int mtk_memif_set_enable(struct mtk_base_afe *afe, int id)373{374struct mtk_base_afe_memif *memif = &afe->memif[id];375376if (memif->data->enable_shift < 0) {377dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",378__func__, id);379return 0;380}381return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,3821, 1, memif->data->enable_shift);383}384EXPORT_SYMBOL_GPL(mtk_memif_set_enable);385386int mtk_memif_set_disable(struct mtk_base_afe *afe, int id)387{388struct mtk_base_afe_memif *memif = &afe->memif[id];389390if (memif->data->enable_shift < 0) {391dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",392__func__, id);393return 0;394}395return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,3961, 0, memif->data->enable_shift);397}398EXPORT_SYMBOL_GPL(mtk_memif_set_disable);399400int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,401unsigned char *dma_area,402dma_addr_t dma_addr,403size_t dma_bytes)404{405struct mtk_base_afe_memif *memif = &afe->memif[id];406int msb_at_bit33 = upper_32_bits(dma_addr) ? 1 : 0;407unsigned int phys_buf_addr = lower_32_bits(dma_addr);408unsigned int phys_buf_addr_upper_32 = upper_32_bits(dma_addr);409410memif->dma_area = dma_area;411memif->dma_addr = dma_addr;412memif->dma_bytes = dma_bytes;413414/* start */415mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,416phys_buf_addr);417/* end */418if (memif->data->reg_ofs_end)419mtk_regmap_write(afe->regmap,420memif->data->reg_ofs_end,421phys_buf_addr + dma_bytes - 1);422else423mtk_regmap_write(afe->regmap,424memif->data->reg_ofs_base +425AFE_BASE_END_OFFSET,426phys_buf_addr + dma_bytes - 1);427428/* set start, end, upper 32 bits */429if (memif->data->reg_ofs_base_msb) {430mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base_msb,431phys_buf_addr_upper_32);432mtk_regmap_write(afe->regmap,433memif->data->reg_ofs_end_msb,434phys_buf_addr_upper_32);435}436437/*438* set MSB to 33-bit, for memif address439* only for memif base address, if msb_end_reg exists440*/441if (memif->data->msb_reg)442mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,4431, msb_at_bit33, memif->data->msb_shift);444445/* set MSB to 33-bit, for memif end address */446if (memif->data->msb_end_reg)447mtk_regmap_update_bits(afe->regmap, memif->data->msb_end_reg,4481, msb_at_bit33,449memif->data->msb_end_shift);450451return 0;452}453EXPORT_SYMBOL_GPL(mtk_memif_set_addr);454455int mtk_memif_set_channel(struct mtk_base_afe *afe,456int id, unsigned int channel)457{458struct mtk_base_afe_memif *memif = &afe->memif[id];459unsigned int mono;460461if (memif->data->mono_shift < 0)462return 0;463464if (memif->data->quad_ch_mask) {465unsigned int quad_ch = (channel == 4) ? 1 : 0;466467mtk_regmap_update_bits(afe->regmap, memif->data->quad_ch_reg,468memif->data->quad_ch_mask,469quad_ch, memif->data->quad_ch_shift);470}471472if (memif->data->mono_invert)473mono = (channel == 1) ? 0 : 1;474else475mono = (channel == 1) ? 1 : 0;476477/* for specific configuration of memif mono mode */478if (memif->data->int_odd_flag_reg)479mtk_regmap_update_bits(afe->regmap,480memif->data->int_odd_flag_reg,4811, mono,482memif->data->int_odd_flag_shift);483484return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,4851, mono, memif->data->mono_shift);486}487EXPORT_SYMBOL_GPL(mtk_memif_set_channel);488489static int mtk_memif_set_rate_fs(struct mtk_base_afe *afe,490int id, int fs)491{492struct mtk_base_afe_memif *memif = &afe->memif[id];493494if (memif->data->fs_shift >= 0)495mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,496memif->data->fs_maskbit,497fs, memif->data->fs_shift);498499return 0;500}501502int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,503int id, unsigned int rate)504{505struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);506struct snd_soc_component *component =507snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);508struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);509510int fs = 0;511512if (!afe->memif_fs) {513dev_err(afe->dev, "%s(), error, afe->memif_fs == NULL\n",514__func__);515return -EINVAL;516}517518fs = afe->memif_fs(substream, rate);519520if (fs < 0)521return -EINVAL;522523return mtk_memif_set_rate_fs(afe, id, fs);524}525EXPORT_SYMBOL_GPL(mtk_memif_set_rate_substream);526527int mtk_memif_set_format(struct mtk_base_afe *afe,528int id, snd_pcm_format_t format)529{530struct mtk_base_afe_memif *memif = &afe->memif[id];531int hd_audio = 0;532int hd_align = 0;533534/* set hd mode */535switch (format) {536case SNDRV_PCM_FORMAT_S16_LE:537case SNDRV_PCM_FORMAT_U16_LE:538hd_audio = 0;539break;540case SNDRV_PCM_FORMAT_S32_LE:541case SNDRV_PCM_FORMAT_U32_LE:542if (afe->memif_32bit_supported) {543hd_audio = 2;544hd_align = 0;545} else {546hd_audio = 1;547hd_align = 1;548}549break;550case SNDRV_PCM_FORMAT_S24_LE:551case SNDRV_PCM_FORMAT_U24_LE:552hd_audio = 1;553break;554default:555dev_err(afe->dev, "%s() error: unsupported format %d\n",556__func__, format);557break;558}559560mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,5610x3, hd_audio, memif->data->hd_shift);562563mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,5640x1, hd_align, memif->data->hd_align_mshift);565566return 0;567}568EXPORT_SYMBOL_GPL(mtk_memif_set_format);569570int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe,571int id, int pbuf_size)572{573const struct mtk_base_memif_data *memif_data = afe->memif[id].data;574575if (memif_data->pbuf_mask == 0 || memif_data->minlen_mask == 0)576return 0;577578mtk_regmap_update_bits(afe->regmap, memif_data->pbuf_reg,579memif_data->pbuf_mask,580pbuf_size, memif_data->pbuf_shift);581582mtk_regmap_update_bits(afe->regmap, memif_data->minlen_reg,583memif_data->minlen_mask,584pbuf_size, memif_data->minlen_shift);585return 0;586}587EXPORT_SYMBOL_GPL(mtk_memif_set_pbuf_size);588589MODULE_DESCRIPTION("Mediatek simple fe dai operator");590MODULE_AUTHOR("Garlic Tseng <[email protected]>");591MODULE_LICENSE("GPL v2");592593594