Commit a4b12990 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/ml26124', 'asoc/topic/of',...

Merge remote-tracking branches 'asoc/topic/ml26124', 'asoc/topic/of', 'asoc/topic/omap', 'asoc/topic/pxa' and 'asoc/topic/rcar' into asoc-next
TDM slot:
This specifies audio DAI's TDM slot.
TDM slot properties:
dai-tdm-slot-num : Number of slots in use.
dai-tdm-slot-width : Width in bits for each slot.
For instance:
dai-tdm-slot-num = <2>;
dai-tdm-slot-width = <8>;
And for each spcified driver, there could be one .of_xlate_tdm_slot_mask()
to specify a explicit mapping of the channels and the slots. If it's absent
the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
tx and rx masks.
For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
for an active slot as default, and the default active bits are at the LSB of
the masks.
Widgets:
This mainly specifies audio off-codec DAPM widgets.
Each entry is a pair of strings in DT:
"template-wname", "user-supplied-wname"
The "template-wname" being the template widget name and currently includes:
"Microphone", "Line", "Headphone" and "Speaker".
The "user-supplied-wname" being the user specified widget name.
For instance:
simple-audio-widgets =
"Microphone", "Microphone Jack",
"Line", "Line In Jack",
"Line", "Line Out Jack",
"Headphone", "Headphone Jack",
"Speaker", "Speaker External";
...@@ -34,17 +34,17 @@ ...@@ -34,17 +34,17 @@
* B : SSI direction * B : SSI direction
*/ */
#define RSND_SSI_CLK_PIN_SHARE (1 << 31) #define RSND_SSI_CLK_PIN_SHARE (1 << 31)
#define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */
#define RSND_SSI_PLAY (1 << 24) #define RSND_SSI_PLAY (1 << 24)
#define RSND_SSI(_dma_id, _pio_irq, _flags) \
{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
#define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \ #define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \
{ .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } { .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
#define RSND_SSI_UNUSED \ #define RSND_SSI_UNUSED \
{ .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 } { .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 }
struct rsnd_ssi_platform_info { struct rsnd_ssi_platform_info {
int dai_id; int dai_id; /* will be removed */
int dma_id; int dma_id;
int pio_irq; int pio_irq;
u32 flags; u32 flags;
...@@ -55,9 +55,31 @@ struct rsnd_ssi_platform_info { ...@@ -55,9 +55,31 @@ struct rsnd_ssi_platform_info {
*/ */
#define RSND_SCU_USE_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */ #define RSND_SCU_USE_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */
struct rsnd_scu_platform_info { #define RSND_SRC(rate, _dma_id) \
{ .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, }
#define RSND_SRC_SET(rate, _dma_id) \
{ .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, }
#define RSND_SRC_UNUSED \
{ .flags = 0, .convert_rate = 0, .dma_id = 0, }
#define rsnd_scu_platform_info rsnd_src_platform_info
#define src_info scu_info
#define src_info_nr scu_info_nr
struct rsnd_src_platform_info {
u32 flags; u32 flags;
u32 convert_rate; /* sampling rate convert */ u32 convert_rate; /* sampling rate convert */
int dma_id; /* for Gen2 SCU */
};
struct rsnd_dai_path_info {
struct rsnd_ssi_platform_info *ssi;
struct rsnd_src_platform_info *src;
};
struct rsnd_dai_platform_info {
struct rsnd_dai_path_info playback;
struct rsnd_dai_path_info capture;
}; };
/* /*
...@@ -75,8 +97,10 @@ struct rcar_snd_info { ...@@ -75,8 +97,10 @@ struct rcar_snd_info {
u32 flags; u32 flags;
struct rsnd_ssi_platform_info *ssi_info; struct rsnd_ssi_platform_info *ssi_info;
int ssi_info_nr; int ssi_info_nr;
struct rsnd_scu_platform_info *scu_info; struct rsnd_src_platform_info *src_info;
int scu_info_nr; int src_info_nr;
struct rsnd_dai_platform_info *dai_info;
int dai_info_nr;
int (*start)(int id); int (*start)(int id);
int (*stop)(int id); int (*stop)(int id);
}; };
......
...@@ -142,6 +142,8 @@ struct snd_soc_dai_ops { ...@@ -142,6 +142,8 @@ struct snd_soc_dai_ops {
* Called by soc_card drivers, normally in their hw_params. * Called by soc_card drivers, normally in their hw_params.
*/ */
int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
int (*of_xlate_tdm_slot_mask)(unsigned int slots,
unsigned int *tx_mask, unsigned int *rx_mask);
int (*set_tdm_slot)(struct snd_soc_dai *dai, int (*set_tdm_slot)(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask, unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width); int slots, int slot_width);
......
...@@ -1227,6 +1227,11 @@ void snd_soc_util_exit(void); ...@@ -1227,6 +1227,11 @@ void snd_soc_util_exit(void);
int snd_soc_of_parse_card_name(struct snd_soc_card *card, int snd_soc_of_parse_card_name(struct snd_soc_card *card,
const char *propname); const char *propname);
int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
const char *propname);
int snd_soc_of_parse_tdm_slot(struct device_node *np,
unsigned int *slots,
unsigned int *slot_width);
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname); const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np, unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
......
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hswadsp
#if !defined(_TRACE_HSWADSP_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HSWADSP_H
#include <linux/types.h>
#include <linux/ktime.h>
#include <linux/tracepoint.h>
struct sst_hsw;
struct sst_hsw_stream;
struct sst_hsw_ipc_stream_free_req;
struct sst_hsw_ipc_volume_req;
struct sst_hsw_ipc_stream_alloc_req;
struct sst_hsw_audio_data_format_ipc;
struct sst_hsw_ipc_stream_info_reply;
struct sst_hsw_ipc_device_config_req;
DECLARE_EVENT_CLASS(sst_irq,
TP_PROTO(uint32_t status, uint32_t mask),
TP_ARGS(status, mask),
TP_STRUCT__entry(
__field( unsigned int, status )
__field( unsigned int, mask )
),
TP_fast_assign(
__entry->status = status;
__entry->mask = mask;
),
TP_printk("status 0x%8.8x mask 0x%8.8x",
(unsigned int)__entry->status, (unsigned int)__entry->mask)
);
DEFINE_EVENT(sst_irq, sst_irq_busy,
TP_PROTO(unsigned int status, unsigned int mask),
TP_ARGS(status, mask)
);
DEFINE_EVENT(sst_irq, sst_irq_done,
TP_PROTO(unsigned int status, unsigned int mask),
TP_ARGS(status, mask)
);
DECLARE_EVENT_CLASS(ipc,
TP_PROTO(const char *name, int val),
TP_ARGS(name, val),
TP_STRUCT__entry(
__string( name, name )
__field( unsigned int, val )
),
TP_fast_assign(
__assign_str(name, name);
__entry->val = val;
),
TP_printk("%s 0x%8.8x", __get_str(name), (unsigned int)__entry->val)
);
DEFINE_EVENT(ipc, ipc_request,
TP_PROTO(const char *name, int val),
TP_ARGS(name, val)
);
DEFINE_EVENT(ipc, ipc_reply,
TP_PROTO(const char *name, int val),
TP_ARGS(name, val)
);
DEFINE_EVENT(ipc, ipc_pending_reply,
TP_PROTO(const char *name, int val),
TP_ARGS(name, val)
);
DEFINE_EVENT(ipc, ipc_notification,
TP_PROTO(const char *name, int val),
TP_ARGS(name, val)
);
DEFINE_EVENT(ipc, ipc_error,
TP_PROTO(const char *name, int val),
TP_ARGS(name, val)
);
DECLARE_EVENT_CLASS(stream_position,
TP_PROTO(unsigned int id, unsigned int pos),
TP_ARGS(id, pos),
TP_STRUCT__entry(
__field( unsigned int, id )
__field( unsigned int, pos )
),
TP_fast_assign(
__entry->id = id;
__entry->pos = pos;
),
TP_printk("id %d position 0x%x",
(unsigned int)__entry->id, (unsigned int)__entry->pos)
);
DEFINE_EVENT(stream_position, stream_read_position,
TP_PROTO(unsigned int id, unsigned int pos),
TP_ARGS(id, pos)
);
DEFINE_EVENT(stream_position, stream_write_position,
TP_PROTO(unsigned int id, unsigned int pos),
TP_ARGS(id, pos)
);
TRACE_EVENT(hsw_stream_buffer,
TP_PROTO(struct sst_hsw_stream *stream),
TP_ARGS(stream),
TP_STRUCT__entry(
__field( int, id )
__field( int, pt_addr )
__field( int, num_pages )
__field( int, ring_size )
__field( int, ring_offset )
__field( int, first_pfn )
),
TP_fast_assign(
__entry->id = stream->host_id;
__entry->pt_addr = stream->request.ringinfo.ring_pt_address;
__entry->num_pages = stream->request.ringinfo.num_pages;
__entry->ring_size = stream->request.ringinfo.ring_size;
__entry->ring_offset = stream->request.ringinfo.ring_offset;
__entry->first_pfn = stream->request.ringinfo.ring_first_pfn;
),
TP_printk("stream %d ring addr 0x%x pages %d size 0x%x offset 0x%x PFN 0x%x",
(int) __entry->id, (int)__entry->pt_addr,
(int)__entry->num_pages, (int)__entry->ring_size,
(int)__entry->ring_offset, (int)__entry->first_pfn)
);
TRACE_EVENT(hsw_stream_alloc_reply,
TP_PROTO(struct sst_hsw_stream *stream),
TP_ARGS(stream),
TP_STRUCT__entry(
__field( int, id )
__field( int, stream_id )
__field( int, mixer_id )
__field( int, peak0 )
__field( int, peak1 )
__field( int, vol0 )
__field( int, vol1 )
),
TP_fast_assign(
__entry->id = stream->host_id;
__entry->stream_id = stream->reply.stream_hw_id;
__entry->mixer_id = stream->reply.mixer_hw_id;
__entry->peak0 = stream->reply.peak_meter_register_address[0];
__entry->peak1 = stream->reply.peak_meter_register_address[1];
__entry->vol0 = stream->reply.volume_register_address[0];
__entry->vol1 = stream->reply.volume_register_address[1];
),
TP_printk("stream %d hw id %d mixer %d peak 0x%x:0x%x vol 0x%x,0x%x",
(int) __entry->id, (int) __entry->stream_id, (int)__entry->mixer_id,
(int)__entry->peak0, (int)__entry->peak1,
(int)__entry->vol0, (int)__entry->vol1)
);
TRACE_EVENT(hsw_mixer_info_reply,
TP_PROTO(struct sst_hsw_ipc_stream_info_reply *reply),
TP_ARGS(reply),
TP_STRUCT__entry(
__field( int, mixer_id )
__field( int, peak0 )
__field( int, peak1 )
__field( int, vol0 )
__field( int, vol1 )
),
TP_fast_assign(
__entry->mixer_id = reply->mixer_hw_id;
__entry->peak0 = reply->peak_meter_register_address[0];
__entry->peak1 = reply->peak_meter_register_address[1];
__entry->vol0 = reply->volume_register_address[0];
__entry->vol1 = reply->volume_register_address[1];
),
TP_printk("mixer id %d peak 0x%x:0x%x vol 0x%x,0x%x",
(int)__entry->mixer_id,
(int)__entry->peak0, (int)__entry->peak1,
(int)__entry->vol0, (int)__entry->vol1)
);
TRACE_EVENT(hsw_stream_data_format,
TP_PROTO(struct sst_hsw_stream *stream,
struct sst_hsw_audio_data_format_ipc *req),
TP_ARGS(stream, req),
TP_STRUCT__entry(
__field( uint32_t, id )
__field( uint32_t, frequency )
__field( uint32_t, bitdepth )
__field( uint32_t, map )
__field( uint32_t, config )
__field( uint32_t, style )
__field( uint8_t, ch_num )
__field( uint8_t, valid_bit )
),
TP_fast_assign(
__entry->id = stream->host_id;
__entry->frequency = req->frequency;
__entry->bitdepth = req->bitdepth;
__entry->map = req->map;
__entry->config = req->config;
__entry->style = req->style;
__entry->ch_num = req->ch_num;
__entry->valid_bit = req->valid_bit;
),
TP_printk("stream %d freq %d depth %d map 0x%x config 0x%x style 0x%x ch %d bits %d",
(int) __entry->id, (uint32_t)__entry->frequency,
(uint32_t)__entry->bitdepth, (uint32_t)__entry->map,
(uint32_t)__entry->config, (uint32_t)__entry->style,
(uint8_t)__entry->ch_num, (uint8_t)__entry->valid_bit)
);
TRACE_EVENT(hsw_stream_alloc_request,
TP_PROTO(struct sst_hsw_stream *stream,
struct sst_hsw_ipc_stream_alloc_req *req),
TP_ARGS(stream, req),
TP_STRUCT__entry(
__field( uint32_t, id )
__field( uint8_t, path_id )
__field( uint8_t, stream_type )
__field( uint8_t, format_id )
),
TP_fast_assign(
__entry->id = stream->host_id;
__entry->path_id = req->path_id;
__entry->stream_type = req->stream_type;
__entry->format_id = req->format_id;
),
TP_printk("stream %d path %d type %d format %d",
(int) __entry->id, (uint8_t)__entry->path_id,
(uint8_t)__entry->stream_type, (uint8_t)__entry->format_id)
);
TRACE_EVENT(hsw_stream_free_req,
TP_PROTO(struct sst_hsw_stream *stream,
struct sst_hsw_ipc_stream_free_req *req),
TP_ARGS(stream, req),
TP_STRUCT__entry(
__field( int, id )
__field( int, stream_id )
),
TP_fast_assign(
__entry->id = stream->host_id;
__entry->stream_id = req->stream_id;
),
TP_printk("stream %d hw id %d",
(int) __entry->id, (int) __entry->stream_id)
);
TRACE_EVENT(hsw_volume_req,
TP_PROTO(struct sst_hsw_stream *stream,
struct sst_hsw_ipc_volume_req *req),
TP_ARGS(stream, req),
TP_STRUCT__entry(
__field( int, id )
__field( uint32_t, channel )
__field( uint32_t, target_volume )
__field( uint64_t, curve_duration )
__field( uint32_t, curve_type )
),
TP_fast_assign(
__entry->id = stream->host_id;
__entry->channel = req->channel;
__entry->target_volume = req->target_volume;
__entry->curve_duration = req->curve_duration;
__entry->curve_type = req->curve_type;
),
TP_printk("stream %d chan 0x%x vol %d duration %llu type %d",
(int) __entry->id, (uint32_t) __entry->channel,
(uint32_t)__entry->target_volume,
(uint64_t)__entry->curve_duration,
(uint32_t)__entry->curve_type)
);
TRACE_EVENT(hsw_device_config_req,
TP_PROTO(struct sst_hsw_ipc_device_config_req *req),
TP_ARGS(req),
TP_STRUCT__entry(
__field( uint32_t, ssp )
__field( uint32_t, clock_freq )
__field( uint32_t, mode )
__field( uint16_t, clock_divider )
),
TP_fast_assign(
__entry->ssp = req->ssp_interface;
__entry->clock_freq = req->clock_frequency;
__entry->mode = req->mode;
__entry->clock_divider = req->clock_divider;
),
TP_printk("SSP %d Freq %d mode %d div %d",
(uint32_t)__entry->ssp,
(uint32_t)__entry->clock_freq, (uint32_t)__entry->mode,
(uint32_t)__entry->clock_divider)
);
#endif /* _TRACE_HSWADSP_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
#undef TRACE_SYSTEM
#define TRACE_SYSTEM intel-sst
#if !defined(_TRACE_INTEL_SST_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_INTEL_SST_H
#include <linux/types.h>
#include <linux/ktime.h>
#include <linux/tracepoint.h>
DECLARE_EVENT_CLASS(sst_ipc_msg,
TP_PROTO(unsigned int val),
TP_ARGS(val),
TP_STRUCT__entry(
__field( unsigned int, val )
),
TP_fast_assign(
__entry->val = val;
),
TP_printk("0x%8.8x", (unsigned int)__entry->val)
);
DEFINE_EVENT(sst_ipc_msg, sst_ipc_msg_tx,
TP_PROTO(unsigned int val),
TP_ARGS(val)
);
DEFINE_EVENT(sst_ipc_msg, sst_ipc_msg_rx,
TP_PROTO(unsigned int val),
TP_ARGS(val)
);
DECLARE_EVENT_CLASS(sst_ipc_mailbox,
TP_PROTO(unsigned int offset, unsigned int val),
TP_ARGS(offset, val),
TP_STRUCT__entry(
__field( unsigned int, offset )
__field( unsigned int, val )
),
TP_fast_assign(
__entry->offset = offset;
__entry->val = val;
),
TP_printk(" 0x%4.4x = 0x%8.8x",
(unsigned int)__entry->offset, (unsigned int)__entry->val)
);
DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_inbox_rdata,
TP_PROTO(unsigned int offset, unsigned int val),
TP_ARGS(offset, val)
);
DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_inbox_wdata,
TP_PROTO(unsigned int offset, unsigned int val),
TP_ARGS(offset, val)
);
DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_outbox_rdata,
TP_PROTO(unsigned int offset, unsigned int val),
TP_ARGS(offset, val)
);
DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_outbox_wdata,
TP_PROTO(unsigned int offset, unsigned int val),
TP_ARGS(offset, val)
);
DECLARE_EVENT_CLASS(sst_ipc_mailbox_info,
TP_PROTO(unsigned int size),
TP_ARGS(size),
TP_STRUCT__entry(
__field( unsigned int, size )
),
TP_fast_assign(
__entry->size = size;
),
TP_printk("Mailbox bytes 0x%8.8x", (unsigned int)__entry->size)
);
DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_inbox_read,
TP_PROTO(unsigned int size),
TP_ARGS(size)
);
DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_inbox_write,
TP_PROTO(unsigned int size),
TP_ARGS(size)
);
DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_outbox_read,
TP_PROTO(unsigned int size),
TP_ARGS(size)
);
DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_outbox_write,
TP_PROTO(unsigned int size),
TP_ARGS(size)
);
#endif /* _TRACE_SST_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
...@@ -73,11 +73,11 @@ static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0); ...@@ -73,11 +73,11 @@ static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
static const char * const ml26124_companding[] = {"16bit PCM", "u-law", static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
"A-law"}; "A-law"};
static const struct soc_enum ml26124_adc_companding_enum static SOC_ENUM_SINGLE_DECL(ml26124_adc_companding_enum,
= SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding); ML26124_SAI_TRANS_CTL, 6, ml26124_companding);
static const struct soc_enum ml26124_dac_companding_enum static SOC_ENUM_SINGLE_DECL(ml26124_dac_companding_enum,
= SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding); ML26124_SAI_RCV_CTL, 6, ml26124_companding);
static const struct snd_kcontrol_new ml26124_snd_controls[] = { static const struct snd_kcontrol_new ml26124_snd_controls[] = {
SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0, SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
...@@ -136,8 +136,8 @@ static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = { ...@@ -136,8 +136,8 @@ static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in", static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
"Digital MIC in", "Analog MIC Differential in"}; "Digital MIC in", "Analog MIC Differential in"};
static const struct soc_enum ml26124_insel_enum = static SOC_ENUM_SINGLE_DECL(ml26124_insel_enum,
SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select); ML26124_MIC_IF_CTL, 0, ml26124_input_select);
static const struct snd_kcontrol_new ml26124_input_mux_controls = static const struct snd_kcontrol_new ml26124_input_mux_controls =
SOC_DAPM_ENUM("Input Select", ml26124_insel_enum); SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
......
...@@ -2,12 +2,50 @@ config SND_MFLD_MACHINE ...@@ -2,12 +2,50 @@ config SND_MFLD_MACHINE
tristate "SOC Machine Audio driver for Intel Medfield MID platform" tristate "SOC Machine Audio driver for Intel Medfield MID platform"
depends on INTEL_SCU_IPC depends on INTEL_SCU_IPC
select SND_SOC_SN95031 select SND_SOC_SN95031
select SND_SST_PLATFORM select SND_SST_MFLD_PLATFORM
help help
This adds support for ASoC machine driver for Intel(R) MID Medfield platform This adds support for ASoC machine driver for Intel(R) MID Medfield platform
used as alsa device in audio substem in Intel(R) MID devices used as alsa device in audio substem in Intel(R) MID devices
Say Y if you have such a device Say Y if you have such a device
If unsure select "N". If unsure select "N".
config SND_SST_PLATFORM config SND_SST_MFLD_PLATFORM
tristate tristate
config SND_SOC_INTEL_SST
tristate "ASoC support for Intel(R) Smart Sound Technology"
select SND_SOC_INTEL_SST_ACPI if ACPI
depends on (X86 || COMPILE_TEST)
help
This adds support for Intel(R) Smart Sound Technology (SST).
Say Y if you have such a device
If unsure select "N".
config SND_SOC_INTEL_SST_ACPI
tristate
config SND_SOC_INTEL_HASWELL
tristate
config SND_SOC_INTEL_BAYTRAIL
tristate
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
help
This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
Ultrabook platforms.
Say Y if you have such a device
If unsure select "N".
config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640
help
This adds audio driver for Intel Baytrail platform based boards
with the RT5640 audio codec.
snd-soc-sst-platform-objs := sst_platform.o # Core support
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-mfld-machine-objs := mfld_machine.o snd-soc-mfld-machine-objs := mfld_machine.o
obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o
obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
# Platform Support
snd-soc-sst-haswell-pcm-objs := \
sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o
snd-soc-sst-baytrail-pcm-objs := \
sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o
obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
# Machine support
snd-soc-sst-haswell-objs := haswell.o
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
/*
* Intel Baytrail SST RT5640 machine driver
* Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include "../codecs/rt5640.h"
#include "sst-dsp.h"
static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Internal Mic", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
};
static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
{"IN2P", NULL, "Headset Mic"},
{"IN2N", NULL, "Headset Mic"},
{"DMIC1", NULL, "Internal Mic"},
{"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"},
{"Speaker", NULL, "SPOLP"},
{"Speaker", NULL, "SPOLN"},
{"Speaker", NULL, "SPORP"},
{"Speaker", NULL, "SPORN"},
};
static const struct snd_kcontrol_new byt_rt5640_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Internal Mic"),
SOC_DAPM_PIN_SWITCH("Speaker"),
};
static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
params_rate(params) * 256,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(codec_dai->dev, "can't set codec clock %d\n", ret);
return ret;
}
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
params_rate(params) * 64,
params_rate(params) * 256);
if (ret < 0) {
dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
return ret;
}
return 0;
}
static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
struct snd_soc_codec *codec = runtime->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = runtime->card;
card->dapm.idle_bias_off = true;
ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
ARRAY_SIZE(byt_rt5640_controls));
if (ret) {
dev_err(card->dev, "unable to add card controls\n");
return ret;
}
snd_soc_dapm_ignore_suspend(dapm, "HPOL");
snd_soc_dapm_ignore_suspend(dapm, "HPOR");
snd_soc_dapm_ignore_suspend(dapm, "SPOLP");
snd_soc_dapm_ignore_suspend(dapm, "SPOLN");
snd_soc_dapm_ignore_suspend(dapm, "SPORP");
snd_soc_dapm_ignore_suspend(dapm, "SPORN");
snd_soc_dapm_enable_pin(dapm, "Headset Mic");
snd_soc_dapm_enable_pin(dapm, "Headphone");
snd_soc_dapm_enable_pin(dapm, "Speaker");
snd_soc_dapm_enable_pin(dapm, "Internal Mic");
snd_soc_dapm_sync(dapm);
return ret;
}
static struct snd_soc_ops byt_rt5640_ops = {
.hw_params = byt_rt5640_hw_params,
};
static struct snd_soc_dai_link byt_rt5640_dais[] = {
{
.name = "Baytrail Audio",
.stream_name = "Audio",
.cpu_dai_name = "Front-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 = 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,
},
};
static struct snd_soc_card byt_rt5640_card = {
.name = "byt-rt5640",
.dai_link = byt_rt5640_dais,
.num_links = ARRAY_SIZE(byt_rt5640_dais),
.dapm_widgets = byt_rt5640_widgets,
.num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
.dapm_routes = byt_rt5640_audio_map,
.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
};
static int byt_rt5640_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &byt_rt5640_card;
struct device *dev = &pdev->dev;
card->dev = &pdev->dev;
dev_set_drvdata(dev, card);
return snd_soc_register_card(card);
}
static int byt_rt5640_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
snd_soc_unregister_card(card);
return 0;
}
static struct platform_driver byt_rt5640_audio = {
.probe = byt_rt5640_probe,
.remove = byt_rt5640_remove,
.driver = {
.name = "byt-rt5640",
.owner = THIS_MODULE,
},
};
module_platform_driver(byt_rt5640_audio)
MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:byt-rt5640");
/*
* Intel Haswell Lynxpoint SST Audio
*
* Copyright (C) 2013, Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include "sst-dsp.h"
#include "sst-haswell-ipc.h"
#include "../codecs/rt5640.h"
/* Haswell ULT platforms have a Headphone and Mic jack */
static const struct snd_soc_dapm_widget haswell_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_MIC("Mic", NULL),
};
static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
{"Headphones", NULL, "HPOR"},
{"Headphones", NULL, "HPOL"},
{"IN2P", NULL, "Mic"},
/* CODEC BE connections */
{"SSP0 CODEC IN", NULL, "AIF1 Capture"},
{"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
};
static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
/* The ADSP will covert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
/* set SSP0 to 16 bit */
snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
SNDRV_PCM_HW_PARAM_FIRST_MASK],
SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
SND_SOC_CLOCK_IN);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec sysclk configuration\n");
return ret;
}
/* set correct codec filter for DAI format and clock config */
snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
return ret;
}
static struct snd_soc_ops haswell_rt5640_ops = {
.hw_params = haswell_rt5640_hw_params,
};
static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
struct sst_hsw *haswell = pdata->dsp;
int ret;
/* Set ADSP SSP port settings */
ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
SST_HSW_DEVICE_CLOCK_MASTER, 9);
if (ret < 0) {
dev_err(rtd->dev, "failed to set device config\n");
return ret;
}
/* always connected */
snd_soc_dapm_enable_pin(dapm, "Headphones");
snd_soc_dapm_enable_pin(dapm, "Mic");
return 0;
}
static struct snd_soc_dai_link haswell_rt5640_dais[] = {
/* Front End DAI links */
{
.name = "System",
.stream_name = "System Playback",
.cpu_dai_name = "System Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.init = haswell_rtd_init,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
},
{
.name = "Offload0",
.stream_name = "Offload0 Playback",
.cpu_dai_name = "Offload0 Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
},
{
.name = "Offload1",
.stream_name = "Offload1 Playback",
.cpu_dai_name = "Offload1 Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
},
{
.name = "Loopback",
.stream_name = "Loopback",
.cpu_dai_name = "Loopback Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 0,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1,
},
{
.name = "Capture",
.stream_name = "Capture",
.cpu_dai_name = "Capture Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1,
},
/* Back End DAI links */
{
/* SSP0 - Codec */
.name = "Codec",
.be_id = 0,
.cpu_dai_name = "snd-soc-dummy-dai",
.platform_name = "snd-soc-dummy",
.no_pcm = 1,
.codec_name = "i2c-INT33CA:00",
.codec_dai_name = "rt5640-aif1",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_suspend = 1,
.ignore_pmdown_time = 1,
.be_hw_params_fixup = haswell_ssp0_fixup,
.ops = &haswell_rt5640_ops,
.dpcm_playback = 1,
.dpcm_capture = 1,
},
};
/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
static struct snd_soc_card haswell_rt5640 = {
.name = "haswell-rt5640",
.owner = THIS_MODULE,
.dai_link = haswell_rt5640_dais,
.num_links = ARRAY_SIZE(haswell_rt5640_dais),
.dapm_widgets = haswell_widgets,
.num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
.dapm_routes = haswell_rt5640_map,
.num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
.fully_routed = true,
};
static int haswell_audio_probe(struct platform_device *pdev)
{
haswell_rt5640.dev = &pdev->dev;
return snd_soc_register_card(&haswell_rt5640);
}
static int haswell_audio_remove(struct platform_device *pdev)
{
snd_soc_unregister_card(&haswell_rt5640);
return 0;
}
static struct platform_driver haswell_audio = {
.probe = haswell_audio_probe,
.remove = haswell_audio_remove,
.driver = {
.name = "haswell-audio",
.owner = THIS_MODULE,
},
};
module_platform_driver(haswell_audio)
/* Module information */
MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:haswell-audio");
/*
* Intel SST loader on ACPI systems
*
* Copyright (C) 2013, Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "sst-dsp.h"
#define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000
#define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000
#define SST_LPT_DSP_DMA_SIZE (1024 - 1)
/* Descriptor for SST ASoC machine driver */
struct sst_acpi_mach {
/* ACPI ID for the matching machine driver. Audio codec for instance */
const u8 id[ACPI_ID_LEN];
/* machine driver name */
const char *drv_name;
/* firmware file name */
const char *fw_filename;
};
/* Descriptor for setting up SST platform data */
struct sst_acpi_desc {
const char *drv_name;
struct sst_acpi_mach *machines;
/* Platform resource indexes. Must set to -1 if not used */
int resindex_lpe_base;
int resindex_pcicfg_base;
int resindex_fw_base;
int irqindex_host_ipc;
int resindex_dma_base;
/* Unique number identifying the SST core on platform */
int sst_id;
/* DMA only valid when resindex_dma_base != -1*/
int dma_engine;
int dma_size;
};
struct sst_acpi_priv {
struct platform_device *pdev_mach;
struct platform_device *pdev_pcm;
struct sst_pdata sst_pdata;
struct sst_acpi_desc *desc;
struct sst_acpi_mach *mach;
};
static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
{
struct platform_device *pdev = context;
struct device *dev = &pdev->dev;
struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
struct sst_acpi_desc *desc = sst_acpi->desc;
struct sst_acpi_mach *mach = sst_acpi->mach;
sst_pdata->fw = fw;
if (!fw) {
dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
return;
}
/* register PCM and DAI driver */
sst_acpi->pdev_pcm =
platform_device_register_data(dev, desc->drv_name, -1,
sst_pdata, sizeof(*sst_pdata));
if (IS_ERR(sst_acpi->pdev_pcm)) {
dev_err(dev, "Cannot register device %s. Error %d\n",
desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
}
return;
}
static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
void *context, void **ret)
{
*(bool *)context = true;
return AE_OK;
}
static struct sst_acpi_mach *sst_acpi_find_machine(
struct sst_acpi_mach *machines)
{
struct sst_acpi_mach *mach;
bool found = false;
for (mach = machines; mach->id[0]; mach++)
if (ACPI_SUCCESS(acpi_get_devices(mach->id,
sst_acpi_mach_match,
&found, NULL)) && found)
return mach;
return NULL;
}
static int sst_acpi_probe(struct platform_device *pdev)
{
const struct acpi_device_id *id;
struct device *dev = &pdev->dev;
struct sst_acpi_priv *sst_acpi;
struct sst_pdata *sst_pdata;
struct sst_acpi_mach *mach;
struct sst_acpi_desc *desc;
struct resource *mmio;
int ret = 0;
sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
if (sst_acpi == NULL)
return -ENOMEM;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return -ENODEV;
desc = (struct sst_acpi_desc *)id->driver_data;
mach = sst_acpi_find_machine(desc->machines);
if (mach == NULL) {
dev_err(dev, "No matching ASoC machine driver found\n");
return -ENODEV;
}
sst_pdata = &sst_acpi->sst_pdata;
sst_pdata->id = desc->sst_id;
sst_acpi->desc = desc;
sst_acpi->mach = mach;
if (desc->resindex_dma_base >= 0) {
sst_pdata->dma_engine = desc->dma_engine;
sst_pdata->dma_base = desc->resindex_dma_base;
sst_pdata->dma_size = desc->dma_size;
}
if (desc->irqindex_host_ipc >= 0)
sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
if (desc->resindex_lpe_base >= 0) {
mmio = platform_get_resource(pdev, IORESOURCE_MEM,
desc->resindex_lpe_base);
if (mmio) {
sst_pdata->lpe_base = mmio->start;
sst_pdata->lpe_size = resource_size(mmio);
}
}
if (desc->resindex_pcicfg_base >= 0) {
mmio = platform_get_resource(pdev, IORESOURCE_MEM,
desc->resindex_pcicfg_base);
if (mmio) {
sst_pdata->pcicfg_base = mmio->start;
sst_pdata->pcicfg_size = resource_size(mmio);
}
}
if (desc->resindex_fw_base >= 0) {
mmio = platform_get_resource(pdev, IORESOURCE_MEM,
desc->resindex_fw_base);
if (mmio) {
sst_pdata->fw_base = mmio->start;
sst_pdata->fw_size = resource_size(mmio);
}
}
platform_set_drvdata(pdev, sst_acpi);
/* register machine driver */
sst_acpi->pdev_mach =
platform_device_register_data(dev, mach->drv_name, -1,
sst_pdata, sizeof(*sst_pdata));
if (IS_ERR(sst_acpi->pdev_mach))
return PTR_ERR(sst_acpi->pdev_mach);
/* continue SST probing after firmware is loaded */
ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
if (ret)
platform_device_unregister(sst_acpi->pdev_mach);
return ret;
}
static int sst_acpi_remove(struct platform_device *pdev)
{
struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
platform_device_unregister(sst_acpi->pdev_mach);
if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
platform_device_unregister(sst_acpi->pdev_pcm);
release_firmware(sst_pdata->fw);
return 0;
}
static struct sst_acpi_mach haswell_machines[] = {
{ "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
{}
};
static struct sst_acpi_desc sst_acpi_haswell_desc = {
.drv_name = "haswell-pcm-audio",
.machines = haswell_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_fw_base = -1,
.irqindex_host_ipc = 0,
.sst_id = SST_DEV_ID_LYNX_POINT,
.dma_engine = SST_DMA_TYPE_DW,
.resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
.dma_size = SST_LPT_DSP_DMA_SIZE,
};
static struct sst_acpi_mach broadwell_machines[] = {
{ "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
{}
};
static struct sst_acpi_desc sst_acpi_broadwell_desc = {
.drv_name = "haswell-pcm-audio",
.machines = broadwell_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_fw_base = -1,
.irqindex_host_ipc = 0,
.sst_id = SST_DEV_ID_WILDCAT_POINT,
.dma_engine = SST_DMA_TYPE_DW,
.resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
.dma_size = SST_LPT_DSP_DMA_SIZE,
};
static struct sst_acpi_mach baytrail_machines[] = {
{ "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
{}
};
static struct sst_acpi_desc sst_acpi_baytrail_desc = {
.drv_name = "baytrail-pcm-audio",
.machines = baytrail_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_fw_base = 2,
.irqindex_host_ipc = 5,
.sst_id = SST_DEV_ID_BYT,
.resindex_dma_base = -1,
};
static struct acpi_device_id sst_acpi_match[] = {
{ "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
{ "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
{ "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
{ }
};
MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
static struct platform_driver sst_acpi_driver = {
.probe = sst_acpi_probe,
.remove = sst_acpi_remove,
.driver = {
.name = "sst-acpi",
.owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(sst_acpi_match),
},
};
module_platform_driver(sst_acpi_driver);
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
MODULE_LICENSE("GPL v2");
/*
* Intel Baytrail SST DSP driver
* Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*/
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include "sst-dsp.h"
#include "sst-dsp-priv.h"
#include "sst-baytrail-ipc.h"
#define SST_BYT_FW_SIGNATURE_SIZE 4
#define SST_BYT_FW_SIGN "$SST"
#define SST_BYT_IRAM_OFFSET 0xC0000
#define SST_BYT_DRAM_OFFSET 0x100000
#define SST_BYT_SHIM_OFFSET 0x140000
enum sst_ram_type {
SST_BYT_IRAM = 1,
SST_BYT_DRAM = 2,
SST_BYT_CACHE = 3,
};
struct dma_block_info {
enum sst_ram_type type; /* IRAM/DRAM */
u32 size; /* Bytes */
u32 ram_offset; /* Offset in I/DRAM */
u32 rsvd; /* Reserved field */
};
struct fw_header {
unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
u32 file_size; /* size of fw minus this header */
u32 modules; /* # of modules */
u32 file_format; /* version of header format */
u32 reserved[4];
};
struct sst_byt_fw_module_header {
unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
u32 mod_size; /* size of module */
u32 blocks; /* # of blocks */
u32 type; /* codec type, pp lib */
u32 entry_point;
};
static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
struct sst_byt_fw_module_header *module)
{
struct dma_block_info *block;
struct sst_module *mod;
struct sst_module_data block_data;
struct sst_module_template template;
int count;
memset(&template, 0, sizeof(template));
template.id = module->type;
template.entry = module->entry_point;
template.p.type = SST_MEM_DRAM;
template.p.data_type = SST_DATA_P;
template.s.type = SST_MEM_DRAM;
template.s.data_type = SST_DATA_S;
mod = sst_module_new(fw, &template, NULL);
if (mod == NULL)
return -ENOMEM;
block = (void *)module + sizeof(*module);
for (count = 0; count < module->blocks; count++) {
if (block->size <= 0) {
dev_err(dsp->dev, "block %d size invalid\n", count);
return -EINVAL;
}
switch (block->type) {
case SST_BYT_IRAM:
block_data.offset = block->ram_offset +
dsp->addr.iram_offset;
block_data.type = SST_MEM_IRAM;
break;
case SST_BYT_DRAM:
block_data.offset = block->ram_offset +
dsp->addr.dram_offset;
block_data.type = SST_MEM_DRAM;
break;
case SST_BYT_CACHE:
block_data.offset = block->ram_offset +
(dsp->addr.fw_ext - dsp->addr.lpe);
block_data.type = SST_MEM_CACHE;
break;
default:
dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
block->type, count);
return -EINVAL;
}
block_data.size = block->size;
block_data.data_type = SST_DATA_M;
block_data.data = (void *)block + sizeof(*block);
sst_module_insert_fixed_block(mod, &block_data);
block = (void *)block + sizeof(*block) + block->size;
}
return 0;
}
static int sst_byt_parse_fw_image(struct sst_fw *sst_fw)
{
struct fw_header *header;
struct sst_byt_fw_module_header *module;
struct sst_dsp *dsp = sst_fw->dsp;
int ret, count;
/* Read the header information from the data pointer */
header = (struct fw_header *)sst_fw->dma_buf;
/* verify FW */
if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) ||
(sst_fw->size != header->file_size + sizeof(*header))) {
/* Invalid FW signature */
dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n");
return -EINVAL;
}
dev_dbg(dsp->dev,
"header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
header->signature, header->file_size, header->modules,
header->file_format, sizeof(*header));
module = (void *)sst_fw->dma_buf + sizeof(*header);
for (count = 0; count < header->modules; count++) {
/* module */
ret = sst_byt_parse_module(dsp, sst_fw, module);
if (ret < 0) {
dev_err(dsp->dev, "invalid module %d\n", count);
return ret;
}
module = (void *)module + sizeof(*module) + module->mod_size;
}
return 0;
}
static void sst_byt_dump_shim(struct sst_dsp *sst)
{
int i;
u64 reg;
for (i = 0; i <= 0xF0; i += 8) {
reg = sst_dsp_shim_read64_unlocked(sst, i);
if (reg)
dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n",
i, reg);
}
for (i = 0x00; i <= 0xff; i += 4) {
reg = readl(sst->addr.pci_cfg + i);
if (reg)
dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n",
i, (u32)reg);
}
}
static irqreturn_t sst_byt_irq(int irq, void *context)
{
struct sst_dsp *sst = (struct sst_dsp *) context;
u64 isrx;
irqreturn_t ret = IRQ_NONE;
spin_lock(&sst->spinlock);
isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
if (isrx & SST_ISRX_DONE) {
/* ADSP has processed the message request from IA */
sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX,
SST_BYT_IPCX_DONE, 0);
ret = IRQ_WAKE_THREAD;
}
if (isrx & SST_BYT_ISRX_REQUEST) {
/* mask message request from ADSP and do processing later */
sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
SST_BYT_IMRX_REQUEST,
SST_BYT_IMRX_REQUEST);
ret = IRQ_WAKE_THREAD;
}
spin_unlock(&sst->spinlock);
return ret;
}
static void sst_byt_boot(struct sst_dsp *sst)
{
int tries = 10;
/* release stall and wait to unstall */
sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
while (tries--) {
if (!(sst_dsp_shim_read64(sst, SST_CSR) &
SST_BYT_CSR_PWAITMODE))
break;
msleep(100);
}
if (tries < 0) {
dev_err(sst->dev, "unable to start DSP\n");
sst_byt_dump_shim(sst);
}
}
static void sst_byt_reset(struct sst_dsp *sst)
{
/* put DSP into reset, set reset vector and stall */
sst_dsp_shim_update_bits64(sst, SST_CSR,
SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL,
SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL);
udelay(10);
/* take DSP out of reset and keep stalled for FW loading */
sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0);
}
struct sst_adsp_memregion {
u32 start;
u32 end;
int blocks;
enum sst_mem_type type;
};
/* BYT test stuff */
static const struct sst_adsp_memregion byt_region[] = {
{0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */
{0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
};
static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
{
sst->addr.lpe_base = pdata->lpe_base;
sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
if (!sst->addr.lpe)
return -ENODEV;
/* ADSP PCI MMIO config space */
sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
if (!sst->addr.pci_cfg) {
iounmap(sst->addr.lpe);
return -ENODEV;
}
/* SST Extended FW allocation */
sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size);
if (!sst->addr.fw_ext) {
iounmap(sst->addr.pci_cfg);
iounmap(sst->addr.lpe);
return -ENODEV;
}
/* SST Shim */
sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204,
SST_BYT_IPC_MAX_PAYLOAD_SIZE,
SST_BYT_MAILBOX_OFFSET,
SST_BYT_IPC_MAX_PAYLOAD_SIZE);
sst->irq = pdata->irq;
return 0;
}
static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
{
const struct sst_adsp_memregion *region;
struct device *dev;
int ret = -ENODEV, i, j, region_count;
u32 offset, size;
dev = sst->dev;
switch (sst->id) {
case SST_DEV_ID_BYT:
region = byt_region;
region_count = ARRAY_SIZE(byt_region);
sst->addr.iram_offset = SST_BYT_IRAM_OFFSET;
sst->addr.dram_offset = SST_BYT_DRAM_OFFSET;
sst->addr.shim_offset = SST_BYT_SHIM_OFFSET;
break;
default:
dev_err(dev, "failed to get mem resources\n");
return ret;
}
ret = sst_byt_resource_map(sst, pdata);
if (ret < 0) {
dev_err(dev, "failed to map resources\n");
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(dev, DMA_BIT_MASK(32));
if (ret)
return ret;
/* enable Interrupt from both sides */
sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0);
sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0);
/* register DSP memory blocks - ideally we should get this from ACPI */
for (i = 0; i < region_count; i++) {
offset = region[i].start;
size = (region[i].end - region[i].start) / region[i].blocks;
/* register individual memory blocks */
for (j = 0; j < region[i].blocks; j++) {
sst_mem_block_register(sst, offset, size,
region[i].type, NULL, j, sst);
offset += size;
}
}
return 0;
}
static void sst_byt_free(struct sst_dsp *sst)
{
sst_mem_block_unregister_all(sst);
iounmap(sst->addr.lpe);
iounmap(sst->addr.pci_cfg);
iounmap(sst->addr.fw_ext);
}
struct sst_ops sst_byt_ops = {
.reset = sst_byt_reset,
.boot = sst_byt_boot,
.write = sst_shim32_write,
.read = sst_shim32_read,
.write64 = sst_shim32_write64,
.read64 = sst_shim32_read64,
.ram_read = sst_memcpy_fromio_32,
.ram_write = sst_memcpy_toio_32,
.irq_handler = sst_byt_irq,
.init = sst_byt_init,
.free = sst_byt_free,
.parse_fw = sst_byt_parse_fw_image,
};
This diff is collapsed.
/*
* Intel Baytrail SST IPC Support
* Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*/
#ifndef __SST_BYT_IPC_H
#define __SST_BYT_IPC_H
#include <linux/types.h>
struct sst_byt;
struct sst_byt_stream;
struct sst_pdata;
extern struct sst_ops sst_byt_ops;
#define SST_BYT_MAILBOX_OFFSET 0x144000
#define SST_BYT_TIMESTAMP_OFFSET (SST_BYT_MAILBOX_OFFSET + 0x800)
/**
* Upfront defined maximum message size that is
* expected by the in/out communication pipes in FW.
*/
#define SST_BYT_IPC_MAX_PAYLOAD_SIZE 200
/* stream API */
struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
uint32_t (*get_write_position)(struct sst_byt_stream *stream,
void *data),
void *data);
/* stream configuration */
int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
int bits);
int sst_byt_stream_set_channels(struct sst_byt *byt,
struct sst_byt_stream *stream, u8 channels);
int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
unsigned int rate);
int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
int codec_type, int stream_type, int operation);
int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
uint32_t buffer_addr, uint32_t buffer_size);
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_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);
int sst_byt_get_dsp_position(struct sst_byt *byt,
struct sst_byt_stream *stream, int buffer_size);
/* init */
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);
#endif
This diff is collapsed.
/*
* Intel Smart Sound Technology
*
* Copyright (C) 2013, Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#ifndef __SOUND_SOC_SST_DSP_PRIV_H
#define __SOUND_SOC_SST_DSP_PRIV_H
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
struct sst_mem_block;
struct sst_module;
struct sst_fw;
/*
* DSP Operations exported by platform Audio DSP driver.
*/
struct sst_ops {
/* DSP core boot / reset */
void (*boot)(struct sst_dsp *);
void (*reset)(struct sst_dsp *);
/* Shim IO */
void (*write)(void __iomem *addr, u32 offset, u32 value);
u32 (*read)(void __iomem *addr, u32 offset);
void (*write64)(void __iomem *addr, u32 offset, u64 value);
u64 (*read64)(void __iomem *addr, u32 offset);
/* DSP I/DRAM IO */
void (*ram_read)(struct sst_dsp *sst, void *dest, void __iomem *src,
size_t bytes);
void (*ram_write)(struct sst_dsp *sst, void __iomem *dest, void *src,
size_t bytes);
void (*dump)(struct sst_dsp *);
/* IRQ handlers */
irqreturn_t (*irq_handler)(int irq, void *context);
/* SST init and free */
int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata);
void (*free)(struct sst_dsp *sst);
/* FW module parser/loader */
int (*parse_fw)(struct sst_fw *sst_fw);
};
/*
* Audio DSP memory offsets and addresses.
*/
struct sst_addr {
u32 lpe_base;
u32 shim_offset;
u32 iram_offset;
u32 dram_offset;
void __iomem *lpe;
void __iomem *shim;
void __iomem *pci_cfg;
void __iomem *fw_ext;
};
/*
* Audio DSP Mailbox configuration.
*/
struct sst_mailbox {
void __iomem *in_base;
void __iomem *out_base;
size_t in_size;
size_t out_size;
};
/*
* Audio DSP Firmware data types.
*/
enum sst_data_type {
SST_DATA_M = 0, /* module block data */
SST_DATA_P = 1, /* peristant data (text, data) */
SST_DATA_S = 2, /* scratch data (usually buffers) */
};
/*
* Audio DSP memory block types.
*/
enum sst_mem_type {
SST_MEM_IRAM = 0,
SST_MEM_DRAM = 1,
SST_MEM_ANY = 2,
SST_MEM_CACHE= 3,
};
/*
* Audio DSP Generic Firmware File.
*
* SST Firmware files can consist of 1..N modules. This generic structure is
* used to manage each firmware file and it's modules regardless of SST firmware
* type. A SST driver may load multiple FW files.
*/
struct sst_fw {
struct sst_dsp *dsp;
/* base addresses of FW file data */
dma_addr_t dmable_fw_paddr; /* physical address of fw data */
void *dma_buf; /* virtual address of fw data */
u32 size; /* size of fw data */
/* lists */
struct list_head list; /* DSP list of FW */
struct list_head module_list; /* FW list of modules */
void *private; /* core doesn't touch this */
};
/*
* Audio DSP Generic Module data.
*
* This is used to dsecribe any sections of persistent (text and data) and
* scratch (buffers) of module data in ADSP memory space.
*/
struct sst_module_data {
enum sst_mem_type type; /* destination memory type */
enum sst_data_type data_type; /* type of module data */
u32 size; /* size in bytes */
u32 offset; /* offset in FW file */
u32 data_offset; /* offset in ADSP memory space */
void *data; /* module data */
};
/*
* Audio DSP Generic Module Template.
*
* Used to define and register a new FW module. This data is extracted from
* FW module header information.
*/
struct sst_module_template {
u32 id;
u32 entry; /* entry point */
struct sst_module_data s; /* scratch data */
struct sst_module_data p; /* peristant data */
};
/*
* Audio DSP Generic Module.
*
* Each Firmware file can consist of 1..N modules. A module can span multiple
* ADSP memory blocks. The simplest FW will be a file with 1 module.
*/
struct sst_module {
struct sst_dsp *dsp;
struct sst_fw *sst_fw; /* parent FW we belong too */
/* module configuration */
u32 id;
u32 entry; /* module entry point */
u32 offset; /* module offset in firmware file */
u32 size; /* module size */
struct sst_module_data s; /* scratch data */
struct sst_module_data p; /* peristant data */
/* runtime */
u32 usage_count; /* can be unloaded if count == 0 */
void *private; /* core doesn't touch this */
/* lists */
struct list_head block_list; /* Module list of blocks in use */
struct list_head list; /* DSP list of modules */
struct list_head list_fw; /* FW list of modules */
};
/*
* SST Memory Block operations.
*/
struct sst_block_ops {
int (*enable)(struct sst_mem_block *block);
int (*disable)(struct sst_mem_block *block);
};
/*
* SST Generic Memory Block.
*
* SST ADP memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be
* power gated.
*/
struct sst_mem_block {
struct sst_dsp *dsp;
struct sst_module *module; /* module that uses this block */
/* block config */
u32 offset; /* offset from base */
u32 size; /* block size */
u32 index; /* block index 0..N */
enum sst_mem_type type; /* block memory type IRAM/DRAM */
struct sst_block_ops *ops; /* block operations, if any */
/* block status */
enum sst_data_type data_type; /* data type held in this block */
u32 bytes_used; /* bytes in use by modules */
void *private; /* generic core does not touch this */
int users; /* number of modules using this block */
/* block lists */
struct list_head module_list; /* Module list of blocks */
struct list_head list; /* Map list of free/used blocks */
};
/*
* Generic SST Shim Interface.
*/
struct sst_dsp {
/* runtime */
struct sst_dsp_device *sst_dev;
spinlock_t spinlock; /* IPC locking */
struct mutex mutex; /* DSP FW lock */
struct device *dev;
void *thread_context;
int irq;
u32 id;
/* list of free and used ADSP memory blocks */
struct list_head used_block_list;
struct list_head free_block_list;
/* operations */
struct sst_ops *ops;
/* debug FS */
struct dentry *debugfs_root;
/* base addresses */
struct sst_addr addr;
/* mailbox */
struct sst_mailbox mailbox;
/* SST FW files loaded and their modules */
struct list_head module_list;
struct list_head fw_list;
/* platform data */
struct sst_pdata *pdata;
/* DMA FW loading */
struct sst_dma *dma;
bool fw_use_dma;
};
/* Size optimised DRAM/IRAM memcpy */
static inline void sst_dsp_write(struct sst_dsp *sst, void *src,
u32 dest_offset, size_t bytes)
{
sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes);
}
static inline void sst_dsp_read(struct sst_dsp *sst, void *dest,
u32 src_offset, size_t bytes)
{
sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes);
}
static inline void *sst_dsp_get_thread_context(struct sst_dsp *sst)
{
return sst->thread_context;
}
/* Create/Free FW files - can contain multiple modules */
struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
const struct firmware *fw, void *private);
void sst_fw_free(struct sst_fw *sst_fw);
void sst_fw_free_all(struct sst_dsp *dsp);
/* Create/Free firmware modules */
struct sst_module *sst_module_new(struct sst_fw *sst_fw,
struct sst_module_template *template, void *private);
void sst_module_free(struct sst_module *sst_module);
int sst_module_insert(struct sst_module *sst_module);
int sst_module_remove(struct sst_module *sst_module);
int sst_module_insert_fixed_block(struct sst_module *module,
struct sst_module_data *data);
struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
/* allocate/free pesistent/scratch memory regions managed by drv */
struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp);
void sst_mem_block_free_scratch(struct sst_dsp *dsp,
struct sst_module *scratch);
int sst_block_module_remove(struct sst_module *module);
/* Register the DSPs memory blocks - would be nice to read from ACPI */
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
void *private);
void sst_mem_block_unregister_all(struct sst_dsp *dsp);
#endif
/*
* Intel Smart Sound Technology (SST) DSP Core Driver
*
* Copyright (C) 2013, Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include "sst-dsp.h"
#include "sst-dsp-priv.h"
#define CREATE_TRACE_POINTS
#include <trace/events/intel-sst.h>
/* Internal generic low-level SST IO functions - can be overidden */
void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
{
writel(value, addr + offset);
}
EXPORT_SYMBOL_GPL(sst_shim32_write);
u32 sst_shim32_read(void __iomem *addr, u32 offset)
{
return readl(addr + offset);
}
EXPORT_SYMBOL_GPL(sst_shim32_read);
void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
{
memcpy_toio(addr + offset, &value, sizeof(value));
}
EXPORT_SYMBOL_GPL(sst_shim32_write64);
u64 sst_shim32_read64(void __iomem *addr, u32 offset)
{
u64 val;
memcpy_fromio(&val, addr + offset, sizeof(val));
return val;
}
EXPORT_SYMBOL_GPL(sst_shim32_read64);
static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest,
u32 *src, size_t bytes)
{
int i, words = bytes >> 2;
for (i = 0; i < words; i++)
writel(src[i], dest + i);
}
static inline void _sst_memcpy_fromio_32(u32 *dest,
const volatile __iomem u32 *src, size_t bytes)
{
int i, words = bytes >> 2;
for (i = 0; i < words; i++)
dest[i] = readl(src + i);
}
void sst_memcpy_toio_32(struct sst_dsp *sst,
void __iomem *dest, void *src, size_t bytes)
{
_sst_memcpy_toio_32(dest, src, bytes);
}
EXPORT_SYMBOL_GPL(sst_memcpy_toio_32);
void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest,
void __iomem *src, size_t bytes)
{
_sst_memcpy_fromio_32(dest, src, bytes);
}
EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32);
/* Public API */
void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
{
unsigned long flags;
spin_lock_irqsave(&sst->spinlock, flags);
sst->ops->write(sst->addr.shim, offset, value);
spin_unlock_irqrestore(&sst->spinlock, flags);
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(&sst->spinlock, flags);
val = sst->ops->read(sst->addr.shim, offset);
spin_unlock_irqrestore(&sst->spinlock, flags);
return val;
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value)
{
unsigned long flags;
spin_lock_irqsave(&sst->spinlock, flags);
sst->ops->write64(sst->addr.shim, offset, value);
spin_unlock_irqrestore(&sst->spinlock, flags);
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_write64);
u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset)
{
unsigned long flags;
u64 val;
spin_lock_irqsave(&sst->spinlock, flags);
val = sst->ops->read64(sst->addr.shim, offset);
spin_unlock_irqrestore(&sst->spinlock, flags);
return val;
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_read64);
void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
{
sst->ops->write(sst->addr.shim, offset, value);
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
{
return sst->ops->read(sst->addr.shim, offset);
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value)
{
sst->ops->write64(sst->addr.shim, offset, value);
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked);
u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset)
{
return sst->ops->read64(sst->addr.shim, offset);
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked);
int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value)
{
bool change;
unsigned int old, new;
u32 ret;
ret = sst_dsp_shim_read_unlocked(sst, offset);
old = ret;
new = (old & (~mask)) | (value & mask);
change = (old != new);
if (change)
sst_dsp_shim_write_unlocked(sst, offset, new);
return change;
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
u64 mask, u64 value)
{
bool change;
u64 old, new;
old = sst_dsp_shim_read64_unlocked(sst, offset);
new = (old & (~mask)) | (value & mask);
change = (old != new);
if (change)
sst_dsp_shim_write64_unlocked(sst, offset, new);
return change;
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value)
{
unsigned long flags;
bool change;
spin_lock_irqsave(&sst->spinlock, flags);
change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
spin_unlock_irqrestore(&sst->spinlock, flags);
return change;
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
u64 mask, u64 value)
{
unsigned long flags;
bool change;
spin_lock_irqsave(&sst->spinlock, flags);
change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value);
spin_unlock_irqrestore(&sst->spinlock, flags);
return change;
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
void sst_dsp_dump(struct sst_dsp *sst)
{
sst->ops->dump(sst);
}
EXPORT_SYMBOL_GPL(sst_dsp_dump);
void sst_dsp_reset(struct sst_dsp *sst)
{
sst->ops->reset(sst);
}
EXPORT_SYMBOL_GPL(sst_dsp_reset);
int sst_dsp_boot(struct sst_dsp *sst)
{
sst->ops->boot(sst);
return 0;
}
EXPORT_SYMBOL_GPL(sst_dsp_boot);
void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
{
sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
trace_sst_ipc_msg_tx(msg);
}
EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx);
u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp)
{
u32 msg;
msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
trace_sst_ipc_msg_rx(msg);
return msg;
}
EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx);
int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
u32 outbox_offset, size_t outbox_size)
{
sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
sst->mailbox.in_size = inbox_size;
sst->mailbox.out_size = outbox_size;
return 0;
}
EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
{
u32 i;
trace_sst_ipc_outbox_write(bytes);
memcpy_toio(sst->mailbox.out_base, message, bytes);
for (i = 0; i < bytes; i += 4)
trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
}
EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
{
u32 i;
trace_sst_ipc_outbox_read(bytes);
memcpy_fromio(message, sst->mailbox.out_base, bytes);
for (i = 0; i < bytes; i += 4)
trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
}
EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
{
u32 i;
trace_sst_ipc_inbox_write(bytes);
memcpy_toio(sst->mailbox.in_base, message, bytes);
for (i = 0; i < bytes; i += 4)
trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
}
EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
{
u32 i;
trace_sst_ipc_inbox_read(bytes);
memcpy_fromio(message, sst->mailbox.in_base, bytes);
for (i = 0; i < bytes; i += 4)
trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
}
EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
struct sst_dsp *sst_dsp_new(struct device *dev,
struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
{
struct sst_dsp *sst;
int err;
dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
if (sst == NULL)
return NULL;
spin_lock_init(&sst->spinlock);
mutex_init(&sst->mutex);
sst->dev = dev;
sst->thread_context = sst_dev->thread_context;
sst->sst_dev = sst_dev;
sst->id = pdata->id;
sst->irq = pdata->irq;
sst->ops = sst_dev->ops;
sst->pdata = pdata;
INIT_LIST_HEAD(&sst->used_block_list);
INIT_LIST_HEAD(&sst->free_block_list);
INIT_LIST_HEAD(&sst->module_list);
INIT_LIST_HEAD(&sst->fw_list);
/* Initialise SST Audio DSP */
if (sst->ops->init) {
err = sst->ops->init(sst, pdata);
if (err < 0)
return NULL;
}
/* Register the ISR */
err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
if (err)
goto irq_err;
return sst;
irq_err:
if (sst->ops->free)
sst->ops->free(sst);
return NULL;
}
EXPORT_SYMBOL_GPL(sst_dsp_new);
void sst_dsp_free(struct sst_dsp *sst)
{
free_irq(sst->irq, sst);
if (sst->ops->free)
sst->ops->free(sst);
}
EXPORT_SYMBOL_GPL(sst_dsp_free);
/* Module information */
MODULE_AUTHOR("Liam Girdwood");
MODULE_DESCRIPTION("Intel SST Core");
MODULE_LICENSE("GPL v2");
/*
* Intel Smart Sound Technology (SST) Core
*
* Copyright (C) 2013, Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#ifndef __SOUND_SOC_SST_DSP_H
#define __SOUND_SOC_SST_DSP_H
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
/* SST Device IDs */
#define SST_DEV_ID_LYNX_POINT 0x33C8
#define SST_DEV_ID_WILDCAT_POINT 0x3438
#define SST_DEV_ID_BYT 0x0F28
/* Supported SST DMA Devices */
#define SST_DMA_TYPE_DW 1
#define SST_DMA_TYPE_MID 2
/* SST Shim register map
* The register naming can differ between products. Some products also
* contain extra functionality.
*/
#define SST_CSR 0x00
#define SST_PISR 0x08
#define SST_PIMR 0x10
#define SST_ISRX 0x18
#define SST_ISRD 0x20
#define SST_IMRX 0x28
#define SST_IMRD 0x30
#define SST_IPCX 0x38 /* IPC IA -> SST */
#define SST_IPCD 0x40 /* IPC SST -> IA */
#define SST_ISRSC 0x48
#define SST_ISRLPESC 0x50
#define SST_IMRSC 0x58
#define SST_IMRLPESC 0x60
#define SST_IPCSC 0x68
#define SST_IPCLPESC 0x70
#define SST_CLKCTL 0x78
#define SST_CSR2 0x80
#define SST_LTRC 0xE0
#define SST_HDMC 0xE8
#define SST_DBGO 0xF0
#define SST_SHIM_SIZE 0x100
#define SST_PWMCTRL 0x1000
/* SST Shim Register bits
* The register bit naming can differ between products. Some products also
* contain extra functionality.
*/
/* CSR / CS */
#define SST_CSR_RST (0x1 << 1)
#define SST_CSR_SBCS0 (0x1 << 2)
#define SST_CSR_SBCS1 (0x1 << 3)
#define SST_CSR_DCS(x) (x << 4)
#define SST_CSR_DCS_MASK (0x7 << 4)
#define SST_CSR_STALL (0x1 << 10)
#define SST_CSR_S0IOCS (0x1 << 21)
#define SST_CSR_S1IOCS (0x1 << 23)
#define SST_CSR_LPCS (0x1 << 31)
#define SST_BYT_CSR_RST (0x1 << 0)
#define SST_BYT_CSR_VECTOR_SEL (0x1 << 1)
#define SST_BYT_CSR_STALL (0x1 << 2)
#define SST_BYT_CSR_PWAITMODE (0x1 << 3)
/* ISRX / ISC */
#define SST_ISRX_BUSY (0x1 << 1)
#define SST_ISRX_DONE (0x1 << 0)
#define SST_BYT_ISRX_REQUEST (0x1 << 1)
/* ISRD / ISD */
#define SST_ISRD_BUSY (0x1 << 1)
#define SST_ISRD_DONE (0x1 << 0)
/* IMRX / IMC */
#define SST_IMRX_BUSY (0x1 << 1)
#define SST_IMRX_DONE (0x1 << 0)
#define SST_BYT_IMRX_REQUEST (0x1 << 1)
/* IPCX / IPCC */
#define SST_IPCX_DONE (0x1 << 30)
#define SST_IPCX_BUSY (0x1 << 31)
#define SST_BYT_IPCX_DONE ((u64)0x1 << 62)
#define SST_BYT_IPCX_BUSY ((u64)0x1 << 63)
/* IPCD */
#define SST_IPCD_DONE (0x1 << 30)
#define SST_IPCD_BUSY (0x1 << 31)
#define SST_BYT_IPCD_DONE ((u64)0x1 << 62)
#define SST_BYT_IPCD_BUSY ((u64)0x1 << 63)
/* CLKCTL */
#define SST_CLKCTL_SMOS(x) (x << 24)
#define SST_CLKCTL_MASK (3 << 24)
#define SST_CLKCTL_DCPLCG (1 << 18)
#define SST_CLKCTL_SCOE1 (1 << 17)
#define SST_CLKCTL_SCOE0 (1 << 16)
/* CSR2 / CS2 */
#define SST_CSR2_SDFD_SSP0 (1 << 1)
#define SST_CSR2_SDFD_SSP1 (1 << 2)
/* LTRC */
#define SST_LTRC_VAL(x) (x << 0)
/* HDMC */
#define SST_HDMC_HDDA0(x) (x << 0)
#define SST_HDMC_HDDA1(x) (x << 7)
/* SST Vendor Defined Registers and bits */
#define SST_VDRTCTL0 0xa0
#define SST_VDRTCTL1 0xa4
#define SST_VDRTCTL2 0xa8
#define SST_VDRTCTL3 0xaC
/* VDRTCTL0 */
#define SST_VDRTCL0_DSRAMPGE_SHIFT 16
#define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
#define SST_VDRTCL0_ISRAMPGE_SHIFT 6
#define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
struct sst_dsp;
/*
* SST Device.
*
* This structure is populated by the SST core driver.
*/
struct sst_dsp_device {
/* Mandatory fields */
struct sst_ops *ops;
irqreturn_t (*thread)(int irq, void *context);
void *thread_context;
};
/*
* SST Platform Data.
*/
struct sst_pdata {
/* ACPI data */
u32 lpe_base;
u32 lpe_size;
u32 pcicfg_base;
u32 pcicfg_size;
u32 fw_base;
u32 fw_size;
int irq;
/* Firmware */
const struct firmware *fw;
/* DMA */
u32 dma_base;
u32 dma_size;
int dma_engine;
/* DSP */
u32 id;
void *dsp;
};
/* Initialization */
struct sst_dsp *sst_dsp_new(struct device *dev,
struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
void sst_dsp_free(struct sst_dsp *sst);
/* SHIM Read / Write */
void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset);
int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value);
void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value);
u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset);
int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
u64 mask, u64 value);
/* SHIM Read / Write Unlocked for callers already holding sst lock */
void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset);
int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value);
void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value);
u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset);
int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
u64 mask, u64 value);
/* Internal generic low-level SST IO functions - can be overidden */
void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
u32 sst_shim32_read(void __iomem *addr, u32 offset);
void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value);
u64 sst_shim32_read64(void __iomem *addr, u32 offset);
void sst_memcpy_toio_32(struct sst_dsp *sst,
void __iomem *dest, void *src, size_t bytes);
void sst_memcpy_fromio_32(struct sst_dsp *sst,
void *dest, void __iomem *src, size_t bytes);
/* DSP reset & boot */
void sst_dsp_reset(struct sst_dsp *sst);
int sst_dsp_boot(struct sst_dsp *sst);
/* Msg IO */
void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);
u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp);
/* Mailbox management */
int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset,
size_t inbox_size, u32 outbox_offset, size_t outbox_size);
void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes);
/* Debug */
void sst_dsp_dump(struct sst_dsp *sst);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef __SST_DSP_H__ #ifndef __SST_MFLD_DSP_H__
#define __SST_DSP_H__ #define __SST_MFLD_DSP_H__
/* /*
* sst_dsp.h - Intel SST Driver for audio engine * sst_mfld_dsp.h - Intel SST Driver for audio engine
* *
* Copyright (C) 2008-12 Intel Corporation * Copyright (C) 2008-12 Intel Corporation
* Authors: Vinod Koul <vinod.koul@linux.intel.com> * Authors: Vinod Koul <vinod.koul@linux.intel.com>
...@@ -131,4 +131,4 @@ struct snd_sst_params { ...@@ -131,4 +131,4 @@ struct snd_sst_params {
struct snd_sst_alloc_params_ext aparams; struct snd_sst_alloc_params_ext aparams;
}; };
#endif /* __SST_DSP_H__ */ #endif /* __SST_MFLD_DSP_H__ */
/* /*
* sst_platform.c - Intel MID Platform driver * sst_mfld_platform.c - Intel MID Platform driver
* *
* Copyright (C) 2010-2013 Intel Corp * Copyright (C) 2010-2013 Intel Corp
* Author: Vinod Koul <vinod.koul@intel.com> * Author: Vinod Koul <vinod.koul@intel.com>
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/compress_driver.h> #include <sound/compress_driver.h>
#include "sst_platform.h" #include "sst-mfld-platform.h"
static struct sst_device *sst; static struct sst_device *sst;
static DEFINE_MUTEX(sst_lock); static DEFINE_MUTEX(sst_lock);
...@@ -709,7 +709,7 @@ static int sst_platform_remove(struct platform_device *pdev) ...@@ -709,7 +709,7 @@ static int sst_platform_remove(struct platform_device *pdev)
static struct platform_driver sst_platform_driver = { static struct platform_driver sst_platform_driver = {
.driver = { .driver = {
.name = "sst-platform", .name = "sst-mfld-platform",
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = sst_platform_probe, .probe = sst_platform_probe,
...@@ -722,4 +722,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver"); ...@@ -722,4 +722,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:sst-platform"); MODULE_ALIAS("platform:sst-mfld-platform");
/* /*
* sst_platform.h - Intel MID Platform driver header file * sst_mfld_platform.h - Intel MID Platform driver header file
* *
* Copyright (C) 2010 Intel Corp * Copyright (C) 2010 Intel Corp
* Author: Vinod Koul <vinod.koul@intel.com> * Author: Vinod Koul <vinod.koul@intel.com>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifndef __SST_PLATFORMDRV_H__ #ifndef __SST_PLATFORMDRV_H__
#define __SST_PLATFORMDRV_H__ #define __SST_PLATFORMDRV_H__
#include "sst_dsp.h" #include "sst-mfld-dsp.h"
#define SST_MONO 1 #define SST_MONO 1
#define SST_STEREO 2 #define SST_STEREO 2
......
...@@ -196,13 +196,11 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol, ...@@ -196,13 +196,11 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
static const struct soc_enum ams_delta_audio_enum[] = { static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum,
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ams_delta_audio_mode), ams_delta_audio_mode);
ams_delta_audio_mode),
};
static const struct snd_kcontrol_new ams_delta_audio_controls[] = { static const struct snd_kcontrol_new ams_delta_audio_controls[] = {
SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum[0], SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum,
ams_delta_get_audio_mode, ams_delta_set_audio_mode), ams_delta_get_audio_mode, ams_delta_set_audio_mode),
}; };
......
...@@ -101,14 +101,9 @@ static void corgi_ext_control(struct snd_soc_dapm_context *dapm) ...@@ -101,14 +101,9 @@ static void corgi_ext_control(struct snd_soc_dapm_context *dapm)
static int corgi_startup(struct snd_pcm_substream *substream) static int corgi_startup(struct snd_pcm_substream *substream)
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&codec->mutex);
/* check the jack status at stream startup */ /* check the jack status at stream startup */
corgi_ext_control(&codec->dapm); corgi_ext_control(&rtd->card->dapm);
mutex_unlock(&codec->mutex);
return 0; return 0;
} }
......
...@@ -103,11 +103,6 @@ static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd) ...@@ -103,11 +103,6 @@ static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "PCBEEP"); snd_soc_dapm_nc_pin(dapm, "PCBEEP");
snd_soc_dapm_nc_pin(dapm, "MIC2"); snd_soc_dapm_nc_pin(dapm, "MIC2");
snd_soc_dapm_new_controls(dapm, e740_dapm_widgets,
ARRAY_SIZE(e740_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0; return 0;
} }
...@@ -136,6 +131,11 @@ static struct snd_soc_card e740 = { ...@@ -136,6 +131,11 @@ static struct snd_soc_card e740 = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dai_link = e740_dai, .dai_link = e740_dai,
.num_links = ARRAY_SIZE(e740_dai), .num_links = ARRAY_SIZE(e740_dai),
.dapm_widgets = e740_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
}; };
static struct gpio e740_audio_gpios[] = { static struct gpio e740_audio_gpios[] = {
......
...@@ -85,11 +85,6 @@ static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd) ...@@ -85,11 +85,6 @@ static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "PCBEEP"); snd_soc_dapm_nc_pin(dapm, "PCBEEP");
snd_soc_dapm_nc_pin(dapm, "MIC2"); snd_soc_dapm_nc_pin(dapm, "MIC2");
snd_soc_dapm_new_controls(dapm, e750_dapm_widgets,
ARRAY_SIZE(e750_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0; return 0;
} }
...@@ -119,6 +114,11 @@ static struct snd_soc_card e750 = { ...@@ -119,6 +114,11 @@ static struct snd_soc_card e750 = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dai_link = e750_dai, .dai_link = e750_dai,
.num_links = ARRAY_SIZE(e750_dai), .num_links = ARRAY_SIZE(e750_dai),
.dapm_widgets = e750_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(e750_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
}; };
static struct gpio e750_audio_gpios[] = { static struct gpio e750_audio_gpios[] = {
......
...@@ -71,19 +71,6 @@ static const struct snd_soc_dapm_route audio_map[] = { ...@@ -71,19 +71,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MIC2", NULL, "Mic (Internal2)"}, {"MIC2", NULL, "Mic (Internal2)"},
}; };
static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, e800_dapm_widgets,
ARRAY_SIZE(e800_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
static struct snd_soc_dai_link e800_dai[] = { static struct snd_soc_dai_link e800_dai[] = {
{ {
.name = "AC97", .name = "AC97",
...@@ -92,7 +79,6 @@ static struct snd_soc_dai_link e800_dai[] = { ...@@ -92,7 +79,6 @@ static struct snd_soc_dai_link e800_dai[] = {
.codec_dai_name = "wm9712-hifi", .codec_dai_name = "wm9712-hifi",
.platform_name = "pxa-pcm-audio", .platform_name = "pxa-pcm-audio",
.codec_name = "wm9712-codec", .codec_name = "wm9712-codec",
.init = e800_ac97_init,
}, },
{ {
.name = "AC97 Aux", .name = "AC97 Aux",
...@@ -109,6 +95,11 @@ static struct snd_soc_card e800 = { ...@@ -109,6 +95,11 @@ static struct snd_soc_card e800 = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dai_link = e800_dai, .dai_link = e800_dai,
.num_links = ARRAY_SIZE(e800_dai), .num_links = ARRAY_SIZE(e800_dai),
.dapm_widgets = e800_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(e800_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
}; };
static struct gpio e800_audio_gpios[] = { static struct gpio e800_audio_gpios[] = {
......
...@@ -77,13 +77,9 @@ static int magician_startup(struct snd_pcm_substream *substream) ...@@ -77,13 +77,9 @@ static int magician_startup(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&codec->mutex);
/* check the jack status at stream startup */ /* check the jack status at stream startup */
magician_ext_control(codec); magician_ext_control(codec);
mutex_unlock(&codec->mutex);
return 0; return 0;
} }
......
...@@ -127,16 +127,8 @@ static const struct snd_soc_dapm_route audio_map[] = { ...@@ -127,16 +127,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
unsigned short reg; unsigned short reg;
/* Add mioa701 specific widgets */
snd_soc_dapm_new_controls(dapm, mioa701_dapm_widgets,
ARRAY_SIZE(mioa701_dapm_widgets));
/* Set up mioa701 specific audio path audio_mapnects */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
/* Prepare GPIO8 for rear speaker amplifier */ /* Prepare GPIO8 for rear speaker amplifier */
reg = codec->driver->read(codec, AC97_GPIO_CFG); reg = codec->driver->read(codec, AC97_GPIO_CFG);
codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100); codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100);
...@@ -145,12 +137,6 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) ...@@ -145,12 +137,6 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
reg = codec->driver->read(codec, AC97_3D_CONTROL); reg = codec->driver->read(codec, AC97_3D_CONTROL);
codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000); codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000);
snd_soc_dapm_enable_pin(dapm, "Front Speaker");
snd_soc_dapm_enable_pin(dapm, "Rear Speaker");
snd_soc_dapm_enable_pin(dapm, "Front Mic");
snd_soc_dapm_enable_pin(dapm, "GSM Line In");
snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
return 0; return 0;
} }
...@@ -183,6 +169,11 @@ static struct snd_soc_card mioa701 = { ...@@ -183,6 +169,11 @@ static struct snd_soc_card mioa701 = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dai_link = mioa701_dai, .dai_link = mioa701_dai,
.num_links = ARRAY_SIZE(mioa701_dai), .num_links = ARRAY_SIZE(mioa701_dai),
.dapm_widgets = mioa701_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(mioa701_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
}; };
static int mioa701_wm9713_probe(struct platform_device *pdev) static int mioa701_wm9713_probe(struct platform_device *pdev)
......
...@@ -74,14 +74,9 @@ static void poodle_ext_control(struct snd_soc_dapm_context *dapm) ...@@ -74,14 +74,9 @@ static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
static int poodle_startup(struct snd_pcm_substream *substream) static int poodle_startup(struct snd_pcm_substream *substream)
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&codec->mutex);
/* check the jack status at stream startup */ /* check the jack status at stream startup */
poodle_ext_control(&codec->dapm); poodle_ext_control(&rtd->card->dapm);
mutex_unlock(&codec->mutex);
return 0; return 0;
} }
......
...@@ -111,14 +111,9 @@ static void spitz_ext_control(struct snd_soc_dapm_context *dapm) ...@@ -111,14 +111,9 @@ static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
static int spitz_startup(struct snd_pcm_substream *substream) static int spitz_startup(struct snd_pcm_substream *substream)
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&codec->mutex);
/* check the jack status at stream startup */ /* check the jack status at stream startup */
spitz_ext_control(&codec->dapm); spitz_ext_control(&rtd->card->dapm);
mutex_unlock(&codec->mutex);
return 0; return 0;
} }
......
...@@ -84,13 +84,9 @@ static int tosa_startup(struct snd_pcm_substream *substream) ...@@ -84,13 +84,9 @@ static int tosa_startup(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
mutex_lock(&codec->mutex);
/* check the jack status at stream startup */ /* check the jack status at stream startup */
tosa_ext_control(codec); tosa_ext_control(codec);
mutex_unlock(&codec->mutex);
return 0; return 0;
} }
......
This diff is collapsed.
snd-soc-rcar-objs := core.o gen.o scu.o adg.o ssi.o snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment