1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (c) 2020 BayLibre, SAS.
4 // Author: Jerome Brunet <jbrunet@baylibre.com>
6 #include <linux/bitfield.h>
8 #include <linux/dma-mapping.h>
9 #include <sound/pcm_params.h>
10 #include <sound/soc.h>
11 #include <sound/soc-dai.h>
15 #define AIU_MEM_START 0x00
16 #define AIU_MEM_RD 0x04
17 #define AIU_MEM_END 0x08
18 #define AIU_MEM_MASKS 0x0c
19 #define AIU_MEM_MASK_CH_RD GENMASK(7, 0)
20 #define AIU_MEM_MASK_CH_MEM GENMASK(15, 8)
21 #define AIU_MEM_CONTROL 0x10
22 #define AIU_MEM_CONTROL_INIT BIT(0)
23 #define AIU_MEM_CONTROL_FILL_EN BIT(1)
24 #define AIU_MEM_CONTROL_EMPTY_EN BIT(2)
26 static struct snd_soc_dai
*aiu_fifo_dai(struct snd_pcm_substream
*ss
)
28 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(ss
);
30 return snd_soc_rtd_to_cpu(rtd
, 0);
33 snd_pcm_uframes_t
aiu_fifo_pointer(struct snd_soc_component
*component
,
34 struct snd_pcm_substream
*substream
)
36 struct snd_soc_dai
*dai
= aiu_fifo_dai(substream
);
37 struct aiu_fifo
*fifo
= snd_soc_dai_dma_data_get_playback(dai
);
38 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
41 addr
= snd_soc_component_read(component
, fifo
->mem_offset
+ AIU_MEM_RD
);
43 return bytes_to_frames(runtime
, addr
- (unsigned int)runtime
->dma_addr
);
46 static void aiu_fifo_enable(struct snd_soc_dai
*dai
, bool enable
)
48 struct snd_soc_component
*component
= dai
->component
;
49 struct aiu_fifo
*fifo
= snd_soc_dai_dma_data_get_playback(dai
);
50 unsigned int en_mask
= (AIU_MEM_CONTROL_FILL_EN
|
51 AIU_MEM_CONTROL_EMPTY_EN
);
53 snd_soc_component_update_bits(component
,
54 fifo
->mem_offset
+ AIU_MEM_CONTROL
,
55 en_mask
, enable
? en_mask
: 0);
58 int aiu_fifo_trigger(struct snd_pcm_substream
*substream
, int cmd
,
59 struct snd_soc_dai
*dai
)
62 case SNDRV_PCM_TRIGGER_START
:
63 case SNDRV_PCM_TRIGGER_RESUME
:
64 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
65 aiu_fifo_enable(dai
, true);
67 case SNDRV_PCM_TRIGGER_SUSPEND
:
68 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
69 case SNDRV_PCM_TRIGGER_STOP
:
70 aiu_fifo_enable(dai
, false);
79 int aiu_fifo_prepare(struct snd_pcm_substream
*substream
,
80 struct snd_soc_dai
*dai
)
82 struct snd_soc_component
*component
= dai
->component
;
83 struct aiu_fifo
*fifo
= snd_soc_dai_dma_data_get_playback(dai
);
85 snd_soc_component_update_bits(component
,
86 fifo
->mem_offset
+ AIU_MEM_CONTROL
,
88 AIU_MEM_CONTROL_INIT
);
89 snd_soc_component_update_bits(component
,
90 fifo
->mem_offset
+ AIU_MEM_CONTROL
,
91 AIU_MEM_CONTROL_INIT
, 0);
95 int aiu_fifo_hw_params(struct snd_pcm_substream
*substream
,
96 struct snd_pcm_hw_params
*params
,
97 struct snd_soc_dai
*dai
)
99 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
100 struct snd_soc_component
*component
= dai
->component
;
101 struct aiu_fifo
*fifo
= snd_soc_dai_dma_data_get_playback(dai
);
104 /* Setup the fifo boundaries */
105 end
= runtime
->dma_addr
+ runtime
->dma_bytes
- fifo
->fifo_block
;
106 snd_soc_component_write(component
, fifo
->mem_offset
+ AIU_MEM_START
,
108 snd_soc_component_write(component
, fifo
->mem_offset
+ AIU_MEM_RD
,
110 snd_soc_component_write(component
, fifo
->mem_offset
+ AIU_MEM_END
,
113 /* Setup the fifo to read all the memory - no skip */
114 snd_soc_component_update_bits(component
,
115 fifo
->mem_offset
+ AIU_MEM_MASKS
,
116 AIU_MEM_MASK_CH_RD
| AIU_MEM_MASK_CH_MEM
,
117 FIELD_PREP(AIU_MEM_MASK_CH_RD
, 0xff) |
118 FIELD_PREP(AIU_MEM_MASK_CH_MEM
, 0xff));
123 static irqreturn_t
aiu_fifo_isr(int irq
, void *dev_id
)
125 struct snd_pcm_substream
*playback
= dev_id
;
127 snd_pcm_period_elapsed(playback
);
132 int aiu_fifo_startup(struct snd_pcm_substream
*substream
,
133 struct snd_soc_dai
*dai
)
135 struct aiu_fifo
*fifo
= snd_soc_dai_dma_data_get_playback(dai
);
138 snd_soc_set_runtime_hwparams(substream
, fifo
->pcm
);
141 * Make sure the buffer and period size are multiple of the fifo burst
144 ret
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
145 SNDRV_PCM_HW_PARAM_BUFFER_BYTES
,
150 ret
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
151 SNDRV_PCM_HW_PARAM_PERIOD_BYTES
,
156 ret
= clk_prepare_enable(fifo
->pclk
);
160 ret
= request_irq(fifo
->irq
, aiu_fifo_isr
, 0, dev_name(dai
->dev
),
163 clk_disable_unprepare(fifo
->pclk
);
168 void aiu_fifo_shutdown(struct snd_pcm_substream
*substream
,
169 struct snd_soc_dai
*dai
)
171 struct aiu_fifo
*fifo
= snd_soc_dai_dma_data_get_playback(dai
);
173 free_irq(fifo
->irq
, substream
);
174 clk_disable_unprepare(fifo
->pclk
);
177 int aiu_fifo_pcm_new(struct snd_soc_pcm_runtime
*rtd
,
178 struct snd_soc_dai
*dai
)
180 struct snd_card
*card
= rtd
->card
->snd_card
;
181 struct aiu_fifo
*fifo
= snd_soc_dai_dma_data_get_playback(dai
);
182 size_t size
= fifo
->pcm
->buffer_bytes_max
;
185 ret
= dma_coerce_mask_and_coherent(card
->dev
, DMA_BIT_MASK(32));
189 snd_pcm_set_managed_buffer_all(rtd
->pcm
, SNDRV_DMA_TYPE_DEV
,
190 card
->dev
, size
, size
);
195 int aiu_fifo_dai_probe(struct snd_soc_dai
*dai
)
197 struct aiu_fifo
*fifo
;
199 fifo
= kzalloc(sizeof(*fifo
), GFP_KERNEL
);
203 snd_soc_dai_dma_data_set_playback(dai
, fifo
);
208 int aiu_fifo_dai_remove(struct snd_soc_dai
*dai
)
210 struct aiu_fifo
*fifo
= snd_soc_dai_dma_data_get_playback(dai
);