sound: Add hisi i2s audio driver
Team:HISI_DRV Feature or Bugfix:Feature Signed-off-by: j00209069 <j00209069@notesmail.huawei.com> Conflicts: arch/arm64/boot/dts/hisilicon/hi3660.dtsi Change-Id: I642e23ec4923f479463a9b83a8b731ce077b449f Signed-off-by: zwx206529 <zwx206529@notesmail.huawei.com> Reviewed-on: http://10.141.107.74:6060/257 Tested-by: public phisik3jenkins <public_phisik3jenkins@notesmail.huawei.com> Reviewed-by: chenfeng 00261379 <puck.chen@hisilicon.com> Signed-off-by: cwx232124 <cwx232124@notesmail.huawei.com> [jstultz: Split out dts bits, removed old hdmi and duplicate adv7511 driver, number of build warning fixes.] Signed-off-by: John Stultz <john.stultz@linaro.org>
This commit is contained in:
@@ -285,6 +285,15 @@ config K3_DMA
|
||||
Support the DMA engine for Hisilicon K3 platform
|
||||
devices.
|
||||
|
||||
config HISI_ASP_DMA
|
||||
tristate "Hisilicon Kirin ASP DMA support"
|
||||
depends on ARCH_HISI
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
help
|
||||
Support the DMA engine for Hisilicon Kirin platform
|
||||
devices.
|
||||
|
||||
config LPC18XX_DMAMUX
|
||||
bool "NXP LPC18xx/43xx DMA MUX for PL080"
|
||||
depends on ARCH_LPC18XX || COMPILE_TEST
|
||||
|
||||
@@ -67,6 +67,7 @@ obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o
|
||||
obj-$(CONFIG_TI_EDMA) += edma.o
|
||||
obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
|
||||
obj-$(CONFIG_ZX_DMA) += zx296702_dma.o
|
||||
obj-$(CONFIG_HISI_ASP_DMA) += hisi_asp_dma.o
|
||||
|
||||
obj-y += qcom/
|
||||
obj-y += xilinx/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,11 @@
|
||||
config SND_I2S_HI6210_I2S
|
||||
tristate "Hisilicon I2S controller"
|
||||
tristate "Hisilicon Hi6210 I2S controller"
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
help
|
||||
Hisilicon I2S
|
||||
|
||||
config SND_I2S_HISI_I2S
|
||||
tristate "Hisilicon 960 I2S controller"
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
help
|
||||
Hisilicon I2S
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
obj-$(CONFIG_SND_I2S_HI6210_I2S) += hi6210-i2s.o
|
||||
obj-$(CONFIG_SND_I2S_HISI_I2S) += hisi-i2s.o
|
||||
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* linux/sound/soc/m8m/hisi_i2s.c - I2S IP driver
|
||||
*
|
||||
* Copyright (C) 2015 Linaro, Ltd
|
||||
* Author: Andy Green <andy.green@linaro.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This driver only deals with S2 interface (BT)
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "hisi-i2s.h"
|
||||
|
||||
struct hisi_i2s {
|
||||
struct device *dev;
|
||||
struct reset_control *rc;
|
||||
int clocks;
|
||||
struct regulator *regu_asp;
|
||||
struct pinctrl *pctrl;
|
||||
struct pinctrl_state *pin_default;
|
||||
struct pinctrl_state *pin_idle;
|
||||
struct clk *asp_subsys_clk;
|
||||
struct snd_soc_dai_driver dai;
|
||||
void __iomem *base;
|
||||
void __iomem *base_syscon;
|
||||
phys_addr_t base_phys;
|
||||
struct snd_dmaengine_dai_dma_data dma_data[2];
|
||||
spinlock_t lock;
|
||||
int rate;
|
||||
int format;
|
||||
int bits;
|
||||
int channels;
|
||||
u32 master;
|
||||
u32 status;
|
||||
};
|
||||
|
||||
static void hisi_bits(struct hisi_i2s *i2s, u32 ofs, u32 reset, u32 set)
|
||||
{
|
||||
u32 val = readl(i2s->base + ofs) & ~reset;
|
||||
|
||||
writel(val | set, i2s->base + ofs);
|
||||
}
|
||||
|
||||
static void hisi_syscon_bits(struct hisi_i2s *i2s, u32 ofs, u32 reset, u32 set)
|
||||
{
|
||||
u32 val = readl(i2s->base_syscon + ofs) & ~reset;
|
||||
|
||||
writel(val | set, i2s->base_syscon + ofs);
|
||||
}
|
||||
|
||||
static int _hisi_i2s_set_fmt(struct hisi_i2s *i2s,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
switch (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
i2s->master = false;
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_CLK_SEL_REG, 0, HI_ASP_CFG_R_CLK_SEL_EN);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
i2s->master = true;
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_CLK_SEL_REG, HI_ASP_CFG_R_CLK_SEL_EN,0);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hisi_i2s_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct hisi_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
// ret = regulator_enable(i2s->regu_asp);
|
||||
if (ret) {
|
||||
dev_err(i2s->dev, "couldn't enable regulators %d\n", ret);
|
||||
ret = -ENOENT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ret = clk_prepare_enable(i2s->asp_subsys_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2s->dev, "couldn't enable clk %d\n", ret);
|
||||
regulator_disable(i2s->regu_asp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* deassert reset on sio_bt*/
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_RST_CTRLDIS_REG, 0,BIT(2)|BIT(6)|BIT(8)|BIT(16));
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_RST_CTRLDIS_REG, 0,0xffffffff);
|
||||
|
||||
/* enable clk before frequency division */
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_GATE_EN_REG, 0,BIT(5)|BIT(6));
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_GATE_EN_REG, 0,0xffffffff);
|
||||
// hisi_syscon_bits(i2s, HI_ASP_CFG_R_SEC_REG, 0,0xffffffff);
|
||||
// hisi_syscon_bits(i2s, 0x5c, 0,0xffffffff);
|
||||
|
||||
/* enable frequency division */
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_GATE_CLKDIV_EN_REG, 0,BIT(2)|BIT(5));
|
||||
|
||||
|
||||
/* select clk */
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_CLK_SEL_REG, HI_ASP_MASK,HI_ASP_CFG_R_CLK_SEL);
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_CLK_SEL_REG, HI_ASP_MASK,0x150010);
|
||||
|
||||
|
||||
/* select clk_div */
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_CLK1_DIV_REG, HI_ASP_MASK,HI_ASP_CFG_R_CLK1_DIV_SEL);
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_CLK4_DIV_REG, HI_ASP_MASK,HI_ASP_CFG_R_CLK4_DIV_SEL);
|
||||
hisi_syscon_bits(i2s, HI_ASP_CFG_R_CLK6_DIV_REG, HI_ASP_MASK,HI_ASP_CFG_R_CLK6_DIV_SEL);
|
||||
|
||||
val = readl(i2s->base_syscon + HI_ASP_CFG_R_SEC_REG);
|
||||
pr_info("****** %s val 0x%x \n", __func__,val);
|
||||
|
||||
#if 1
|
||||
/* sio config */
|
||||
hisi_bits(i2s, HI_ASP_SIO_MODE_REG, HI_ASP_MASK, 0x0);
|
||||
hisi_bits(i2s, HI_ASP_SIO_DATA_WIDTH_SET_REG, HI_ASP_MASK, 0x09);
|
||||
hisi_bits(i2s, HI_ASP_SIO_I2S_POS_MERGE_EN_REG, HI_ASP_MASK, 0x1);
|
||||
hisi_bits(i2s, HI_ASP_SIO_I2S_START_POS_REG, HI_ASP_MASK, 0x0);
|
||||
#endif
|
||||
pr_info("****** %s return \n", __func__);
|
||||
return 0;
|
||||
}
|
||||
void hisi_i2s_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct hisi_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
|
||||
int ret = 0;
|
||||
|
||||
// ret = regulator_disable(i2s->regu_asp);
|
||||
if (ret) {
|
||||
dev_err(i2s->dev, "regulator disable failed!, ret:%d\n", ret);
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(i2s->asp_subsys_clk)) {
|
||||
clk_disable_unprepare(i2s->asp_subsys_clk);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void hisi_i2s_txctrl(struct snd_soc_dai *cpu_dai, int on)
|
||||
{
|
||||
struct hisi_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
|
||||
|
||||
spin_lock(&i2s->lock);
|
||||
|
||||
if (on) {
|
||||
/* enable SIO TX */
|
||||
hisi_bits(i2s, HI_ASP_SIO_CT_SET_REG, 0,
|
||||
HI_ASP_SIO_TX_ENABLE | HI_ASP_SIO_TX_DATA_MERGE | HI_ASP_SIO_TX_FIFO_THRESHOLD |
|
||||
HI_ASP_SIO_RX_ENABLE |HI_ASP_SIO_RX_DATA_MERGE | HI_ASP_SIO_RX_FIFO_THRESHOLD);
|
||||
} else
|
||||
/* disable SIO TX */
|
||||
hisi_bits(i2s, HI_ASP_SIO_CT_CLR_REG, 0, HI_ASP_SIO_TX_ENABLE |HI_ASP_SIO_RX_ENABLE);
|
||||
spin_unlock(&i2s->lock);
|
||||
}
|
||||
|
||||
static void hisi_i2s_rxctrl(struct snd_soc_dai *cpu_dai, int on)
|
||||
{
|
||||
struct hisi_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
|
||||
|
||||
spin_lock(&i2s->lock);
|
||||
if (on)
|
||||
/* enable SIO RX */
|
||||
hisi_bits(i2s, HI_ASP_SIO_CT_SET_REG, 0,
|
||||
HI_ASP_SIO_TX_ENABLE | HI_ASP_SIO_TX_DATA_MERGE | HI_ASP_SIO_TX_FIFO_THRESHOLD |
|
||||
HI_ASP_SIO_RX_ENABLE |HI_ASP_SIO_RX_DATA_MERGE | HI_ASP_SIO_RX_FIFO_THRESHOLD);
|
||||
else
|
||||
/* disable SIO RX */
|
||||
hisi_bits(i2s, HI_ASP_SIO_CT_CLR_REG,0, HI_ASP_SIO_TX_ENABLE |HI_ASP_SIO_RX_ENABLE);
|
||||
spin_unlock(&i2s->lock);
|
||||
}
|
||||
|
||||
static int hisi_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
|
||||
{
|
||||
struct hisi_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
|
||||
|
||||
i2s->format = fmt;
|
||||
i2s->master = (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) ==
|
||||
SND_SOC_DAIFMT_CBS_CFS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct hisi_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
|
||||
|
||||
_hisi_i2s_set_fmt(i2s, substream);
|
||||
|
||||
dma_data->maxburst = 4;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dma_data->addr = i2s->base_phys + HI_ASP_SIO_I2S_DUAL_TX_CHN_REG;
|
||||
else
|
||||
dma_data->addr = i2s->base_phys + HI_ASP_SIO_I2S_DUAL_RX_CHN_REG;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_U16_LE:
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
i2s->bits = 16;
|
||||
dma_data->addr_width = 4;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_U24_LE:
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
i2s->bits = 32;
|
||||
dma_data->addr_width = 4;
|
||||
break;
|
||||
default:
|
||||
dev_err(cpu_dai->dev, "Bad format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
hisi_i2s_rxctrl(cpu_dai, 1);
|
||||
else
|
||||
hisi_i2s_txctrl(cpu_dai, 1);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
hisi_i2s_rxctrl(cpu_dai, 0);
|
||||
else
|
||||
hisi_i2s_txctrl(cpu_dai, 0);
|
||||
break;
|
||||
default:
|
||||
dev_err(cpu_dai->dev, "uknown cmd\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_i2s_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hisi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
snd_soc_dai_init_dma_data(dai,
|
||||
&i2s->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
|
||||
&i2s->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct snd_soc_dai_ops hisi_i2s_dai_ops = {
|
||||
.trigger = hisi_i2s_trigger,
|
||||
.hw_params = hisi_i2s_hw_params,
|
||||
.set_fmt = hisi_i2s_set_fmt,
|
||||
.set_sysclk = hisi_i2s_set_sysclk,
|
||||
.startup = hisi_i2s_startup,
|
||||
.shutdown = hisi_i2s_shutdown,
|
||||
};
|
||||
|
||||
struct snd_soc_dai_driver hisi_i2s_dai_init = {
|
||||
.name = "hisi_i2s",
|
||||
.probe = hisi_i2s_dai_probe,
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_U16_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_U16_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
},
|
||||
.ops = &hisi_i2s_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver hisi_i2s_i2s_comp = {
|
||||
.name = "hisi_i2s-i2s",
|
||||
};
|
||||
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
static const struct snd_pcm_hardware snd_hisi_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_HALF_DUPLEX,
|
||||
.period_bytes_min = 4096,
|
||||
.period_bytes_max = 4096,
|
||||
.periods_min = 4,
|
||||
.periods_max = UINT_MAX,
|
||||
.buffer_bytes_max = SIZE_MAX,
|
||||
};
|
||||
|
||||
static const struct snd_dmaengine_pcm_config hisi_dmaengine_pcm_config = {
|
||||
.pcm_hardware = &snd_hisi_hardware,
|
||||
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
|
||||
.prealloc_buffer_size = 64 * 1024,
|
||||
};
|
||||
|
||||
static int hisi_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct hisi_i2s *i2s;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
i2s = devm_kzalloc(dev,sizeof(*i2s), GFP_KERNEL);
|
||||
if (!i2s)
|
||||
return -ENOMEM;
|
||||
|
||||
i2s->dev = dev;
|
||||
spin_lock_init(&i2s->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
i2s->base_phys = (phys_addr_t)res->start;
|
||||
|
||||
i2s->dai = hisi_i2s_dai_init;
|
||||
dev_set_drvdata(&pdev->dev, i2s);
|
||||
|
||||
i2s->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(i2s->base)) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = PTR_ERR(i2s->base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
i2s->base_syscon = devm_ioremap(dev, res->start, resource_size(res));
|
||||
if (IS_ERR(i2s->base_syscon)) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = PTR_ERR(i2s->base_syscon);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* asp power on */
|
||||
// i2s->regu_asp = devm_regulator_get(dev, "sio-bt");
|
||||
if (IS_ERR(i2s->regu_asp)) {
|
||||
dev_err(dev, "couldn't get regulators !\n");
|
||||
ret = -ENOENT;
|
||||
// return ret;
|
||||
}
|
||||
|
||||
// i2s->asp_subsys_clk = devm_clk_get(dev, "clk_asp_subsys");
|
||||
if (IS_ERR_OR_NULL(i2s->asp_subsys_clk)) {
|
||||
dev_err(dev, "devm_clk_get: clk_asp_subsys not found!\n");
|
||||
// return -EFAULT;
|
||||
}
|
||||
|
||||
/* i2s iomux config */
|
||||
i2s->pctrl = devm_pinctrl_get(dev);
|
||||
if (IS_ERR(i2s->pctrl)) {
|
||||
dev_err(dev, "could not get pinctrl\n");
|
||||
ret = -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2s->pin_default = pinctrl_lookup_state(i2s->pctrl, PINCTRL_STATE_DEFAULT);
|
||||
if (IS_ERR(i2s->pin_default)) {
|
||||
dev_err(dev, "could not get default state (%li)\n" , PTR_ERR(i2s->pin_default));
|
||||
ret = -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* i2s->pin_idle = pinctrl_lookup_state(i2s->pctrl, PINCTRL_STATE_IDLE);
|
||||
if (IS_ERR(i2s->pin_idle)) {
|
||||
dev_err(dev, "could not get idle state (%li)\n", PTR_ERR(i2s->pin_idle));
|
||||
ret = -EIO;
|
||||
return ret;
|
||||
}*/
|
||||
|
||||
if (pinctrl_select_state(i2s->pctrl, i2s->pin_default)) {
|
||||
dev_err(dev, "could not set pins to default state\n");
|
||||
ret = -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
|
||||
&hisi_dmaengine_pcm_config,
|
||||
0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev, &hisi_i2s_i2s_comp,
|
||||
&i2s->dai, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register dai\n");
|
||||
return ret;;
|
||||
}
|
||||
dev_info(&pdev->dev, "Registered as %s\n", i2s->dai.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_i2s_remove(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct hisi_i2s *i2s = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
|
||||
pinctrl_put(i2s->pctrl);
|
||||
// ret = regulator_disable(i2s->regu_asp);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "regulator disable failed!, ret:%d\n", ret);
|
||||
}
|
||||
|
||||
// clk_disable_unprepare(i2s->asp_subsys_clk);
|
||||
// clk_put(i2s->asp_subsys_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id hisi_i2s_dt_ids[] = {
|
||||
{ .compatible = "hisilicon,hisi-i2s" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, hisi_i2s_dt_ids);
|
||||
|
||||
static struct platform_driver hisi_i2s_driver = {
|
||||
.probe = hisi_i2s_probe,
|
||||
.remove = hisi_i2s_remove,
|
||||
.driver = {
|
||||
.name = "hisi_i2s",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = hisi_i2s_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(hisi_i2s_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Hisilicon I2S driver");
|
||||
MODULE_AUTHOR("Andy Green <andy.green@linaro.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* linux/sound/soc/hisilicon/hisi-i2s.h
|
||||
*
|
||||
* Copyright (C) 2015 Linaro, Ltd
|
||||
* Author: Andy Green <andy.green@linaro.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HISI_I2S_H
|
||||
#define _HISI_I2S_H
|
||||
|
||||
enum hisi_bits {
|
||||
HII2S_BITS_16,
|
||||
HII2S_BITS_18,
|
||||
HII2S_BITS_20,
|
||||
HII2S_BITS_24,
|
||||
};
|
||||
|
||||
enum hisi_i2s_rates {
|
||||
HII2S_FS_RATE_8KHZ = 0,
|
||||
HII2S_FS_RATE_16KHZ = 1,
|
||||
HII2S_FS_RATE_32KHZ = 2,
|
||||
HII2S_FS_RATE_48KHZ = 4,
|
||||
HII2S_FS_RATE_96KHZ = 5,
|
||||
HII2S_FS_RATE_192KHZ = 6,
|
||||
};
|
||||
|
||||
#define HI_ASP_CFG_R_RST_CTRLEN_REG 0x0
|
||||
#define HI_ASP_CFG_R_RST_CTRLDIS_REG 0x4
|
||||
#define HI_ASP_CFG_R_GATE_EN_REG 0xC
|
||||
#define HI_ASP_CFG_R_GATE_DIS_REG 0x10
|
||||
#define HI_ASP_CFG_R_GATE_CLKEN_REG 0x14
|
||||
#define HI_ASP_CFG_R_GATE_CLKSTAT_REG 0x18
|
||||
#define HI_ASP_CFG_R_GATE_CLKDIV_EN_REG 0x1C
|
||||
#define HI_ASP_CFG_R_CLK1_DIV_REG 0x20
|
||||
#define HI_ASP_CFG_R_CLK2_DIV_REG 0x24
|
||||
#define HI_ASP_CFG_R_CLK3_DIV_REG 0x28
|
||||
#define HI_ASP_CFG_R_CLK4_DIV_REG 0x2C
|
||||
#define HI_ASP_CFG_R_CLK5_DIV_REG 0x30
|
||||
#define HI_ASP_CFG_R_CLK6_DIV_REG 0x34
|
||||
#define HI_ASP_CFG_R_CLK_SEL_REG 0x38
|
||||
#define HI_ASP_CFG_R_SEC_REG 0x100
|
||||
|
||||
|
||||
#define HI_ASP_SIO_VERSION_REG (0x3C)
|
||||
#define HI_ASP_SIO_MODE_REG (0x40)
|
||||
#define HI_ASP_SIO_INTSTATUS_REG (0x44)
|
||||
#define HI_ASP_SIO_INTCLR_REG (0x48)
|
||||
#define HI_ASP_SIO_I2S_LEFT_XD_REG (0x4C)
|
||||
#define HI_ASP_SIO_I2S_RIGHT_XD_REG (0x50)
|
||||
#define HI_ASP_SIO_I2S_LEFT_RD_REG (0x54)
|
||||
#define HI_ASP_SIO_I2S_RIGHT_RD_REG (0x58)
|
||||
#define HI_ASP_SIO_CT_SET_REG (0x5C)
|
||||
#define HI_ASP_SIO_CT_CLR_REG (0x60)
|
||||
#define HI_ASP_SIO_RX_STA_REG (0x68)
|
||||
#define HI_ASP_SIO_TX_STA_REG (0x6C)
|
||||
#define HI_ASP_SIO_DATA_WIDTH_SET_REG (0x78)
|
||||
#define HI_ASP_SIO_I2S_START_POS_REG (0x7C)
|
||||
#define HI_ASP_SIO_I2S_POS_FLAG_REG (0x80)
|
||||
#define HI_ASP_SIO_SIGNED_EXT_REG (0x84)
|
||||
#define HI_ASP_SIO_I2S_POS_MERGE_EN_REG (0x88)
|
||||
#define HI_ASP_SIO_INTMASK_REG (0x8C)
|
||||
#define HI_ASP_SIO_I2S_DUAL_RX_CHN_REG (0xA0)
|
||||
#define HI_ASP_SIO_I2S_DUAL_TX_CHN_REG (0xC0)
|
||||
|
||||
|
||||
#define HI_ASP_CFG_R_CLK_SEL_EN BIT(2)
|
||||
#define HI_ASP_CFG_R_CLK_SEL 0x140010
|
||||
#define HI_ASP_CFG_R_CLK1_DIV_SEL 0xbcdc9a
|
||||
#define HI_ASP_CFG_R_CLK4_DIV_SEL 0x00ff000f
|
||||
#define HI_ASP_CFG_R_CLK6_DIV_SEL 0x00ff003f
|
||||
#define HI_ASP_CFG_SIO_MODE 0
|
||||
#define HI_ASP_SIO_MODE_SEL_EN BIT(0)
|
||||
#define HI_ASP_MASK 0xffffffff
|
||||
|
||||
#define HI_ASP_SIO_RX_ENABLE BIT(13)
|
||||
#define HI_ASP_SIO_TX_ENABLE BIT(12)
|
||||
#define HI_ASP_SIO_RX_FIFO_DISABLE BIT(11)
|
||||
#define HI_ASP_SIO_TX_FIFO_DISABLE BIT(10)
|
||||
#define HI_ASP_SIO_RX_DATA_MERGE BIT(9)
|
||||
#define HI_ASP_SIO_TX_DATA_MERGE BIT(8)
|
||||
#define HI_ASP_SIO_RX_FIFO_THRESHOLD (0x5 << 4)
|
||||
#define HI_ASP_SIO_TX_FIFO_THRESHOLD (0xB << 0)
|
||||
#define HI_ASP_SIO_RX_FIFO_THRESHOLD_CLR (0xF << 4)
|
||||
#define HI_ASP_SIO_TX_FIFO_THRESHOLD_CLR (0xF << 0)
|
||||
#define HI_ASP_SIO_BURST (0x4)
|
||||
|
||||
|
||||
enum hisi_i2s_formats {
|
||||
HII2S_FORMAT_I2S,
|
||||
HII2S_FORMAT_PCM_STD,
|
||||
HII2S_FORMAT_PCM_USER,
|
||||
HII2S_FORMAT_LEFT_JUST,
|
||||
HII2S_FORMAT_RIGHT_JUST,
|
||||
};
|
||||
|
||||
#endif/* _HISI_I2S_H */
|
||||
@@ -2832,7 +2832,7 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
|
||||
dev_info(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
|
||||
|
||||
component->dai_drv = dai_drv;
|
||||
|
||||
@@ -3161,7 +3161,7 @@ int snd_soc_register_platform(struct device *dev,
|
||||
struct snd_soc_platform *platform;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
|
||||
dev_info(dev, "ASoC: platform register %s\n", dev_name(dev));
|
||||
|
||||
platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
|
||||
if (platform == NULL)
|
||||
@@ -3320,7 +3320,7 @@ int snd_soc_register_codec(struct device *dev,
|
||||
struct snd_soc_dai *dai;
|
||||
int ret, i;
|
||||
|
||||
dev_dbg(dev, "codec register %s\n", dev_name(dev));
|
||||
dev_info(dev, "codec register %s\n", dev_name(dev));
|
||||
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
|
||||
Reference in New Issue
Block a user