You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge remote-tracking branches 'asoc/topic/headers', 'asoc/topic/intel', 'asoc/topic/jz4740', 'asoc/topic/max98090', 'asoc/topic/max98095', 'asoc/topic/mc13783' and 'asoc/topic/multicodec' into asoc-next
This commit is contained in:
@@ -10,6 +10,9 @@ Optional properties:
|
||||
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
|
||||
|
||||
Sub-nodes:
|
||||
- codec: Contain the Audio Codec node.
|
||||
- adc-port: Contain PMIC SSI port number used for ADC.
|
||||
- dac-port: Contain PMIC SSI port number used for DAC.
|
||||
- leds : Contain the led nodes and initial register values in property
|
||||
"led-control". Number of register depends of used IC, for MC13783 is 6,
|
||||
for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
MAX98095 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "maxim,max98095".
|
||||
|
||||
- reg : The I2C address of the device.
|
||||
|
||||
Example:
|
||||
|
||||
max98095: codec@11 {
|
||||
compatible = "maxim,max98095";
|
||||
reg = <0x11>;
|
||||
};
|
||||
@@ -22,8 +22,6 @@ enum jz4740_dma_request_type {
|
||||
JZ4740_DMA_TYPE_UART_RECEIVE = 21,
|
||||
JZ4740_DMA_TYPE_SPI_TRANSMIT = 22,
|
||||
JZ4740_DMA_TYPE_SPI_RECEIVE = 23,
|
||||
JZ4740_DMA_TYPE_AIC_TRANSMIT = 24,
|
||||
JZ4740_DMA_TYPE_AIC_RECEIVE = 25,
|
||||
JZ4740_DMA_TYPE_MMC_TRANSMIT = 26,
|
||||
JZ4740_DMA_TYPE_MMC_RECEIVE = 27,
|
||||
JZ4740_DMA_TYPE_TCU = 28,
|
||||
|
||||
@@ -425,6 +425,15 @@ static struct platform_device qi_lb60_audio_device = {
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table qi_lb60_audio_gpio_table = {
|
||||
.dev_id = "qi-lb60-audio",
|
||||
.table = {
|
||||
GPIO_LOOKUP("Bank B", 29, "snd", 0),
|
||||
GPIO_LOOKUP("Bank D", 4, "amp", 0),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *jz_platform_devices[] __initdata = {
|
||||
&jz4740_udc_device,
|
||||
&jz4740_udc_xceiv_device,
|
||||
@@ -461,6 +470,8 @@ static int __init qi_lb60_init_platform_devices(void)
|
||||
jz4740_adc_device.dev.platform_data = &qi_lb60_battery_pdata;
|
||||
jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata;
|
||||
|
||||
gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
|
||||
|
||||
jz4740_serial_device_register();
|
||||
|
||||
spi_register_board_info(qi_lb60_spi_board_info,
|
||||
|
||||
@@ -673,9 +673,13 @@ int mc13xxx_common_init(struct device *dev)
|
||||
if (mc13xxx->flags & MC13XXX_USE_ADC)
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
|
||||
|
||||
if (mc13xxx->flags & MC13XXX_USE_CODEC)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
|
||||
pdata->codec, sizeof(*pdata->codec));
|
||||
if (mc13xxx->flags & MC13XXX_USE_CODEC) {
|
||||
if (pdata)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
|
||||
pdata->codec, sizeof(*pdata->codec));
|
||||
else
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-codec");
|
||||
}
|
||||
|
||||
if (mc13xxx->flags & MC13XXX_USE_RTC)
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define DRV_NAME "hdmi-audio-codec"
|
||||
|
||||
+35
-12
@@ -11,10 +11,12 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@@ -1674,6 +1676,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
|
||||
M98090_REG_CLOCK_RATIO_NI_LSB, 0x00);
|
||||
snd_soc_update_bits(codec, M98090_REG_CLOCK_MODE,
|
||||
M98090_USE_M1_MASK, 0);
|
||||
max98090->master = false;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
/* Set to master mode */
|
||||
@@ -1690,6 +1693,7 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
|
||||
regval |= M98090_MAS_MASK |
|
||||
M98090_BSEL_32;
|
||||
}
|
||||
max98090->master = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
@@ -1793,13 +1797,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
|
||||
/*
|
||||
* Set to normal bias level.
|
||||
*/
|
||||
snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
|
||||
M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
@@ -1873,7 +1870,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
max98090_configure_bclk(codec);
|
||||
if (max98090->master)
|
||||
max98090_configure_bclk(codec);
|
||||
|
||||
cdata->rate = max98090->lrclk;
|
||||
|
||||
@@ -1952,8 +1950,6 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
|
||||
|
||||
max98090->sysclk = freq;
|
||||
|
||||
max98090_configure_bclk(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2225,6 +2221,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
|
||||
/* Initialize private data */
|
||||
|
||||
max98090->sysclk = (unsigned)-1;
|
||||
max98090->master = false;
|
||||
|
||||
cdata = &max98090->dai[0];
|
||||
cdata->rate = (unsigned)-1;
|
||||
@@ -2294,6 +2291,9 @@ static int max98090_probe(struct snd_soc_codec *codec)
|
||||
snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
|
||||
M98090_VCM_MODE_MASK);
|
||||
|
||||
snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
|
||||
M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
|
||||
|
||||
max98090_handle_pdata(codec);
|
||||
|
||||
max98090_add_widgets(codec);
|
||||
@@ -2330,9 +2330,11 @@ static const struct regmap_config max98090_regmap = {
|
||||
};
|
||||
|
||||
static int max98090_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *i2c_id)
|
||||
{
|
||||
struct max98090_priv *max98090;
|
||||
const struct acpi_device_id *acpi_id;
|
||||
kernel_ulong_t driver_data = 0;
|
||||
int ret;
|
||||
|
||||
pr_debug("max98090_i2c_probe\n");
|
||||
@@ -2342,7 +2344,19 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
|
||||
if (max98090 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
max98090->devtype = id->driver_data;
|
||||
if (ACPI_HANDLE(&i2c->dev)) {
|
||||
acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
|
||||
&i2c->dev);
|
||||
if (!acpi_id) {
|
||||
dev_err(&i2c->dev, "No driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
driver_data = acpi_id->driver_data;
|
||||
} else if (i2c_id) {
|
||||
driver_data = i2c_id->driver_data;
|
||||
}
|
||||
|
||||
max98090->devtype = driver_data;
|
||||
i2c_set_clientdata(i2c, max98090);
|
||||
max98090->pdata = i2c->dev.platform_data;
|
||||
max98090->irq = i2c->irq;
|
||||
@@ -2433,12 +2447,21 @@ static const struct of_device_id max98090_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max98090_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static struct acpi_device_id max98090_acpi_match[] = {
|
||||
{ "193C9890", MAX98090 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, max98090_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver max98090_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max98090",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &max98090_pm,
|
||||
.of_match_table = of_match_ptr(max98090_of_match),
|
||||
.acpi_match_table = ACPI_PTR(max98090_acpi_match),
|
||||
},
|
||||
.probe = max98090_i2c_probe,
|
||||
.remove = max98090_i2c_remove,
|
||||
|
||||
@@ -1540,6 +1540,7 @@ struct max98090_priv {
|
||||
unsigned int pa2en;
|
||||
unsigned int extmic_mux;
|
||||
unsigned int sidetone;
|
||||
bool master;
|
||||
};
|
||||
|
||||
int max98090_mic_detect(struct snd_soc_codec *codec,
|
||||
|
||||
@@ -2399,10 +2399,17 @@ static const struct i2c_device_id max98095_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
|
||||
|
||||
static const struct of_device_id max98095_of_match[] = {
|
||||
{ .compatible = "maxim,max98095", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max98095_of_match);
|
||||
|
||||
static struct i2c_driver max98095_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max98095",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(max98095_of_match),
|
||||
},
|
||||
.probe = max98095_i2c_probe,
|
||||
.remove = max98095_i2c_remove,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/mc13xxx.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
@@ -748,6 +749,7 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_priv *priv;
|
||||
struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
@@ -758,7 +760,17 @@ static int __init mc13783_codec_probe(struct platform_device *pdev)
|
||||
priv->adc_ssi_port = pdata->adc_ssi_port;
|
||||
priv->dac_ssi_port = pdata->dac_ssi_port;
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
np = of_get_child_by_name(pdev->dev.parent->of_node, "codec");
|
||||
if (!np)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, priv);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <sound/tpa6130a2-plat.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include "tpa6130a2.h"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
|
||||
snd-soc-sst-acpi-objs := sst-acpi.o
|
||||
|
||||
snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o
|
||||
snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o
|
||||
snd-soc-mfld-machine-objs := mfld_machine.o
|
||||
|
||||
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
|
||||
|
||||
@@ -111,27 +111,13 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
|
||||
{
|
||||
.name = "Baytrail Audio",
|
||||
.stream_name = "Audio",
|
||||
.cpu_dai_name = "Front-cpu-dai",
|
||||
.cpu_dai_name = "baytrail-pcm-audio",
|
||||
.codec_dai_name = "rt5640-aif1",
|
||||
.codec_name = "i2c-10EC5640:00",
|
||||
.platform_name = "baytrail-pcm-audio",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
.init = byt_rt5640_init,
|
||||
.ignore_suspend = 1,
|
||||
.ops = &byt_rt5640_ops,
|
||||
},
|
||||
{
|
||||
.name = "Baytrail Voice",
|
||||
.stream_name = "Voice",
|
||||
.cpu_dai_name = "Mic1-cpu-dai",
|
||||
.codec_dai_name = "rt5640-aif1",
|
||||
.codec_name = "i2c-10EC5640:00",
|
||||
.platform_name = "baytrail-pcm-audio",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
.init = NULL,
|
||||
.ignore_suspend = 1,
|
||||
.ops = &byt_rt5640_ops,
|
||||
},
|
||||
};
|
||||
@@ -146,6 +132,17 @@ static struct snd_soc_card byt_rt5640_card = {
|
||||
.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static const struct dev_pm_ops byt_rt5640_pm_ops = {
|
||||
.suspend = snd_soc_suspend,
|
||||
.resume = snd_soc_resume,
|
||||
};
|
||||
|
||||
#define BYT_RT5640_PM_OPS (&byt_rt5640_pm_ops)
|
||||
#else
|
||||
#define BYT_RT5640_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static int byt_rt5640_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &byt_rt5640_card;
|
||||
@@ -171,6 +168,7 @@ static struct platform_driver byt_rt5640_audio = {
|
||||
.driver = {
|
||||
.name = "byt-rt5640",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = BYT_RT5640_PM_OPS,
|
||||
},
|
||||
};
|
||||
module_platform_driver(byt_rt5640_audio)
|
||||
|
||||
@@ -214,6 +214,13 @@ static void sst_byt_boot(struct sst_dsp *sst)
|
||||
{
|
||||
int tries = 10;
|
||||
|
||||
/*
|
||||
* save the physical address of extended firmware block in the first
|
||||
* 4 bytes of the mailbox
|
||||
*/
|
||||
memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
|
||||
&sst->pdata->fw_base, sizeof(u32));
|
||||
|
||||
/* release stall and wait to unstall */
|
||||
sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
|
||||
while (tries--) {
|
||||
@@ -317,13 +324,6 @@ static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* save the physical address of extended firmware block in the first
|
||||
* 4 bytes of the mailbox
|
||||
*/
|
||||
memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
|
||||
&pdata->fw_base, sizeof(u32));
|
||||
|
||||
ret = dma_coerce_mask_and_coherent(sst->dma_dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -173,6 +173,7 @@ struct sst_byt {
|
||||
/* boot */
|
||||
wait_queue_head_t boot_wait;
|
||||
bool boot_complete;
|
||||
struct sst_fw *fw;
|
||||
|
||||
/* IPC messaging */
|
||||
struct list_head tx_list;
|
||||
@@ -299,6 +300,24 @@ static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
|
||||
wake_up(&msg->waitq);
|
||||
}
|
||||
|
||||
static void sst_byt_drop_all(struct sst_byt *byt)
|
||||
{
|
||||
struct ipc_message *msg, *tmp;
|
||||
unsigned long flags;
|
||||
|
||||
/* drop all TX and Rx messages before we stall + reset DSP */
|
||||
spin_lock_irqsave(&byt->dsp->spinlock, flags);
|
||||
list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) {
|
||||
list_move(&msg->list, &byt->empty_list);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) {
|
||||
list_move(&msg->list, &byt->empty_list);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
|
||||
}
|
||||
|
||||
static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
|
||||
void *rx_data)
|
||||
{
|
||||
@@ -661,36 +680,33 @@ out:
|
||||
static int sst_byt_stream_operations(struct sst_byt *byt, int type,
|
||||
int stream_id, int wait)
|
||||
{
|
||||
struct sst_byt_start_stream_params start_stream;
|
||||
u64 header;
|
||||
void *tx_msg = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (type != IPC_IA_START_STREAM) {
|
||||
header = sst_byt_header(type, 0, false, stream_id);
|
||||
} else {
|
||||
start_stream.byte_offset = 0;
|
||||
header = sst_byt_header(IPC_IA_START_STREAM,
|
||||
sizeof(start_stream) + sizeof(u32),
|
||||
true, stream_id);
|
||||
tx_msg = &start_stream;
|
||||
size = sizeof(start_stream);
|
||||
}
|
||||
|
||||
header = sst_byt_header(type, 0, false, stream_id);
|
||||
if (wait)
|
||||
return sst_byt_ipc_tx_msg_wait(byt, header,
|
||||
tx_msg, size, NULL, 0);
|
||||
return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
|
||||
else
|
||||
return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
|
||||
return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0);
|
||||
}
|
||||
|
||||
/* stream ALSA trigger operations */
|
||||
int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream)
|
||||
int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
|
||||
u32 start_offset)
|
||||
{
|
||||
struct sst_byt_start_stream_params start_stream;
|
||||
void *tx_msg;
|
||||
size_t size;
|
||||
u64 header;
|
||||
int ret;
|
||||
|
||||
ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM,
|
||||
stream->str_id, 0);
|
||||
start_stream.byte_offset = start_offset;
|
||||
header = sst_byt_header(IPC_IA_START_STREAM,
|
||||
sizeof(start_stream) + sizeof(u32),
|
||||
true, stream->str_id);
|
||||
tx_msg = &start_stream;
|
||||
size = sizeof(start_stream);
|
||||
|
||||
ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
|
||||
if (ret < 0)
|
||||
dev_err(byt->dev, "ipc: error failed to start stream %d\n",
|
||||
stream->str_id);
|
||||
@@ -782,6 +798,73 @@ static struct sst_dsp_device byt_dev = {
|
||||
.ops = &sst_byt_ops,
|
||||
};
|
||||
|
||||
int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
|
||||
{
|
||||
struct sst_byt *byt = pdata->dsp;
|
||||
|
||||
dev_dbg(byt->dev, "dsp reset\n");
|
||||
sst_dsp_reset(byt->dsp);
|
||||
sst_byt_drop_all(byt);
|
||||
dev_dbg(byt->dev, "dsp in reset\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq);
|
||||
|
||||
int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
|
||||
{
|
||||
struct sst_byt *byt = pdata->dsp;
|
||||
|
||||
dev_dbg(byt->dev, "free all blocks and unload fw\n");
|
||||
sst_fw_unload(byt->fw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_late);
|
||||
|
||||
int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata)
|
||||
{
|
||||
struct sst_byt *byt = pdata->dsp;
|
||||
int ret;
|
||||
|
||||
dev_dbg(byt->dev, "reload dsp fw\n");
|
||||
|
||||
sst_dsp_reset(byt->dsp);
|
||||
|
||||
ret = sst_fw_reload(byt->fw);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "error: failed to reload firmware\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* wait for DSP boot completion */
|
||||
byt->boot_complete = false;
|
||||
sst_dsp_boot(byt->dsp);
|
||||
dev_dbg(byt->dev, "dsp booting...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_byt_dsp_boot);
|
||||
|
||||
int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata)
|
||||
{
|
||||
struct sst_byt *byt = pdata->dsp;
|
||||
int err;
|
||||
|
||||
dev_dbg(byt->dev, "wait for dsp reboot\n");
|
||||
|
||||
err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
|
||||
msecs_to_jiffies(IPC_BOOT_MSECS));
|
||||
if (err == 0) {
|
||||
dev_err(byt->dev, "ipc: error DSP boot timeout\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dev_dbg(byt->dev, "dsp rebooted\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
|
||||
|
||||
int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
|
||||
{
|
||||
struct sst_byt *byt;
|
||||
@@ -848,6 +931,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
|
||||
}
|
||||
|
||||
pdata->dsp = byt;
|
||||
byt->fw = byt_sst_fw;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -53,7 +53,8 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
|
||||
int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
|
||||
|
||||
/* stream ALSA trigger operations */
|
||||
int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream);
|
||||
int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
|
||||
u32 start_offset);
|
||||
int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
|
||||
int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
|
||||
int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
|
||||
@@ -65,5 +66,9 @@ int sst_byt_get_dsp_position(struct sst_byt *byt,
|
||||
int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
|
||||
void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
|
||||
struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
|
||||
int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata);
|
||||
int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
|
||||
int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
|
||||
int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,6 +45,11 @@ struct sst_byt_pcm_data {
|
||||
struct sst_byt_stream *stream;
|
||||
struct snd_pcm_substream *substream;
|
||||
struct mutex mutex;
|
||||
|
||||
/* latest DSP DMA hw pointer */
|
||||
u32 hw_ptr;
|
||||
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
/* private data for the driver */
|
||||
@@ -63,7 +68,7 @@ static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct sst_byt_priv_data *pdata =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
u32 rate, bits;
|
||||
u8 channels;
|
||||
@@ -130,21 +135,56 @@ static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_restore_stream_context(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct sst_byt_priv_data *pdata =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
int ret;
|
||||
|
||||
/* commit stream using existing stream params */
|
||||
ret = sst_byt_stream_commit(byt, pcm_data->stream);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sst_byt_stream_start(byt, pcm_data->stream, pcm_data->hw_ptr);
|
||||
|
||||
dev_dbg(rtd->dev, "stream context restored at offset %d\n",
|
||||
pcm_data->hw_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sst_byt_pcm_work(struct work_struct *work)
|
||||
{
|
||||
struct sst_byt_pcm_data *pcm_data =
|
||||
container_of(work, struct sst_byt_pcm_data, work);
|
||||
|
||||
if (snd_pcm_running(pcm_data->substream))
|
||||
sst_byt_pcm_restore_stream_context(pcm_data->substream);
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct sst_byt_priv_data *pdata =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
|
||||
dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
sst_byt_stream_start(byt, pcm_data->stream);
|
||||
sst_byt_stream_start(byt, pcm_data->stream, 0);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
schedule_work(&pcm_data->work);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
sst_byt_stream_resume(byt, pcm_data->stream);
|
||||
break;
|
||||
@@ -168,13 +208,19 @@ static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
|
||||
struct snd_pcm_substream *substream = pcm_data->substream;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
u32 pos;
|
||||
struct sst_byt_priv_data *pdata =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
u32 pos, hw_pos;
|
||||
|
||||
hw_pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
|
||||
snd_pcm_lib_buffer_bytes(substream));
|
||||
pcm_data->hw_ptr = hw_pos;
|
||||
pos = frames_to_bytes(runtime,
|
||||
(runtime->control->appl_ptr %
|
||||
runtime->buffer_size));
|
||||
|
||||
dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
|
||||
dev_dbg(rtd->dev, "PCM: App/DMA pointer %u/%u bytes\n", pos, hw_pos);
|
||||
|
||||
snd_pcm_period_elapsed(substream);
|
||||
return pos;
|
||||
@@ -186,18 +232,11 @@ static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct sst_byt_priv_data *pdata =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
snd_pcm_uframes_t offset;
|
||||
int pos;
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
|
||||
pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
|
||||
snd_pcm_lib_buffer_bytes(substream));
|
||||
offset = bytes_to_frames(runtime, pos);
|
||||
dev_dbg(rtd->dev, "PCM: DMA pointer %u bytes\n", pcm_data->hw_ptr);
|
||||
|
||||
dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
|
||||
frames_to_bytes(runtime, (u32)offset));
|
||||
return offset;
|
||||
return bytes_to_frames(runtime, pcm_data->hw_ptr);
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
|
||||
@@ -205,20 +244,18 @@ static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct sst_byt_priv_data *pdata =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
|
||||
dev_dbg(rtd->dev, "PCM: open\n");
|
||||
|
||||
pcm_data = &pdata->pcm[rtd->cpu_dai->id];
|
||||
mutex_lock(&pcm_data->mutex);
|
||||
|
||||
snd_soc_pcm_set_drvdata(rtd, pcm_data);
|
||||
pcm_data->substream = substream;
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
|
||||
|
||||
pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1,
|
||||
pcm_data->stream = sst_byt_stream_new(byt, substream->stream + 1,
|
||||
byt_notify_pointer, pcm_data);
|
||||
if (pcm_data->stream == NULL) {
|
||||
dev_err(rtd->dev, "failed to create stream\n");
|
||||
@@ -235,12 +272,13 @@ static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct sst_byt_priv_data *pdata =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
|
||||
struct sst_byt_pcm_data *pcm_data = &pdata->pcm[substream->stream];
|
||||
struct sst_byt *byt = pdata->byt;
|
||||
int ret;
|
||||
|
||||
dev_dbg(rtd->dev, "PCM: close\n");
|
||||
|
||||
cancel_work_sync(&pcm_data->work);
|
||||
mutex_lock(&pcm_data->mutex);
|
||||
ret = sst_byt_stream_free(byt, pcm_data->stream);
|
||||
if (ret < 0) {
|
||||
@@ -283,18 +321,16 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
size_t size;
|
||||
struct snd_soc_platform *platform = rtd->platform;
|
||||
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
|
||||
int ret = 0;
|
||||
|
||||
ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
|
||||
pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
|
||||
size = sst_byt_pcm_hardware.buffer_bytes_max;
|
||||
ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
|
||||
SNDRV_DMA_TYPE_DEV,
|
||||
rtd->card->dev,
|
||||
pdata->dma_dev,
|
||||
size, size);
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "dma buffer allocation failed %d\n",
|
||||
@@ -308,7 +344,7 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
|
||||
static struct snd_soc_dai_driver byt_dais[] = {
|
||||
{
|
||||
.name = "Front-cpu-dai",
|
||||
.name = "Baytrail PCM",
|
||||
.playback = {
|
||||
.stream_name = "System Playback",
|
||||
.channels_min = 2,
|
||||
@@ -317,9 +353,6 @@ static struct snd_soc_dai_driver byt_dais[] = {
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE |
|
||||
SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "Mic1-cpu-dai",
|
||||
.capture = {
|
||||
.stream_name = "Analog Capture",
|
||||
.channels_min = 2,
|
||||
@@ -344,8 +377,10 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
|
||||
priv_data->byt = plat_data->dsp;
|
||||
snd_soc_platform_set_drvdata(platform, priv_data);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(byt_dais); i++)
|
||||
for (i = 0; i < BYT_PCM_COUNT; i++) {
|
||||
mutex_init(&priv_data->pcm[i].mutex);
|
||||
INIT_WORK(&priv_data->pcm[i].work, sst_byt_pcm_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -367,6 +402,72 @@ static const struct snd_soc_component_driver byt_dai_component = {
|
||||
.name = "byt-dai",
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct sst_pdata *sst_pdata = dev_get_platdata(dev);
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "suspending noirq\n");
|
||||
|
||||
/* at this point all streams will be stopped and context saved */
|
||||
ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to suspend %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_dev_suspend_late(struct device *dev)
|
||||
{
|
||||
struct sst_pdata *sst_pdata = dev_get_platdata(dev);
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "suspending late\n");
|
||||
|
||||
ret = sst_byt_dsp_suspend_late(dev, sst_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to suspend %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_dev_resume_early(struct device *dev)
|
||||
{
|
||||
struct sst_pdata *sst_pdata = dev_get_platdata(dev);
|
||||
|
||||
dev_dbg(dev, "resume early\n");
|
||||
|
||||
/* load fw and boot DSP */
|
||||
return sst_byt_dsp_boot(dev, sst_pdata);
|
||||
}
|
||||
|
||||
static int sst_byt_pcm_dev_resume(struct device *dev)
|
||||
{
|
||||
struct sst_pdata *sst_pdata = dev_get_platdata(dev);
|
||||
|
||||
dev_dbg(dev, "resume\n");
|
||||
|
||||
/* wait for FW to finish booting */
|
||||
return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sst_byt_pm_ops = {
|
||||
.suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
|
||||
.suspend_late = sst_byt_pcm_dev_suspend_late,
|
||||
.resume_early = sst_byt_pcm_dev_resume_early,
|
||||
.resume = sst_byt_pcm_dev_resume,
|
||||
};
|
||||
|
||||
#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
|
||||
#else
|
||||
#define SST_BYT_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
|
||||
@@ -409,6 +510,7 @@ static struct platform_driver sst_byt_pcm_driver = {
|
||||
.driver = {
|
||||
.name = "baytrail-pcm-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = SST_BYT_PM_OPS,
|
||||
},
|
||||
|
||||
.probe = sst_byt_pcm_dev_probe,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user