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 <sound/pcm_params.h>
10 #include <sound/soc-dai.h>
14 #define AIU_MEM_START 0x00
15 #define AIU_MEM_RD 0x04
16 #define AIU_MEM_END 0x08
17 #define AIU_MEM_MASKS 0x0c
18 #define AIU_MEM_MASK_CH_RD GENMASK(7, 0)
19 #define AIU_MEM_MASK_CH_MEM GENMASK(15, 8)
20 #define AIU_MEM_CONTROL 0x10
21 #define AIU_MEM_CONTROL_INIT BIT(0)
22 #define AIU_MEM_CONTROL_FILL_EN BIT(1)
23 #define AIU_MEM_CONTROL_EMPTY_EN BIT(2)
25 static struct snd_soc_dai
*aiu_fifo_dai(struct snd_pcm_substream
*ss
)
27 struct snd_soc_pcm_runtime
*rtd
= ss
->private_data
;
29 return asoc_rtd_to_cpu(rtd
, 0);
32 snd_pcm_uframes_t
aiu_fifo_pointer(struct snd_soc_component
*component
,
33 struct snd_pcm_substream
*substream
)
35 struct snd_soc_dai
*dai
= aiu_fifo_dai(substream
);
36 struct aiu_fifo
*fifo
= dai
->playback_dma_data
;
37 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
40 addr
= snd_soc_component_read(component
, fifo
->mem_offset
+ AIU_MEM_RD
);
42 return bytes_to_frames(runtime
, addr
- (unsigned int)runtime
->dma_addr
);
45 static void aiu_fifo_enable(struct snd_soc_dai
*dai
, bool enable
)
47 struct snd_soc_component
*component
= dai
->component
;
48 struct aiu_fifo
*fifo
= dai
->playback_dma_data
;
49 unsigned int en_mask
= (AIU_MEM_CONTROL_FILL_EN
|
50 AIU_MEM_CONTROL_EMPTY_EN
);
52 snd_soc_component_update_bits(component
,
53 fifo
->mem_offset
+ AIU_MEM_CONTROL
,
54 en_mask
, enable
? en_mask
: 0);
57 int aiu_fifo_trigger(struct snd_pcm_substream
*substream
, int cmd
,
58 struct snd_soc_dai
*dai
)
61 case SNDRV_PCM_TRIGGER_START
:
62 case SNDRV_PCM_TRIGGER_RESUME
:
63 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
64 aiu_fifo_enable(dai
, true);
66 case SNDRV_PCM_TRIGGER_SUSPEND
:
67 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
68 case SNDRV_PCM_TRIGGER_STOP
:
69 aiu_fifo_enable(dai
, false);
78 int aiu_fifo_prepare(struct snd_pcm_substream
*substream
,
79 struct snd_soc_dai
*dai
)
81 struct snd_soc_component
*component
= dai
->component
;
82 struct aiu_fifo
*fifo
= dai
->playback_dma_data
;
84 snd_soc_component_update_bits(component
,
85 fifo
->mem_offset
+ AIU_MEM_CONTROL
,
87 AIU_MEM_CONTROL_INIT
);
88 snd_soc_component_update_bits(component
,
89 fifo
->mem_offset
+ AIU_MEM_CONTROL
,
90 AIU_MEM_CONTROL_INIT
, 0);
94 int aiu_fifo_hw_params(struct snd_pcm_substream
*substream
,
95 struct snd_pcm_hw_params
*params
,
96 struct snd_soc_dai
*dai
)
98 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
99 struct snd_soc_component
*component
= dai
->component
;
100 struct aiu_fifo
*fifo
= dai
->playback_dma_data
;
104 ret
= snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
108 /* Setup the fifo boundaries */
109 end
= runtime
->dma_addr
+ runtime
->dma_bytes
- fifo
->fifo_block
;
110 snd_soc_component_write(component
, fifo
->mem_offset
+ AIU_MEM_START
,
112 snd_soc_component_write(component
, fifo
->mem_offset
+ AIU_MEM_RD
,
114 snd_soc_component_write(component
, fifo
->mem_offset
+ AIU_MEM_END
,
117 /* Setup the fifo to read all the memory - no skip */
118 snd_soc_component_update_bits(component
,
119 fifo
->mem_offset
+ AIU_MEM_MASKS
,
120 AIU_MEM_MASK_CH_RD
| AIU_MEM_MASK_CH_MEM
,
121 FIELD_PREP(AIU_MEM_MASK_CH_RD
, 0xff) |
122 FIELD_PREP(AIU_MEM_MASK_CH_MEM
, 0xff));
127 int aiu_fifo_hw_free(struct snd_pcm_substream
*substream
,
128 struct snd_soc_dai
*dai
)
130 return snd_pcm_lib_free_pages(substream
);
133 static irqreturn_t
aiu_fifo_isr(int irq
, void *dev_id
)
135 struct snd_pcm_substream
*playback
= dev_id
;
137 snd_pcm_period_elapsed(playback
);
142 int aiu_fifo_startup(struct snd_pcm_substream
*substream
,
143 struct snd_soc_dai
*dai
)
145 struct aiu_fifo
*fifo
= dai
->playback_dma_data
;
148 snd_soc_set_runtime_hwparams(substream
, fifo
->pcm
);
151 * Make sure the buffer and period size are multiple of the fifo burst
154 ret
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
155 SNDRV_PCM_HW_PARAM_BUFFER_BYTES
,
160 ret
= snd_pcm_hw_constraint_step(substream
->runtime
, 0,
161 SNDRV_PCM_HW_PARAM_PERIOD_BYTES
,
166 ret
= clk_prepare_enable(fifo
->pclk
);
170 ret
= request_irq(fifo
->irq
, aiu_fifo_isr
, 0, dev_name(dai
->dev
),
173 clk_disable_unprepare(fifo
->pclk
);
178 void aiu_fifo_shutdown(struct snd_pcm_substream
*substream
,
179 struct snd_soc_dai
*dai
)
181 struct aiu_fifo
*fifo
= dai
->playback_dma_data
;
183 free_irq(fifo
->irq
, substream
);
184 clk_disable_unprepare(fifo
->pclk
);
187 int aiu_fifo_pcm_new(struct snd_soc_pcm_runtime
*rtd
,
188 struct snd_soc_dai
*dai
)
190 struct snd_pcm_substream
*substream
=
191 rtd
->pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
;
192 struct snd_card
*card
= rtd
->card
->snd_card
;
193 struct aiu_fifo
*fifo
= dai
->playback_dma_data
;
194 size_t size
= fifo
->pcm
->buffer_bytes_max
;
196 snd_pcm_lib_preallocate_pages(substream
,
198 card
->dev
, size
, size
);
203 int aiu_fifo_dai_probe(struct snd_soc_dai
*dai
)
205 struct aiu_fifo
*fifo
;
207 fifo
= kzalloc(sizeof(*fifo
), GFP_KERNEL
);
211 dai
->playback_dma_data
= fifo
;
216 int aiu_fifo_dai_remove(struct snd_soc_dai
*dai
)
218 kfree(dai
->playback_dma_data
);