.. | .. |
---|
19 | 19 | * This file implements the platform operations common to the playback and |
---|
20 | 20 | * capture frontend DAI. The logic behind this two types of fifo is very |
---|
21 | 21 | * similar but some difference exist. |
---|
22 | | - * These differences the respective DAI drivers |
---|
| 22 | + * These differences are handled in the respective DAI drivers |
---|
23 | 23 | */ |
---|
24 | 24 | |
---|
25 | 25 | static struct snd_pcm_hardware axg_fifo_hw = { |
---|
.. | .. |
---|
34 | 34 | .rate_max = 192000, |
---|
35 | 35 | .channels_min = 1, |
---|
36 | 36 | .channels_max = AXG_FIFO_CH_MAX, |
---|
37 | | - .period_bytes_min = AXG_FIFO_MIN_DEPTH, |
---|
| 37 | + .period_bytes_min = AXG_FIFO_BURST, |
---|
38 | 38 | .period_bytes_max = UINT_MAX, |
---|
39 | 39 | .periods_min = 2, |
---|
40 | 40 | .periods_max = UINT_MAX, |
---|
.. | .. |
---|
47 | 47 | { |
---|
48 | 48 | struct snd_soc_pcm_runtime *rtd = ss->private_data; |
---|
49 | 49 | |
---|
50 | | - return rtd->cpu_dai; |
---|
| 50 | + return asoc_rtd_to_cpu(rtd, 0); |
---|
51 | 51 | } |
---|
52 | 52 | |
---|
53 | 53 | static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss) |
---|
.. | .. |
---|
70 | 70 | enable ? CTRL0_DMA_EN : 0); |
---|
71 | 71 | } |
---|
72 | 72 | |
---|
73 | | -static int axg_fifo_pcm_trigger(struct snd_pcm_substream *ss, int cmd) |
---|
| 73 | +int axg_fifo_pcm_trigger(struct snd_soc_component *component, |
---|
| 74 | + struct snd_pcm_substream *ss, int cmd) |
---|
74 | 75 | { |
---|
75 | 76 | struct axg_fifo *fifo = axg_fifo_data(ss); |
---|
76 | 77 | |
---|
.. | .. |
---|
91 | 92 | |
---|
92 | 93 | return 0; |
---|
93 | 94 | } |
---|
| 95 | +EXPORT_SYMBOL_GPL(axg_fifo_pcm_trigger); |
---|
94 | 96 | |
---|
95 | | -static snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_pcm_substream *ss) |
---|
| 97 | +snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_soc_component *component, |
---|
| 98 | + struct snd_pcm_substream *ss) |
---|
96 | 99 | { |
---|
97 | 100 | struct axg_fifo *fifo = axg_fifo_data(ss); |
---|
98 | 101 | struct snd_pcm_runtime *runtime = ss->runtime; |
---|
.. | .. |
---|
102 | 105 | |
---|
103 | 106 | return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); |
---|
104 | 107 | } |
---|
| 108 | +EXPORT_SYMBOL_GPL(axg_fifo_pcm_pointer); |
---|
105 | 109 | |
---|
106 | | -static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss, |
---|
107 | | - struct snd_pcm_hw_params *params) |
---|
| 110 | +int axg_fifo_pcm_hw_params(struct snd_soc_component *component, |
---|
| 111 | + struct snd_pcm_substream *ss, |
---|
| 112 | + struct snd_pcm_hw_params *params) |
---|
108 | 113 | { |
---|
109 | 114 | struct snd_pcm_runtime *runtime = ss->runtime; |
---|
110 | 115 | struct axg_fifo *fifo = axg_fifo_data(ss); |
---|
| 116 | + unsigned int burst_num, period, threshold; |
---|
111 | 117 | dma_addr_t end_ptr; |
---|
112 | | - unsigned int burst_num; |
---|
113 | | - int ret; |
---|
114 | 118 | |
---|
115 | | - ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(params)); |
---|
116 | | - if (ret < 0) |
---|
117 | | - return ret; |
---|
| 119 | + period = params_period_bytes(params); |
---|
118 | 120 | |
---|
119 | 121 | /* Setup dma memory pointers */ |
---|
120 | 122 | end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST; |
---|
.. | .. |
---|
122 | 124 | regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr); |
---|
123 | 125 | |
---|
124 | 126 | /* Setup interrupt periodicity */ |
---|
125 | | - burst_num = params_period_bytes(params) / AXG_FIFO_BURST; |
---|
| 127 | + burst_num = period / AXG_FIFO_BURST; |
---|
126 | 128 | regmap_write(fifo->map, FIFO_INT_ADDR, burst_num); |
---|
| 129 | + |
---|
| 130 | + /* |
---|
| 131 | + * Start the fifo request on the smallest of the following: |
---|
| 132 | + * - Half the fifo size |
---|
| 133 | + * - Half the period size |
---|
| 134 | + */ |
---|
| 135 | + threshold = min(period / 2, fifo->depth / 2); |
---|
| 136 | + |
---|
| 137 | + /* |
---|
| 138 | + * With the threshold in bytes, register value is: |
---|
| 139 | + * V = (threshold / burst) - 1 |
---|
| 140 | + */ |
---|
| 141 | + threshold /= AXG_FIFO_BURST; |
---|
| 142 | + regmap_field_write(fifo->field_threshold, |
---|
| 143 | + threshold ? threshold - 1 : 0); |
---|
127 | 144 | |
---|
128 | 145 | /* Enable block count irq */ |
---|
129 | 146 | regmap_update_bits(fifo->map, FIFO_CTRL0, |
---|
.. | .. |
---|
132 | 149 | |
---|
133 | 150 | return 0; |
---|
134 | 151 | } |
---|
| 152 | +EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_params); |
---|
135 | 153 | |
---|
136 | | -static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss) |
---|
| 154 | +int g12a_fifo_pcm_hw_params(struct snd_soc_component *component, |
---|
| 155 | + struct snd_pcm_substream *ss, |
---|
| 156 | + struct snd_pcm_hw_params *params) |
---|
| 157 | +{ |
---|
| 158 | + struct axg_fifo *fifo = axg_fifo_data(ss); |
---|
| 159 | + struct snd_pcm_runtime *runtime = ss->runtime; |
---|
| 160 | + int ret; |
---|
| 161 | + |
---|
| 162 | + ret = axg_fifo_pcm_hw_params(component, ss, params); |
---|
| 163 | + if (ret) |
---|
| 164 | + return ret; |
---|
| 165 | + |
---|
| 166 | + /* Set the initial memory address of the DMA */ |
---|
| 167 | + regmap_write(fifo->map, FIFO_INIT_ADDR, runtime->dma_addr); |
---|
| 168 | + |
---|
| 169 | + return 0; |
---|
| 170 | +} |
---|
| 171 | +EXPORT_SYMBOL_GPL(g12a_fifo_pcm_hw_params); |
---|
| 172 | + |
---|
| 173 | +int axg_fifo_pcm_hw_free(struct snd_soc_component *component, |
---|
| 174 | + struct snd_pcm_substream *ss) |
---|
137 | 175 | { |
---|
138 | 176 | struct axg_fifo *fifo = axg_fifo_data(ss); |
---|
139 | 177 | |
---|
.. | .. |
---|
141 | 179 | regmap_update_bits(fifo->map, FIFO_CTRL0, |
---|
142 | 180 | CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0); |
---|
143 | 181 | |
---|
144 | | - return snd_pcm_lib_free_pages(ss); |
---|
| 182 | + return 0; |
---|
145 | 183 | } |
---|
| 184 | +EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free); |
---|
146 | 185 | |
---|
147 | 186 | static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask) |
---|
148 | 187 | { |
---|
.. | .. |
---|
177 | 216 | return IRQ_RETVAL(status); |
---|
178 | 217 | } |
---|
179 | 218 | |
---|
180 | | -static int axg_fifo_pcm_open(struct snd_pcm_substream *ss) |
---|
| 219 | +int axg_fifo_pcm_open(struct snd_soc_component *component, |
---|
| 220 | + struct snd_pcm_substream *ss) |
---|
181 | 221 | { |
---|
182 | 222 | struct axg_fifo *fifo = axg_fifo_data(ss); |
---|
183 | 223 | struct device *dev = axg_fifo_dev(ss); |
---|
.. | .. |
---|
187 | 227 | |
---|
188 | 228 | /* |
---|
189 | 229 | * Make sure the buffer and period size are multiple of the FIFO |
---|
190 | | - * minimum depth size |
---|
| 230 | + * burst |
---|
191 | 231 | */ |
---|
192 | 232 | ret = snd_pcm_hw_constraint_step(ss->runtime, 0, |
---|
193 | 233 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, |
---|
194 | | - AXG_FIFO_MIN_DEPTH); |
---|
| 234 | + AXG_FIFO_BURST); |
---|
195 | 235 | if (ret) |
---|
196 | 236 | return ret; |
---|
197 | 237 | |
---|
198 | 238 | ret = snd_pcm_hw_constraint_step(ss->runtime, 0, |
---|
199 | 239 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, |
---|
200 | | - AXG_FIFO_MIN_DEPTH); |
---|
| 240 | + AXG_FIFO_BURST); |
---|
201 | 241 | if (ret) |
---|
202 | 242 | return ret; |
---|
203 | 243 | |
---|
.. | .. |
---|
239 | 279 | free_irq(fifo->irq, ss); |
---|
240 | 280 | return ret; |
---|
241 | 281 | } |
---|
| 282 | +EXPORT_SYMBOL_GPL(axg_fifo_pcm_open); |
---|
242 | 283 | |
---|
243 | | -static int axg_fifo_pcm_close(struct snd_pcm_substream *ss) |
---|
| 284 | +int axg_fifo_pcm_close(struct snd_soc_component *component, |
---|
| 285 | + struct snd_pcm_substream *ss) |
---|
244 | 286 | { |
---|
245 | 287 | struct axg_fifo *fifo = axg_fifo_data(ss); |
---|
246 | 288 | int ret; |
---|
.. | .. |
---|
256 | 298 | |
---|
257 | 299 | return ret; |
---|
258 | 300 | } |
---|
259 | | - |
---|
260 | | -const struct snd_pcm_ops axg_fifo_pcm_ops = { |
---|
261 | | - .open = axg_fifo_pcm_open, |
---|
262 | | - .close = axg_fifo_pcm_close, |
---|
263 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
264 | | - .hw_params = axg_fifo_pcm_hw_params, |
---|
265 | | - .hw_free = axg_fifo_pcm_hw_free, |
---|
266 | | - .pointer = axg_fifo_pcm_pointer, |
---|
267 | | - .trigger = axg_fifo_pcm_trigger, |
---|
268 | | -}; |
---|
269 | | -EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops); |
---|
| 301 | +EXPORT_SYMBOL_GPL(axg_fifo_pcm_close); |
---|
270 | 302 | |
---|
271 | 303 | int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type) |
---|
272 | 304 | { |
---|
273 | 305 | struct snd_card *card = rtd->card->snd_card; |
---|
274 | 306 | size_t size = axg_fifo_hw.buffer_bytes_max; |
---|
275 | 307 | |
---|
276 | | - return snd_pcm_lib_preallocate_pages(rtd->pcm->streams[type].substream, |
---|
277 | | - SNDRV_DMA_TYPE_DEV, card->dev, |
---|
278 | | - size, size); |
---|
| 308 | + snd_pcm_set_managed_buffer(rtd->pcm->streams[type].substream, |
---|
| 309 | + SNDRV_DMA_TYPE_DEV, card->dev, |
---|
| 310 | + size, size); |
---|
| 311 | + return 0; |
---|
279 | 312 | } |
---|
280 | 313 | EXPORT_SYMBOL_GPL(axg_fifo_pcm_new); |
---|
281 | 314 | |
---|
.. | .. |
---|
283 | 316 | .reg_bits = 32, |
---|
284 | 317 | .val_bits = 32, |
---|
285 | 318 | .reg_stride = 4, |
---|
286 | | - .max_register = FIFO_STATUS2, |
---|
| 319 | + .max_register = FIFO_CTRL2, |
---|
287 | 320 | }; |
---|
288 | 321 | |
---|
289 | 322 | int axg_fifo_probe(struct platform_device *pdev) |
---|
.. | .. |
---|
291 | 324 | struct device *dev = &pdev->dev; |
---|
292 | 325 | const struct axg_fifo_match_data *data; |
---|
293 | 326 | struct axg_fifo *fifo; |
---|
294 | | - struct resource *res; |
---|
295 | 327 | void __iomem *regs; |
---|
| 328 | + int ret; |
---|
296 | 329 | |
---|
297 | 330 | data = of_device_get_match_data(dev); |
---|
298 | 331 | if (!data) { |
---|
.. | .. |
---|
305 | 338 | return -ENOMEM; |
---|
306 | 339 | platform_set_drvdata(pdev, fifo); |
---|
307 | 340 | |
---|
308 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
309 | | - regs = devm_ioremap_resource(dev, res); |
---|
| 341 | + regs = devm_platform_ioremap_resource(pdev, 0); |
---|
310 | 342 | if (IS_ERR(regs)) |
---|
311 | 343 | return PTR_ERR(regs); |
---|
312 | 344 | |
---|
.. | .. |
---|
339 | 371 | return fifo->irq; |
---|
340 | 372 | } |
---|
341 | 373 | |
---|
| 374 | + fifo->field_threshold = |
---|
| 375 | + devm_regmap_field_alloc(dev, fifo->map, data->field_threshold); |
---|
| 376 | + if (IS_ERR(fifo->field_threshold)) |
---|
| 377 | + return PTR_ERR(fifo->field_threshold); |
---|
| 378 | + |
---|
| 379 | + ret = of_property_read_u32(dev->of_node, "amlogic,fifo-depth", |
---|
| 380 | + &fifo->depth); |
---|
| 381 | + if (ret) { |
---|
| 382 | + /* Error out for anything but a missing property */ |
---|
| 383 | + if (ret != -EINVAL) |
---|
| 384 | + return ret; |
---|
| 385 | + /* |
---|
| 386 | + * If the property is missing, it might be because of an old |
---|
| 387 | + * DT. In such case, assume the smallest known fifo depth |
---|
| 388 | + */ |
---|
| 389 | + fifo->depth = 256; |
---|
| 390 | + dev_warn(dev, "fifo depth not found, assume %u bytes\n", |
---|
| 391 | + fifo->depth); |
---|
| 392 | + } |
---|
| 393 | + |
---|
342 | 394 | return devm_snd_soc_register_component(dev, data->component_drv, |
---|
343 | 395 | data->dai_drv, 1); |
---|
344 | 396 | } |
---|
345 | 397 | EXPORT_SYMBOL_GPL(axg_fifo_probe); |
---|
346 | 398 | |
---|
347 | | -MODULE_DESCRIPTION("Amlogic AXG fifo driver"); |
---|
| 399 | +MODULE_DESCRIPTION("Amlogic AXG/G12A fifo driver"); |
---|
348 | 400 | MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); |
---|
349 | 401 | MODULE_LICENSE("GPL v2"); |
---|