diff options
Diffstat (limited to 'sound/soc/sh/fsi.c')
-rw-r--r-- | sound/soc/sh/fsi.c | 912 |
1 files changed, 608 insertions, 304 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index ea4a82d01160..378cc5b056d7 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -13,8 +13,11 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/dma-mapping.h> | ||
16 | #include <linux/pm_runtime.h> | 17 | #include <linux/pm_runtime.h> |
17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/scatterlist.h> | ||
20 | #include <linux/sh_dma.h> | ||
18 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
19 | #include <linux/module.h> | 22 | #include <linux/module.h> |
20 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
@@ -53,6 +56,7 @@ | |||
53 | 56 | ||
54 | /* DO_FMT */ | 57 | /* DO_FMT */ |
55 | /* DI_FMT */ | 58 | /* DI_FMT */ |
59 | #define CR_BWS_MASK (0x3 << 20) /* FSI2 */ | ||
56 | #define CR_BWS_24 (0x0 << 20) /* FSI2 */ | 60 | #define CR_BWS_24 (0x0 << 20) /* FSI2 */ |
57 | #define CR_BWS_16 (0x1 << 20) /* FSI2 */ | 61 | #define CR_BWS_16 (0x1 << 20) /* FSI2 */ |
58 | #define CR_BWS_20 (0x2 << 20) /* FSI2 */ | 62 | #define CR_BWS_20 (0x2 << 20) /* FSI2 */ |
@@ -68,6 +72,15 @@ | |||
68 | #define CR_TDM (0x4 << 4) | 72 | #define CR_TDM (0x4 << 4) |
69 | #define CR_TDM_D (0x5 << 4) | 73 | #define CR_TDM_D (0x5 << 4) |
70 | 74 | ||
75 | /* OUT_DMAC */ | ||
76 | /* IN_DMAC */ | ||
77 | #define VDMD_MASK (0x3 << 4) | ||
78 | #define VDMD_FRONT (0x0 << 4) /* Package in front */ | ||
79 | #define VDMD_BACK (0x1 << 4) /* Package in back */ | ||
80 | #define VDMD_STREAM (0x2 << 4) /* Stream mode(16bit * 2) */ | ||
81 | |||
82 | #define DMA_ON (0x1 << 0) | ||
83 | |||
71 | /* DOFF_CTL */ | 84 | /* DOFF_CTL */ |
72 | /* DIFF_CTL */ | 85 | /* DIFF_CTL */ |
73 | #define IRQ_HALF 0x00100000 | 86 | #define IRQ_HALF 0x00100000 |
@@ -116,7 +129,7 @@ | |||
116 | 129 | ||
117 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | 130 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) |
118 | 131 | ||
119 | typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int enable); | 132 | typedef int (*set_rate_func)(struct device *dev, int rate, int enable); |
120 | 133 | ||
121 | /* | 134 | /* |
122 | * FSI driver use below type name for variable | 135 | * FSI driver use below type name for variable |
@@ -159,22 +172,41 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena | |||
159 | * struct | 172 | * struct |
160 | */ | 173 | */ |
161 | 174 | ||
175 | struct fsi_stream_handler; | ||
162 | struct fsi_stream { | 176 | struct fsi_stream { |
163 | struct snd_pcm_substream *substream; | ||
164 | 177 | ||
178 | /* | ||
179 | * these are initialized by fsi_stream_init() | ||
180 | */ | ||
181 | struct snd_pcm_substream *substream; | ||
165 | int fifo_sample_capa; /* sample capacity of FSI FIFO */ | 182 | int fifo_sample_capa; /* sample capacity of FSI FIFO */ |
166 | int buff_sample_capa; /* sample capacity of ALSA buffer */ | 183 | int buff_sample_capa; /* sample capacity of ALSA buffer */ |
167 | int buff_sample_pos; /* sample position of ALSA buffer */ | 184 | int buff_sample_pos; /* sample position of ALSA buffer */ |
168 | int period_samples; /* sample number / 1 period */ | 185 | int period_samples; /* sample number / 1 period */ |
169 | int period_pos; /* current period position */ | 186 | int period_pos; /* current period position */ |
170 | 187 | int sample_width; /* sample width */ | |
171 | int uerr_num; | 188 | int uerr_num; |
172 | int oerr_num; | 189 | int oerr_num; |
190 | |||
191 | /* | ||
192 | * thse are initialized by fsi_handler_init() | ||
193 | */ | ||
194 | struct fsi_stream_handler *handler; | ||
195 | struct fsi_priv *priv; | ||
196 | |||
197 | /* | ||
198 | * these are for DMAEngine | ||
199 | */ | ||
200 | struct dma_chan *chan; | ||
201 | struct sh_dmae_slave slave; /* see fsi_handler_init() */ | ||
202 | struct tasklet_struct tasklet; | ||
203 | dma_addr_t dma; | ||
173 | }; | 204 | }; |
174 | 205 | ||
175 | struct fsi_priv { | 206 | struct fsi_priv { |
176 | void __iomem *base; | 207 | void __iomem *base; |
177 | struct fsi_master *master; | 208 | struct fsi_master *master; |
209 | struct sh_fsi_port_info *info; | ||
178 | 210 | ||
179 | struct fsi_stream playback; | 211 | struct fsi_stream playback; |
180 | struct fsi_stream capture; | 212 | struct fsi_stream capture; |
@@ -189,6 +221,20 @@ struct fsi_priv { | |||
189 | long rate; | 221 | long rate; |
190 | }; | 222 | }; |
191 | 223 | ||
224 | struct fsi_stream_handler { | ||
225 | int (*init)(struct fsi_priv *fsi, struct fsi_stream *io); | ||
226 | int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io); | ||
227 | int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io); | ||
228 | int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); | ||
229 | int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); | ||
230 | void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io, | ||
231 | int enable); | ||
232 | }; | ||
233 | #define fsi_stream_handler_call(io, func, args...) \ | ||
234 | (!(io) ? -ENODEV : \ | ||
235 | !((io)->handler->func) ? 0 : \ | ||
236 | (io)->handler->func(args)) | ||
237 | |||
192 | struct fsi_core { | 238 | struct fsi_core { |
193 | int ver; | 239 | int ver; |
194 | 240 | ||
@@ -205,10 +251,11 @@ struct fsi_master { | |||
205 | struct fsi_priv fsia; | 251 | struct fsi_priv fsia; |
206 | struct fsi_priv fsib; | 252 | struct fsi_priv fsib; |
207 | struct fsi_core *core; | 253 | struct fsi_core *core; |
208 | struct sh_fsi_platform_info *info; | ||
209 | spinlock_t lock; | 254 | spinlock_t lock; |
210 | }; | 255 | }; |
211 | 256 | ||
257 | static int fsi_stream_is_play(struct fsi_priv *fsi, struct fsi_stream *io); | ||
258 | |||
212 | /* | 259 | /* |
213 | * basic read write function | 260 | * basic read write function |
214 | */ | 261 | */ |
@@ -295,6 +342,11 @@ static int fsi_is_spdif(struct fsi_priv *fsi) | |||
295 | return fsi->spdif; | 342 | return fsi->spdif; |
296 | } | 343 | } |
297 | 344 | ||
345 | static int fsi_is_play(struct snd_pcm_substream *substream) | ||
346 | { | ||
347 | return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
348 | } | ||
349 | |||
298 | static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) | 350 | static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) |
299 | { | 351 | { |
300 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 352 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
@@ -317,44 +369,25 @@ static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) | |||
317 | return fsi_get_priv_frm_dai(fsi_get_dai(substream)); | 369 | return fsi_get_priv_frm_dai(fsi_get_dai(substream)); |
318 | } | 370 | } |
319 | 371 | ||
320 | static set_rate_func fsi_get_info_set_rate(struct fsi_master *master) | 372 | static set_rate_func fsi_get_info_set_rate(struct fsi_priv *fsi) |
321 | { | 373 | { |
322 | if (!master->info) | 374 | if (!fsi->info) |
323 | return NULL; | 375 | return NULL; |
324 | 376 | ||
325 | return master->info->set_rate; | 377 | return fsi->info->set_rate; |
326 | } | 378 | } |
327 | 379 | ||
328 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) | 380 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) |
329 | { | 381 | { |
330 | int is_porta = fsi_is_port_a(fsi); | 382 | if (!fsi->info) |
331 | struct fsi_master *master = fsi_get_master(fsi); | ||
332 | |||
333 | if (!master->info) | ||
334 | return 0; | 383 | return 0; |
335 | 384 | ||
336 | return is_porta ? master->info->porta_flags : | 385 | return fsi->info->flags; |
337 | master->info->portb_flags; | ||
338 | } | ||
339 | |||
340 | static inline int fsi_stream_is_play(int stream) | ||
341 | { | ||
342 | return stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
343 | } | ||
344 | |||
345 | static inline int fsi_is_play(struct snd_pcm_substream *substream) | ||
346 | { | ||
347 | return fsi_stream_is_play(substream->stream); | ||
348 | } | 386 | } |
349 | 387 | ||
350 | static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi, | 388 | static u32 fsi_get_port_shift(struct fsi_priv *fsi, struct fsi_stream *io) |
351 | int is_play) | ||
352 | { | ||
353 | return is_play ? &fsi->playback : &fsi->capture; | ||
354 | } | ||
355 | |||
356 | static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) | ||
357 | { | 389 | { |
390 | int is_play = fsi_stream_is_play(fsi, io); | ||
358 | int is_porta = fsi_is_port_a(fsi); | 391 | int is_porta = fsi_is_port_a(fsi); |
359 | u32 shift; | 392 | u32 shift; |
360 | 393 | ||
@@ -376,26 +409,81 @@ static int fsi_sample2frame(struct fsi_priv *fsi, int samples) | |||
376 | return samples / fsi->chan_num; | 409 | return samples / fsi->chan_num; |
377 | } | 410 | } |
378 | 411 | ||
412 | static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, | ||
413 | struct fsi_stream *io) | ||
414 | { | ||
415 | int is_play = fsi_stream_is_play(fsi, io); | ||
416 | u32 status; | ||
417 | int frames; | ||
418 | |||
419 | status = is_play ? | ||
420 | fsi_reg_read(fsi, DOFF_ST) : | ||
421 | fsi_reg_read(fsi, DIFF_ST); | ||
422 | |||
423 | frames = 0x1ff & (status >> 8); | ||
424 | |||
425 | return fsi_frame2sample(fsi, frames); | ||
426 | } | ||
427 | |||
428 | static void fsi_count_fifo_err(struct fsi_priv *fsi) | ||
429 | { | ||
430 | u32 ostatus = fsi_reg_read(fsi, DOFF_ST); | ||
431 | u32 istatus = fsi_reg_read(fsi, DIFF_ST); | ||
432 | |||
433 | if (ostatus & ERR_OVER) | ||
434 | fsi->playback.oerr_num++; | ||
435 | |||
436 | if (ostatus & ERR_UNDER) | ||
437 | fsi->playback.uerr_num++; | ||
438 | |||
439 | if (istatus & ERR_OVER) | ||
440 | fsi->capture.oerr_num++; | ||
441 | |||
442 | if (istatus & ERR_UNDER) | ||
443 | fsi->capture.uerr_num++; | ||
444 | |||
445 | fsi_reg_write(fsi, DOFF_ST, 0); | ||
446 | fsi_reg_write(fsi, DIFF_ST, 0); | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * fsi_stream_xx() function | ||
451 | */ | ||
452 | static inline int fsi_stream_is_play(struct fsi_priv *fsi, | ||
453 | struct fsi_stream *io) | ||
454 | { | ||
455 | return &fsi->playback == io; | ||
456 | } | ||
457 | |||
458 | static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi, | ||
459 | struct snd_pcm_substream *substream) | ||
460 | { | ||
461 | return fsi_is_play(substream) ? &fsi->playback : &fsi->capture; | ||
462 | } | ||
463 | |||
379 | static int fsi_stream_is_working(struct fsi_priv *fsi, | 464 | static int fsi_stream_is_working(struct fsi_priv *fsi, |
380 | int is_play) | 465 | struct fsi_stream *io) |
381 | { | 466 | { |
382 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
383 | struct fsi_master *master = fsi_get_master(fsi); | 467 | struct fsi_master *master = fsi_get_master(fsi); |
384 | unsigned long flags; | 468 | unsigned long flags; |
385 | int ret; | 469 | int ret; |
386 | 470 | ||
387 | spin_lock_irqsave(&master->lock, flags); | 471 | spin_lock_irqsave(&master->lock, flags); |
388 | ret = !!io->substream; | 472 | ret = !!(io->substream && io->substream->runtime); |
389 | spin_unlock_irqrestore(&master->lock, flags); | 473 | spin_unlock_irqrestore(&master->lock, flags); |
390 | 474 | ||
391 | return ret; | 475 | return ret; |
392 | } | 476 | } |
393 | 477 | ||
394 | static void fsi_stream_push(struct fsi_priv *fsi, | 478 | static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io) |
395 | int is_play, | 479 | { |
480 | return io->priv; | ||
481 | } | ||
482 | |||
483 | static void fsi_stream_init(struct fsi_priv *fsi, | ||
484 | struct fsi_stream *io, | ||
396 | struct snd_pcm_substream *substream) | 485 | struct snd_pcm_substream *substream) |
397 | { | 486 | { |
398 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
399 | struct snd_pcm_runtime *runtime = substream->runtime; | 487 | struct snd_pcm_runtime *runtime = substream->runtime; |
400 | struct fsi_master *master = fsi_get_master(fsi); | 488 | struct fsi_master *master = fsi_get_master(fsi); |
401 | unsigned long flags; | 489 | unsigned long flags; |
@@ -406,14 +494,15 @@ static void fsi_stream_push(struct fsi_priv *fsi, | |||
406 | io->buff_sample_pos = 0; | 494 | io->buff_sample_pos = 0; |
407 | io->period_samples = fsi_frame2sample(fsi, runtime->period_size); | 495 | io->period_samples = fsi_frame2sample(fsi, runtime->period_size); |
408 | io->period_pos = 0; | 496 | io->period_pos = 0; |
497 | io->sample_width = samples_to_bytes(runtime, 1); | ||
409 | io->oerr_num = -1; /* ignore 1st err */ | 498 | io->oerr_num = -1; /* ignore 1st err */ |
410 | io->uerr_num = -1; /* ignore 1st err */ | 499 | io->uerr_num = -1; /* ignore 1st err */ |
500 | fsi_stream_handler_call(io, init, fsi, io); | ||
411 | spin_unlock_irqrestore(&master->lock, flags); | 501 | spin_unlock_irqrestore(&master->lock, flags); |
412 | } | 502 | } |
413 | 503 | ||
414 | static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) | 504 | static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io) |
415 | { | 505 | { |
416 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
417 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); | 506 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); |
418 | struct fsi_master *master = fsi_get_master(fsi); | 507 | struct fsi_master *master = fsi_get_master(fsi); |
419 | unsigned long flags; | 508 | unsigned long flags; |
@@ -426,127 +515,87 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) | |||
426 | if (io->uerr_num > 0) | 515 | if (io->uerr_num > 0) |
427 | dev_err(dai->dev, "under_run = %d\n", io->uerr_num); | 516 | dev_err(dai->dev, "under_run = %d\n", io->uerr_num); |
428 | 517 | ||
518 | fsi_stream_handler_call(io, quit, fsi, io); | ||
429 | io->substream = NULL; | 519 | io->substream = NULL; |
430 | io->buff_sample_capa = 0; | 520 | io->buff_sample_capa = 0; |
431 | io->buff_sample_pos = 0; | 521 | io->buff_sample_pos = 0; |
432 | io->period_samples = 0; | 522 | io->period_samples = 0; |
433 | io->period_pos = 0; | 523 | io->period_pos = 0; |
524 | io->sample_width = 0; | ||
434 | io->oerr_num = 0; | 525 | io->oerr_num = 0; |
435 | io->uerr_num = 0; | 526 | io->uerr_num = 0; |
436 | spin_unlock_irqrestore(&master->lock, flags); | 527 | spin_unlock_irqrestore(&master->lock, flags); |
437 | } | 528 | } |
438 | 529 | ||
439 | static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play) | 530 | static int fsi_stream_transfer(struct fsi_stream *io) |
440 | { | 531 | { |
441 | u32 status; | 532 | struct fsi_priv *fsi = fsi_stream_to_priv(io); |
442 | int frames; | 533 | if (!fsi) |
443 | 534 | return -EIO; | |
444 | status = is_play ? | ||
445 | fsi_reg_read(fsi, DOFF_ST) : | ||
446 | fsi_reg_read(fsi, DIFF_ST); | ||
447 | |||
448 | frames = 0x1ff & (status >> 8); | ||
449 | |||
450 | return fsi_frame2sample(fsi, frames); | ||
451 | } | ||
452 | |||
453 | static void fsi_count_fifo_err(struct fsi_priv *fsi) | ||
454 | { | ||
455 | u32 ostatus = fsi_reg_read(fsi, DOFF_ST); | ||
456 | u32 istatus = fsi_reg_read(fsi, DIFF_ST); | ||
457 | |||
458 | if (ostatus & ERR_OVER) | ||
459 | fsi->playback.oerr_num++; | ||
460 | |||
461 | if (ostatus & ERR_UNDER) | ||
462 | fsi->playback.uerr_num++; | ||
463 | |||
464 | if (istatus & ERR_OVER) | ||
465 | fsi->capture.oerr_num++; | ||
466 | |||
467 | if (istatus & ERR_UNDER) | ||
468 | fsi->capture.uerr_num++; | ||
469 | 535 | ||
470 | fsi_reg_write(fsi, DOFF_ST, 0); | 536 | return fsi_stream_handler_call(io, transfer, fsi, io); |
471 | fsi_reg_write(fsi, DIFF_ST, 0); | ||
472 | } | 537 | } |
473 | 538 | ||
474 | /* | 539 | #define fsi_stream_start(fsi, io)\ |
475 | * dma function | 540 | fsi_stream_handler_call(io, start_stop, fsi, io, 1) |
476 | */ | ||
477 | 541 | ||
478 | static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream) | 542 | #define fsi_stream_stop(fsi, io)\ |
479 | { | 543 | fsi_stream_handler_call(io, start_stop, fsi, io, 0) |
480 | int is_play = fsi_stream_is_play(stream); | ||
481 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
482 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
483 | 544 | ||
484 | return runtime->dma_area + | 545 | static int fsi_stream_probe(struct fsi_priv *fsi) |
485 | samples_to_bytes(runtime, io->buff_sample_pos); | ||
486 | } | ||
487 | |||
488 | static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num) | ||
489 | { | 546 | { |
490 | u16 *start; | 547 | struct fsi_stream *io; |
491 | int i; | 548 | int ret1, ret2; |
492 | |||
493 | start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK); | ||
494 | 549 | ||
495 | for (i = 0; i < num; i++) | 550 | io = &fsi->playback; |
496 | fsi_reg_write(fsi, DODT, ((u32)*(start + i) << 8)); | 551 | ret1 = fsi_stream_handler_call(io, probe, fsi, io); |
497 | } | ||
498 | |||
499 | static void fsi_dma_soft_pop16(struct fsi_priv *fsi, int num) | ||
500 | { | ||
501 | u16 *start; | ||
502 | int i; | ||
503 | 552 | ||
504 | start = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE); | 553 | io = &fsi->capture; |
554 | ret2 = fsi_stream_handler_call(io, probe, fsi, io); | ||
505 | 555 | ||
556 | if (ret1 < 0) | ||
557 | return ret1; | ||
558 | if (ret2 < 0) | ||
559 | return ret2; | ||
506 | 560 | ||
507 | for (i = 0; i < num; i++) | 561 | return 0; |
508 | *(start + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8); | ||
509 | } | 562 | } |
510 | 563 | ||
511 | static void fsi_dma_soft_push32(struct fsi_priv *fsi, int num) | 564 | static int fsi_stream_remove(struct fsi_priv *fsi) |
512 | { | 565 | { |
513 | u32 *start; | 566 | struct fsi_stream *io; |
514 | int i; | 567 | int ret1, ret2; |
515 | 568 | ||
516 | start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK); | 569 | io = &fsi->playback; |
517 | 570 | ret1 = fsi_stream_handler_call(io, remove, fsi, io); | |
518 | |||
519 | for (i = 0; i < num; i++) | ||
520 | fsi_reg_write(fsi, DODT, *(start + i)); | ||
521 | } | ||
522 | 571 | ||
523 | static void fsi_dma_soft_pop32(struct fsi_priv *fsi, int num) | 572 | io = &fsi->capture; |
524 | { | 573 | ret2 = fsi_stream_handler_call(io, remove, fsi, io); |
525 | u32 *start; | ||
526 | int i; | ||
527 | 574 | ||
528 | start = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE); | 575 | if (ret1 < 0) |
576 | return ret1; | ||
577 | if (ret2 < 0) | ||
578 | return ret2; | ||
529 | 579 | ||
530 | for (i = 0; i < num; i++) | 580 | return 0; |
531 | *(start + i) = fsi_reg_read(fsi, DIDT); | ||
532 | } | 581 | } |
533 | 582 | ||
534 | /* | 583 | /* |
535 | * irq function | 584 | * irq function |
536 | */ | 585 | */ |
537 | 586 | ||
538 | static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) | 587 | static void fsi_irq_enable(struct fsi_priv *fsi, struct fsi_stream *io) |
539 | { | 588 | { |
540 | u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play)); | 589 | u32 data = AB_IO(1, fsi_get_port_shift(fsi, io)); |
541 | struct fsi_master *master = fsi_get_master(fsi); | 590 | struct fsi_master *master = fsi_get_master(fsi); |
542 | 591 | ||
543 | fsi_core_mask_set(master, imsk, data, data); | 592 | fsi_core_mask_set(master, imsk, data, data); |
544 | fsi_core_mask_set(master, iemsk, data, data); | 593 | fsi_core_mask_set(master, iemsk, data, data); |
545 | } | 594 | } |
546 | 595 | ||
547 | static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) | 596 | static void fsi_irq_disable(struct fsi_priv *fsi, struct fsi_stream *io) |
548 | { | 597 | { |
549 | u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play)); | 598 | u32 data = AB_IO(1, fsi_get_port_shift(fsi, io)); |
550 | struct fsi_master *master = fsi_get_master(fsi); | 599 | struct fsi_master *master = fsi_get_master(fsi); |
551 | 600 | ||
552 | fsi_core_mask_set(master, imsk, data, 0); | 601 | fsi_core_mask_set(master, imsk, data, 0); |
@@ -563,8 +612,8 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi) | |||
563 | u32 data = 0; | 612 | u32 data = 0; |
564 | struct fsi_master *master = fsi_get_master(fsi); | 613 | struct fsi_master *master = fsi_get_master(fsi); |
565 | 614 | ||
566 | data |= AB_IO(1, fsi_get_port_shift(fsi, 0)); | 615 | data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->playback)); |
567 | data |= AB_IO(1, fsi_get_port_shift(fsi, 1)); | 616 | data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->capture)); |
568 | 617 | ||
569 | /* clear interrupt factor */ | 618 | /* clear interrupt factor */ |
570 | fsi_core_mask_set(master, int_st, data, 0); | 619 | fsi_core_mask_set(master, int_st, data, 0); |
@@ -600,11 +649,14 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, | |||
600 | long rate, int enable) | 649 | long rate, int enable) |
601 | { | 650 | { |
602 | struct fsi_master *master = fsi_get_master(fsi); | 651 | struct fsi_master *master = fsi_get_master(fsi); |
603 | set_rate_func set_rate = fsi_get_info_set_rate(master); | 652 | set_rate_func set_rate = fsi_get_info_set_rate(fsi); |
604 | int fsi_ver = master->core->ver; | 653 | int fsi_ver = master->core->ver; |
605 | int ret; | 654 | int ret; |
606 | 655 | ||
607 | ret = set_rate(dev, fsi_is_port_a(fsi), rate, enable); | 656 | if (!set_rate) |
657 | return 0; | ||
658 | |||
659 | ret = set_rate(dev, rate, enable); | ||
608 | if (ret < 0) /* error */ | 660 | if (ret < 0) /* error */ |
609 | return ret; | 661 | return ret; |
610 | 662 | ||
@@ -671,96 +723,64 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, | |||
671 | return ret; | 723 | return ret; |
672 | } | 724 | } |
673 | 725 | ||
674 | #define fsi_port_start(f, i) __fsi_port_clk_ctrl(f, i, 1) | 726 | /* |
675 | #define fsi_port_stop(f, i) __fsi_port_clk_ctrl(f, i, 0) | 727 | * pio data transfer handler |
676 | static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int is_play, int enable) | 728 | */ |
729 | static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) | ||
677 | { | 730 | { |
678 | struct fsi_master *master = fsi_get_master(fsi); | 731 | u16 *buf = (u16 *)_buf; |
679 | u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; | 732 | int i; |
680 | 733 | ||
681 | if (enable) | 734 | for (i = 0; i < samples; i++) |
682 | fsi_irq_enable(fsi, is_play); | 735 | fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); |
683 | else | 736 | } |
684 | fsi_irq_disable(fsi, is_play); | ||
685 | 737 | ||
686 | if (fsi_is_clk_master(fsi)) | 738 | static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples) |
687 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); | 739 | { |
740 | u16 *buf = (u16 *)_buf; | ||
741 | int i; | ||
742 | |||
743 | for (i = 0; i < samples; i++) | ||
744 | *(buf + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8); | ||
688 | } | 745 | } |
689 | 746 | ||
690 | /* | 747 | static void fsi_pio_push32(struct fsi_priv *fsi, u8 *_buf, int samples) |
691 | * ctrl function | ||
692 | */ | ||
693 | static void fsi_fifo_init(struct fsi_priv *fsi, | ||
694 | int is_play, | ||
695 | struct device *dev) | ||
696 | { | 748 | { |
697 | struct fsi_master *master = fsi_get_master(fsi); | 749 | u32 *buf = (u32 *)_buf; |
698 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 750 | int i; |
699 | u32 shift, i; | ||
700 | int frame_capa; | ||
701 | 751 | ||
702 | /* get on-chip RAM capacity */ | 752 | for (i = 0; i < samples; i++) |
703 | shift = fsi_master_read(master, FIFO_SZ); | 753 | fsi_reg_write(fsi, DODT, *(buf + i)); |
704 | shift >>= fsi_get_port_shift(fsi, is_play); | 754 | } |
705 | shift &= FIFO_SZ_MASK; | ||
706 | frame_capa = 256 << shift; | ||
707 | dev_dbg(dev, "fifo = %d words\n", frame_capa); | ||
708 | 755 | ||
709 | /* | 756 | static void fsi_pio_pop32(struct fsi_priv *fsi, u8 *_buf, int samples) |
710 | * The maximum number of sample data varies depending | 757 | { |
711 | * on the number of channels selected for the format. | 758 | u32 *buf = (u32 *)_buf; |
712 | * | 759 | int i; |
713 | * FIFOs are used in 4-channel units in 3-channel mode | ||
714 | * and in 8-channel units in 5- to 7-channel mode | ||
715 | * meaning that more FIFOs than the required size of DPRAM | ||
716 | * are used. | ||
717 | * | ||
718 | * ex) if 256 words of DP-RAM is connected | ||
719 | * 1 channel: 256 (256 x 1 = 256) | ||
720 | * 2 channels: 128 (128 x 2 = 256) | ||
721 | * 3 channels: 64 ( 64 x 3 = 192) | ||
722 | * 4 channels: 64 ( 64 x 4 = 256) | ||
723 | * 5 channels: 32 ( 32 x 5 = 160) | ||
724 | * 6 channels: 32 ( 32 x 6 = 192) | ||
725 | * 7 channels: 32 ( 32 x 7 = 224) | ||
726 | * 8 channels: 32 ( 32 x 8 = 256) | ||
727 | */ | ||
728 | for (i = 1; i < fsi->chan_num; i <<= 1) | ||
729 | frame_capa >>= 1; | ||
730 | dev_dbg(dev, "%d channel %d store\n", | ||
731 | fsi->chan_num, frame_capa); | ||
732 | 760 | ||
733 | io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); | 761 | for (i = 0; i < samples; i++) |
762 | *(buf + i) = fsi_reg_read(fsi, DIDT); | ||
763 | } | ||
734 | 764 | ||
735 | /* | 765 | static u8 *fsi_pio_get_area(struct fsi_priv *fsi, struct fsi_stream *io) |
736 | * set interrupt generation factor | 766 | { |
737 | * clear FIFO | 767 | struct snd_pcm_runtime *runtime = io->substream->runtime; |
738 | */ | 768 | |
739 | if (is_play) { | 769 | return runtime->dma_area + |
740 | fsi_reg_write(fsi, DOFF_CTL, IRQ_HALF); | 770 | samples_to_bytes(runtime, io->buff_sample_pos); |
741 | fsi_reg_mask_set(fsi, DOFF_CTL, FIFO_CLR, FIFO_CLR); | ||
742 | } else { | ||
743 | fsi_reg_write(fsi, DIFF_CTL, IRQ_HALF); | ||
744 | fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); | ||
745 | } | ||
746 | } | 771 | } |
747 | 772 | ||
748 | static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | 773 | static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, |
774 | void (*run16)(struct fsi_priv *fsi, u8 *buf, int samples), | ||
775 | void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples), | ||
776 | int samples) | ||
749 | { | 777 | { |
750 | struct snd_pcm_runtime *runtime; | 778 | struct snd_pcm_runtime *runtime; |
751 | struct snd_pcm_substream *substream = NULL; | 779 | struct snd_pcm_substream *substream; |
752 | int is_play = fsi_stream_is_play(stream); | 780 | u8 *buf; |
753 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
754 | int sample_residues; | ||
755 | int sample_width; | ||
756 | int samples; | ||
757 | int samples_max; | ||
758 | int over_period; | 781 | int over_period; |
759 | void (*fn)(struct fsi_priv *fsi, int size); | ||
760 | 782 | ||
761 | if (!fsi || | 783 | if (!fsi_stream_is_working(fsi, io)) |
762 | !io->substream || | ||
763 | !io->substream->runtime) | ||
764 | return -EINVAL; | 784 | return -EINVAL; |
765 | 785 | ||
766 | over_period = 0; | 786 | over_period = 0; |
@@ -780,60 +800,19 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
780 | io->buff_sample_pos = 0; | 800 | io->buff_sample_pos = 0; |
781 | } | 801 | } |
782 | 802 | ||
783 | /* get 1 sample data width */ | 803 | buf = fsi_pio_get_area(fsi, io); |
784 | sample_width = samples_to_bytes(runtime, 1); | ||
785 | 804 | ||
786 | /* get number of residue samples */ | 805 | switch (io->sample_width) { |
787 | sample_residues = io->buff_sample_capa - io->buff_sample_pos; | 806 | case 2: |
788 | 807 | run16(fsi, buf, samples); | |
789 | if (is_play) { | 808 | break; |
790 | /* | 809 | case 4: |
791 | * for play-back | 810 | run32(fsi, buf, samples); |
792 | * | 811 | break; |
793 | * samples_max : number of FSI fifo free samples space | 812 | default: |
794 | * samples : number of ALSA residue samples | 813 | return -EINVAL; |
795 | */ | ||
796 | samples_max = io->fifo_sample_capa; | ||
797 | samples_max -= fsi_get_current_fifo_samples(fsi, is_play); | ||
798 | |||
799 | samples = sample_residues; | ||
800 | |||
801 | switch (sample_width) { | ||
802 | case 2: | ||
803 | fn = fsi_dma_soft_push16; | ||
804 | break; | ||
805 | case 4: | ||
806 | fn = fsi_dma_soft_push32; | ||
807 | break; | ||
808 | default: | ||
809 | return -EINVAL; | ||
810 | } | ||
811 | } else { | ||
812 | /* | ||
813 | * for capture | ||
814 | * | ||
815 | * samples_max : number of ALSA free samples space | ||
816 | * samples : number of samples in FSI fifo | ||
817 | */ | ||
818 | samples_max = sample_residues; | ||
819 | samples = fsi_get_current_fifo_samples(fsi, is_play); | ||
820 | |||
821 | switch (sample_width) { | ||
822 | case 2: | ||
823 | fn = fsi_dma_soft_pop16; | ||
824 | break; | ||
825 | case 4: | ||
826 | fn = fsi_dma_soft_pop32; | ||
827 | break; | ||
828 | default: | ||
829 | return -EINVAL; | ||
830 | } | ||
831 | } | 814 | } |
832 | 815 | ||
833 | samples = min(samples, samples_max); | ||
834 | |||
835 | fn(fsi, samples); | ||
836 | |||
837 | /* update buff_sample_pos */ | 816 | /* update buff_sample_pos */ |
838 | io->buff_sample_pos += samples; | 817 | io->buff_sample_pos += samples; |
839 | 818 | ||
@@ -843,16 +822,66 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
843 | return 0; | 822 | return 0; |
844 | } | 823 | } |
845 | 824 | ||
846 | static int fsi_data_pop(struct fsi_priv *fsi) | 825 | static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io) |
826 | { | ||
827 | int sample_residues; /* samples in FSI fifo */ | ||
828 | int sample_space; /* ALSA free samples space */ | ||
829 | int samples; | ||
830 | |||
831 | sample_residues = fsi_get_current_fifo_samples(fsi, io); | ||
832 | sample_space = io->buff_sample_capa - io->buff_sample_pos; | ||
833 | |||
834 | samples = min(sample_residues, sample_space); | ||
835 | |||
836 | return fsi_pio_transfer(fsi, io, | ||
837 | fsi_pio_pop16, | ||
838 | fsi_pio_pop32, | ||
839 | samples); | ||
840 | } | ||
841 | |||
842 | static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io) | ||
847 | { | 843 | { |
848 | return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_CAPTURE); | 844 | int sample_residues; /* ALSA residue samples */ |
845 | int sample_space; /* FSI fifo free samples space */ | ||
846 | int samples; | ||
847 | |||
848 | sample_residues = io->buff_sample_capa - io->buff_sample_pos; | ||
849 | sample_space = io->fifo_sample_capa - | ||
850 | fsi_get_current_fifo_samples(fsi, io); | ||
851 | |||
852 | samples = min(sample_residues, sample_space); | ||
853 | |||
854 | return fsi_pio_transfer(fsi, io, | ||
855 | fsi_pio_push16, | ||
856 | fsi_pio_push32, | ||
857 | samples); | ||
849 | } | 858 | } |
850 | 859 | ||
851 | static int fsi_data_push(struct fsi_priv *fsi) | 860 | static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, |
861 | int enable) | ||
852 | { | 862 | { |
853 | return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_PLAYBACK); | 863 | struct fsi_master *master = fsi_get_master(fsi); |
864 | u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; | ||
865 | |||
866 | if (enable) | ||
867 | fsi_irq_enable(fsi, io); | ||
868 | else | ||
869 | fsi_irq_disable(fsi, io); | ||
870 | |||
871 | if (fsi_is_clk_master(fsi)) | ||
872 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); | ||
854 | } | 873 | } |
855 | 874 | ||
875 | static struct fsi_stream_handler fsi_pio_push_handler = { | ||
876 | .transfer = fsi_pio_push, | ||
877 | .start_stop = fsi_pio_start_stop, | ||
878 | }; | ||
879 | |||
880 | static struct fsi_stream_handler fsi_pio_pop_handler = { | ||
881 | .transfer = fsi_pio_pop, | ||
882 | .start_stop = fsi_pio_start_stop, | ||
883 | }; | ||
884 | |||
856 | static irqreturn_t fsi_interrupt(int irq, void *data) | 885 | static irqreturn_t fsi_interrupt(int irq, void *data) |
857 | { | 886 | { |
858 | struct fsi_master *master = data; | 887 | struct fsi_master *master = data; |
@@ -863,13 +892,13 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
863 | fsi_master_mask_set(master, SOFT_RST, IR, IR); | 892 | fsi_master_mask_set(master, SOFT_RST, IR, IR); |
864 | 893 | ||
865 | if (int_st & AB_IO(1, AO_SHIFT)) | 894 | if (int_st & AB_IO(1, AO_SHIFT)) |
866 | fsi_data_push(&master->fsia); | 895 | fsi_stream_transfer(&master->fsia.playback); |
867 | if (int_st & AB_IO(1, BO_SHIFT)) | 896 | if (int_st & AB_IO(1, BO_SHIFT)) |
868 | fsi_data_push(&master->fsib); | 897 | fsi_stream_transfer(&master->fsib.playback); |
869 | if (int_st & AB_IO(1, AI_SHIFT)) | 898 | if (int_st & AB_IO(1, AI_SHIFT)) |
870 | fsi_data_pop(&master->fsia); | 899 | fsi_stream_transfer(&master->fsia.capture); |
871 | if (int_st & AB_IO(1, BI_SHIFT)) | 900 | if (int_st & AB_IO(1, BI_SHIFT)) |
872 | fsi_data_pop(&master->fsib); | 901 | fsi_stream_transfer(&master->fsib.capture); |
873 | 902 | ||
874 | fsi_count_fifo_err(&master->fsia); | 903 | fsi_count_fifo_err(&master->fsia); |
875 | fsi_count_fifo_err(&master->fsib); | 904 | fsi_count_fifo_err(&master->fsib); |
@@ -881,11 +910,271 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
881 | } | 910 | } |
882 | 911 | ||
883 | /* | 912 | /* |
913 | * dma data transfer handler | ||
914 | */ | ||
915 | static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) | ||
916 | { | ||
917 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
918 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); | ||
919 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | ||
920 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | ||
921 | |||
922 | io->dma = dma_map_single(dai->dev, runtime->dma_area, | ||
923 | snd_pcm_lib_buffer_bytes(io->substream), dir); | ||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io) | ||
928 | { | ||
929 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); | ||
930 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | ||
931 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | ||
932 | |||
933 | dma_unmap_single(dai->dev, io->dma, | ||
934 | snd_pcm_lib_buffer_bytes(io->substream), dir); | ||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | static void fsi_dma_complete(void *data) | ||
939 | { | ||
940 | struct fsi_stream *io = (struct fsi_stream *)data; | ||
941 | struct fsi_priv *fsi = fsi_stream_to_priv(io); | ||
942 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
943 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); | ||
944 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | ||
945 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | ||
946 | |||
947 | dma_sync_single_for_cpu(dai->dev, io->dma, | ||
948 | samples_to_bytes(runtime, io->period_samples), dir); | ||
949 | |||
950 | io->buff_sample_pos += io->period_samples; | ||
951 | io->period_pos++; | ||
952 | |||
953 | if (io->period_pos >= runtime->periods) { | ||
954 | io->period_pos = 0; | ||
955 | io->buff_sample_pos = 0; | ||
956 | } | ||
957 | |||
958 | fsi_count_fifo_err(fsi); | ||
959 | fsi_stream_transfer(io); | ||
960 | |||
961 | snd_pcm_period_elapsed(io->substream); | ||
962 | } | ||
963 | |||
964 | static dma_addr_t fsi_dma_get_area(struct fsi_stream *io) | ||
965 | { | ||
966 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
967 | |||
968 | return io->dma + samples_to_bytes(runtime, io->buff_sample_pos); | ||
969 | } | ||
970 | |||
971 | static void fsi_dma_do_tasklet(unsigned long data) | ||
972 | { | ||
973 | struct fsi_stream *io = (struct fsi_stream *)data; | ||
974 | struct fsi_priv *fsi = fsi_stream_to_priv(io); | ||
975 | struct dma_chan *chan; | ||
976 | struct snd_soc_dai *dai; | ||
977 | struct dma_async_tx_descriptor *desc; | ||
978 | struct scatterlist sg; | ||
979 | struct snd_pcm_runtime *runtime; | ||
980 | enum dma_data_direction dir; | ||
981 | dma_cookie_t cookie; | ||
982 | int is_play = fsi_stream_is_play(fsi, io); | ||
983 | int len; | ||
984 | dma_addr_t buf; | ||
985 | |||
986 | if (!fsi_stream_is_working(fsi, io)) | ||
987 | return; | ||
988 | |||
989 | dai = fsi_get_dai(io->substream); | ||
990 | chan = io->chan; | ||
991 | runtime = io->substream->runtime; | ||
992 | dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | ||
993 | len = samples_to_bytes(runtime, io->period_samples); | ||
994 | buf = fsi_dma_get_area(io); | ||
995 | |||
996 | dma_sync_single_for_device(dai->dev, io->dma, len, dir); | ||
997 | |||
998 | sg_init_table(&sg, 1); | ||
999 | sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)), | ||
1000 | len , offset_in_page(buf)); | ||
1001 | sg_dma_address(&sg) = buf; | ||
1002 | sg_dma_len(&sg) = len; | ||
1003 | |||
1004 | desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir, | ||
1005 | DMA_PREP_INTERRUPT | | ||
1006 | DMA_CTRL_ACK); | ||
1007 | if (!desc) { | ||
1008 | dev_err(dai->dev, "device_prep_slave_sg() fail\n"); | ||
1009 | return; | ||
1010 | } | ||
1011 | |||
1012 | desc->callback = fsi_dma_complete; | ||
1013 | desc->callback_param = io; | ||
1014 | |||
1015 | cookie = desc->tx_submit(desc); | ||
1016 | if (cookie < 0) { | ||
1017 | dev_err(dai->dev, "tx_submit() fail\n"); | ||
1018 | return; | ||
1019 | } | ||
1020 | |||
1021 | dma_async_issue_pending(chan); | ||
1022 | |||
1023 | /* | ||
1024 | * FIXME | ||
1025 | * | ||
1026 | * In DMAEngine case, codec and FSI cannot be started simultaneously | ||
1027 | * since FSI is using tasklet. | ||
1028 | * Therefore, in capture case, probably FSI FIFO will have got | ||
1029 | * overflow error in this point. | ||
1030 | * in that case, DMA cannot start transfer until error was cleared. | ||
1031 | */ | ||
1032 | if (!is_play) { | ||
1033 | if (ERR_OVER & fsi_reg_read(fsi, DIFF_ST)) { | ||
1034 | fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); | ||
1035 | fsi_reg_write(fsi, DIFF_ST, 0); | ||
1036 | } | ||
1037 | } | ||
1038 | } | ||
1039 | |||
1040 | static bool fsi_dma_filter(struct dma_chan *chan, void *param) | ||
1041 | { | ||
1042 | struct sh_dmae_slave *slave = param; | ||
1043 | |||
1044 | chan->private = slave; | ||
1045 | |||
1046 | return true; | ||
1047 | } | ||
1048 | |||
1049 | static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) | ||
1050 | { | ||
1051 | tasklet_schedule(&io->tasklet); | ||
1052 | |||
1053 | return 0; | ||
1054 | } | ||
1055 | |||
1056 | static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, | ||
1057 | int start) | ||
1058 | { | ||
1059 | u32 bws; | ||
1060 | u32 dma; | ||
1061 | |||
1062 | switch (io->sample_width * start) { | ||
1063 | case 2: | ||
1064 | bws = CR_BWS_16; | ||
1065 | dma = VDMD_STREAM | DMA_ON; | ||
1066 | break; | ||
1067 | case 4: | ||
1068 | bws = CR_BWS_24; | ||
1069 | dma = VDMD_BACK | DMA_ON; | ||
1070 | break; | ||
1071 | default: | ||
1072 | bws = 0; | ||
1073 | dma = 0; | ||
1074 | } | ||
1075 | |||
1076 | fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws); | ||
1077 | fsi_reg_write(fsi, OUT_DMAC, dma); | ||
1078 | } | ||
1079 | |||
1080 | static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) | ||
1081 | { | ||
1082 | dma_cap_mask_t mask; | ||
1083 | |||
1084 | dma_cap_zero(mask); | ||
1085 | dma_cap_set(DMA_SLAVE, mask); | ||
1086 | |||
1087 | io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave); | ||
1088 | if (!io->chan) | ||
1089 | return -EIO; | ||
1090 | |||
1091 | tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io); | ||
1092 | |||
1093 | return 0; | ||
1094 | } | ||
1095 | |||
1096 | static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) | ||
1097 | { | ||
1098 | tasklet_kill(&io->tasklet); | ||
1099 | |||
1100 | fsi_stream_stop(fsi, io); | ||
1101 | |||
1102 | if (io->chan) | ||
1103 | dma_release_channel(io->chan); | ||
1104 | |||
1105 | io->chan = NULL; | ||
1106 | return 0; | ||
1107 | } | ||
1108 | |||
1109 | static struct fsi_stream_handler fsi_dma_push_handler = { | ||
1110 | .init = fsi_dma_init, | ||
1111 | .quit = fsi_dma_quit, | ||
1112 | .probe = fsi_dma_probe, | ||
1113 | .transfer = fsi_dma_transfer, | ||
1114 | .remove = fsi_dma_remove, | ||
1115 | .start_stop = fsi_dma_push_start_stop, | ||
1116 | }; | ||
1117 | |||
1118 | /* | ||
884 | * dai ops | 1119 | * dai ops |
885 | */ | 1120 | */ |
1121 | static void fsi_fifo_init(struct fsi_priv *fsi, | ||
1122 | struct fsi_stream *io, | ||
1123 | struct device *dev) | ||
1124 | { | ||
1125 | struct fsi_master *master = fsi_get_master(fsi); | ||
1126 | int is_play = fsi_stream_is_play(fsi, io); | ||
1127 | u32 shift, i; | ||
1128 | int frame_capa; | ||
1129 | |||
1130 | /* get on-chip RAM capacity */ | ||
1131 | shift = fsi_master_read(master, FIFO_SZ); | ||
1132 | shift >>= fsi_get_port_shift(fsi, io); | ||
1133 | shift &= FIFO_SZ_MASK; | ||
1134 | frame_capa = 256 << shift; | ||
1135 | dev_dbg(dev, "fifo = %d words\n", frame_capa); | ||
1136 | |||
1137 | /* | ||
1138 | * The maximum number of sample data varies depending | ||
1139 | * on the number of channels selected for the format. | ||
1140 | * | ||
1141 | * FIFOs are used in 4-channel units in 3-channel mode | ||
1142 | * and in 8-channel units in 5- to 7-channel mode | ||
1143 | * meaning that more FIFOs than the required size of DPRAM | ||
1144 | * are used. | ||
1145 | * | ||
1146 | * ex) if 256 words of DP-RAM is connected | ||
1147 | * 1 channel: 256 (256 x 1 = 256) | ||
1148 | * 2 channels: 128 (128 x 2 = 256) | ||
1149 | * 3 channels: 64 ( 64 x 3 = 192) | ||
1150 | * 4 channels: 64 ( 64 x 4 = 256) | ||
1151 | * 5 channels: 32 ( 32 x 5 = 160) | ||
1152 | * 6 channels: 32 ( 32 x 6 = 192) | ||
1153 | * 7 channels: 32 ( 32 x 7 = 224) | ||
1154 | * 8 channels: 32 ( 32 x 8 = 256) | ||
1155 | */ | ||
1156 | for (i = 1; i < fsi->chan_num; i <<= 1) | ||
1157 | frame_capa >>= 1; | ||
1158 | dev_dbg(dev, "%d channel %d store\n", | ||
1159 | fsi->chan_num, frame_capa); | ||
1160 | |||
1161 | io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); | ||
1162 | |||
1163 | /* | ||
1164 | * set interrupt generation factor | ||
1165 | * clear FIFO | ||
1166 | */ | ||
1167 | if (is_play) { | ||
1168 | fsi_reg_write(fsi, DOFF_CTL, IRQ_HALF); | ||
1169 | fsi_reg_mask_set(fsi, DOFF_CTL, FIFO_CLR, FIFO_CLR); | ||
1170 | } else { | ||
1171 | fsi_reg_write(fsi, DIFF_CTL, IRQ_HALF); | ||
1172 | fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); | ||
1173 | } | ||
1174 | } | ||
886 | 1175 | ||
887 | static int fsi_hw_startup(struct fsi_priv *fsi, | 1176 | static int fsi_hw_startup(struct fsi_priv *fsi, |
888 | int is_play, | 1177 | struct fsi_stream *io, |
889 | struct device *dev) | 1178 | struct device *dev) |
890 | { | 1179 | { |
891 | struct fsi_master *master = fsi_get_master(fsi); | 1180 | struct fsi_master *master = fsi_get_master(fsi); |
@@ -934,17 +1223,16 @@ static int fsi_hw_startup(struct fsi_priv *fsi, | |||
934 | } | 1223 | } |
935 | 1224 | ||
936 | /* irq clear */ | 1225 | /* irq clear */ |
937 | fsi_irq_disable(fsi, is_play); | 1226 | fsi_irq_disable(fsi, io); |
938 | fsi_irq_clear_status(fsi); | 1227 | fsi_irq_clear_status(fsi); |
939 | 1228 | ||
940 | /* fifo init */ | 1229 | /* fifo init */ |
941 | fsi_fifo_init(fsi, is_play, dev); | 1230 | fsi_fifo_init(fsi, io, dev); |
942 | 1231 | ||
943 | return 0; | 1232 | return 0; |
944 | } | 1233 | } |
945 | 1234 | ||
946 | static void fsi_hw_shutdown(struct fsi_priv *fsi, | 1235 | static void fsi_hw_shutdown(struct fsi_priv *fsi, |
947 | int is_play, | ||
948 | struct device *dev) | 1236 | struct device *dev) |
949 | { | 1237 | { |
950 | if (fsi_is_clk_master(fsi)) | 1238 | if (fsi_is_clk_master(fsi)) |
@@ -955,18 +1243,16 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
955 | struct snd_soc_dai *dai) | 1243 | struct snd_soc_dai *dai) |
956 | { | 1244 | { |
957 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1245 | struct fsi_priv *fsi = fsi_get_priv(substream); |
958 | int is_play = fsi_is_play(substream); | ||
959 | 1246 | ||
960 | return fsi_hw_startup(fsi, is_play, dai->dev); | 1247 | return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev); |
961 | } | 1248 | } |
962 | 1249 | ||
963 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | 1250 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, |
964 | struct snd_soc_dai *dai) | 1251 | struct snd_soc_dai *dai) |
965 | { | 1252 | { |
966 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1253 | struct fsi_priv *fsi = fsi_get_priv(substream); |
967 | int is_play = fsi_is_play(substream); | ||
968 | 1254 | ||
969 | fsi_hw_shutdown(fsi, is_play, dai->dev); | 1255 | fsi_hw_shutdown(fsi, dai->dev); |
970 | fsi->rate = 0; | 1256 | fsi->rate = 0; |
971 | } | 1257 | } |
972 | 1258 | ||
@@ -974,18 +1260,19 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
974 | struct snd_soc_dai *dai) | 1260 | struct snd_soc_dai *dai) |
975 | { | 1261 | { |
976 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1262 | struct fsi_priv *fsi = fsi_get_priv(substream); |
977 | int is_play = fsi_is_play(substream); | 1263 | struct fsi_stream *io = fsi_stream_get(fsi, substream); |
978 | int ret = 0; | 1264 | int ret = 0; |
979 | 1265 | ||
980 | switch (cmd) { | 1266 | switch (cmd) { |
981 | case SNDRV_PCM_TRIGGER_START: | 1267 | case SNDRV_PCM_TRIGGER_START: |
982 | fsi_stream_push(fsi, is_play, substream); | 1268 | fsi_stream_init(fsi, io, substream); |
983 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); | 1269 | ret = fsi_stream_transfer(io); |
984 | fsi_port_start(fsi, is_play); | 1270 | if (0 == ret) |
1271 | fsi_stream_start(fsi, io); | ||
985 | break; | 1272 | break; |
986 | case SNDRV_PCM_TRIGGER_STOP: | 1273 | case SNDRV_PCM_TRIGGER_STOP: |
987 | fsi_port_stop(fsi, is_play); | 1274 | fsi_stream_stop(fsi, io); |
988 | fsi_stream_pop(fsi, is_play); | 1275 | fsi_stream_quit(fsi, io); |
989 | break; | 1276 | break; |
990 | } | 1277 | } |
991 | 1278 | ||
@@ -1036,8 +1323,7 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) | |||
1036 | static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 1323 | static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
1037 | { | 1324 | { |
1038 | struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); | 1325 | struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); |
1039 | struct fsi_master *master = fsi_get_master(fsi); | 1326 | set_rate_func set_rate = fsi_get_info_set_rate(fsi); |
1040 | set_rate_func set_rate = fsi_get_info_set_rate(master); | ||
1041 | u32 flags = fsi_get_info_flags(fsi); | 1327 | u32 flags = fsi_get_info_flags(fsi); |
1042 | int ret; | 1328 | int ret; |
1043 | 1329 | ||
@@ -1151,7 +1437,7 @@ static int fsi_hw_free(struct snd_pcm_substream *substream) | |||
1151 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) | 1437 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) |
1152 | { | 1438 | { |
1153 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1439 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1154 | struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream)); | 1440 | struct fsi_stream *io = fsi_stream_get(fsi, substream); |
1155 | 1441 | ||
1156 | return fsi_sample2frame(fsi, io->buff_sample_pos); | 1442 | return fsi_sample2frame(fsi, io->buff_sample_pos); |
1157 | } | 1443 | } |
@@ -1239,11 +1525,24 @@ static struct snd_soc_platform_driver fsi_soc_platform = { | |||
1239 | /* | 1525 | /* |
1240 | * platform function | 1526 | * platform function |
1241 | */ | 1527 | */ |
1528 | static void fsi_handler_init(struct fsi_priv *fsi) | ||
1529 | { | ||
1530 | fsi->playback.handler = &fsi_pio_push_handler; /* default PIO */ | ||
1531 | fsi->playback.priv = fsi; | ||
1532 | fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ | ||
1533 | fsi->capture.priv = fsi; | ||
1534 | |||
1535 | if (fsi->info->tx_id) { | ||
1536 | fsi->playback.slave.slave_id = fsi->info->tx_id; | ||
1537 | fsi->playback.handler = &fsi_dma_push_handler; | ||
1538 | } | ||
1539 | } | ||
1242 | 1540 | ||
1243 | static int fsi_probe(struct platform_device *pdev) | 1541 | static int fsi_probe(struct platform_device *pdev) |
1244 | { | 1542 | { |
1245 | struct fsi_master *master; | 1543 | struct fsi_master *master; |
1246 | const struct platform_device_id *id_entry; | 1544 | const struct platform_device_id *id_entry; |
1545 | struct sh_fsi_platform_info *info = pdev->dev.platform_data; | ||
1247 | struct resource *res; | 1546 | struct resource *res; |
1248 | unsigned int irq; | 1547 | unsigned int irq; |
1249 | int ret; | 1548 | int ret; |
@@ -1278,17 +1577,30 @@ static int fsi_probe(struct platform_device *pdev) | |||
1278 | 1577 | ||
1279 | /* master setting */ | 1578 | /* master setting */ |
1280 | master->irq = irq; | 1579 | master->irq = irq; |
1281 | master->info = pdev->dev.platform_data; | ||
1282 | master->core = (struct fsi_core *)id_entry->driver_data; | 1580 | master->core = (struct fsi_core *)id_entry->driver_data; |
1283 | spin_lock_init(&master->lock); | 1581 | spin_lock_init(&master->lock); |
1284 | 1582 | ||
1285 | /* FSI A setting */ | 1583 | /* FSI A setting */ |
1286 | master->fsia.base = master->base; | 1584 | master->fsia.base = master->base; |
1287 | master->fsia.master = master; | 1585 | master->fsia.master = master; |
1586 | master->fsia.info = &info->port_a; | ||
1587 | fsi_handler_init(&master->fsia); | ||
1588 | ret = fsi_stream_probe(&master->fsia); | ||
1589 | if (ret < 0) { | ||
1590 | dev_err(&pdev->dev, "FSIA stream probe failed\n"); | ||
1591 | goto exit_iounmap; | ||
1592 | } | ||
1288 | 1593 | ||
1289 | /* FSI B setting */ | 1594 | /* FSI B setting */ |
1290 | master->fsib.base = master->base + 0x40; | 1595 | master->fsib.base = master->base + 0x40; |
1291 | master->fsib.master = master; | 1596 | master->fsib.master = master; |
1597 | master->fsib.info = &info->port_b; | ||
1598 | fsi_handler_init(&master->fsib); | ||
1599 | ret = fsi_stream_probe(&master->fsib); | ||
1600 | if (ret < 0) { | ||
1601 | dev_err(&pdev->dev, "FSIB stream probe failed\n"); | ||
1602 | goto exit_fsia; | ||
1603 | } | ||
1292 | 1604 | ||
1293 | pm_runtime_enable(&pdev->dev); | 1605 | pm_runtime_enable(&pdev->dev); |
1294 | dev_set_drvdata(&pdev->dev, master); | 1606 | dev_set_drvdata(&pdev->dev, master); |
@@ -1297,7 +1609,7 @@ static int fsi_probe(struct platform_device *pdev) | |||
1297 | id_entry->name, master); | 1609 | id_entry->name, master); |
1298 | if (ret) { | 1610 | if (ret) { |
1299 | dev_err(&pdev->dev, "irq request err\n"); | 1611 | dev_err(&pdev->dev, "irq request err\n"); |
1300 | goto exit_iounmap; | 1612 | goto exit_fsib; |
1301 | } | 1613 | } |
1302 | 1614 | ||
1303 | ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform); | 1615 | ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform); |
@@ -1319,6 +1631,10 @@ exit_snd_soc: | |||
1319 | snd_soc_unregister_platform(&pdev->dev); | 1631 | snd_soc_unregister_platform(&pdev->dev); |
1320 | exit_free_irq: | 1632 | exit_free_irq: |
1321 | free_irq(irq, master); | 1633 | free_irq(irq, master); |
1634 | exit_fsib: | ||
1635 | fsi_stream_remove(&master->fsib); | ||
1636 | exit_fsia: | ||
1637 | fsi_stream_remove(&master->fsia); | ||
1322 | exit_iounmap: | 1638 | exit_iounmap: |
1323 | iounmap(master->base); | 1639 | iounmap(master->base); |
1324 | pm_runtime_disable(&pdev->dev); | 1640 | pm_runtime_disable(&pdev->dev); |
@@ -1341,6 +1657,9 @@ static int fsi_remove(struct platform_device *pdev) | |||
1341 | snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); | 1657 | snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); |
1342 | snd_soc_unregister_platform(&pdev->dev); | 1658 | snd_soc_unregister_platform(&pdev->dev); |
1343 | 1659 | ||
1660 | fsi_stream_remove(&master->fsia); | ||
1661 | fsi_stream_remove(&master->fsib); | ||
1662 | |||
1344 | iounmap(master->base); | 1663 | iounmap(master->base); |
1345 | kfree(master); | 1664 | kfree(master); |
1346 | 1665 | ||
@@ -1348,30 +1667,29 @@ static int fsi_remove(struct platform_device *pdev) | |||
1348 | } | 1667 | } |
1349 | 1668 | ||
1350 | static void __fsi_suspend(struct fsi_priv *fsi, | 1669 | static void __fsi_suspend(struct fsi_priv *fsi, |
1351 | int is_play, | 1670 | struct fsi_stream *io, |
1352 | struct device *dev) | 1671 | struct device *dev) |
1353 | { | 1672 | { |
1354 | if (!fsi_stream_is_working(fsi, is_play)) | 1673 | if (!fsi_stream_is_working(fsi, io)) |
1355 | return; | 1674 | return; |
1356 | 1675 | ||
1357 | fsi_port_stop(fsi, is_play); | 1676 | fsi_stream_stop(fsi, io); |
1358 | fsi_hw_shutdown(fsi, is_play, dev); | 1677 | fsi_hw_shutdown(fsi, dev); |
1359 | } | 1678 | } |
1360 | 1679 | ||
1361 | static void __fsi_resume(struct fsi_priv *fsi, | 1680 | static void __fsi_resume(struct fsi_priv *fsi, |
1362 | int is_play, | 1681 | struct fsi_stream *io, |
1363 | struct device *dev) | 1682 | struct device *dev) |
1364 | { | 1683 | { |
1365 | if (!fsi_stream_is_working(fsi, is_play)) | 1684 | if (!fsi_stream_is_working(fsi, io)) |
1366 | return; | 1685 | return; |
1367 | 1686 | ||
1368 | fsi_hw_startup(fsi, is_play, dev); | 1687 | fsi_hw_startup(fsi, io, dev); |
1369 | 1688 | ||
1370 | if (fsi_is_clk_master(fsi) && fsi->rate) | 1689 | if (fsi_is_clk_master(fsi) && fsi->rate) |
1371 | fsi_set_master_clk(dev, fsi, fsi->rate, 1); | 1690 | fsi_set_master_clk(dev, fsi, fsi->rate, 1); |
1372 | 1691 | ||
1373 | fsi_port_start(fsi, is_play); | 1692 | fsi_stream_start(fsi, io); |
1374 | |||
1375 | } | 1693 | } |
1376 | 1694 | ||
1377 | static int fsi_suspend(struct device *dev) | 1695 | static int fsi_suspend(struct device *dev) |
@@ -1380,11 +1698,11 @@ static int fsi_suspend(struct device *dev) | |||
1380 | struct fsi_priv *fsia = &master->fsia; | 1698 | struct fsi_priv *fsia = &master->fsia; |
1381 | struct fsi_priv *fsib = &master->fsib; | 1699 | struct fsi_priv *fsib = &master->fsib; |
1382 | 1700 | ||
1383 | __fsi_suspend(fsia, 1, dev); | 1701 | __fsi_suspend(fsia, &fsia->playback, dev); |
1384 | __fsi_suspend(fsia, 0, dev); | 1702 | __fsi_suspend(fsia, &fsia->capture, dev); |
1385 | 1703 | ||
1386 | __fsi_suspend(fsib, 1, dev); | 1704 | __fsi_suspend(fsib, &fsib->playback, dev); |
1387 | __fsi_suspend(fsib, 0, dev); | 1705 | __fsi_suspend(fsib, &fsib->capture, dev); |
1388 | 1706 | ||
1389 | return 0; | 1707 | return 0; |
1390 | } | 1708 | } |
@@ -1395,32 +1713,18 @@ static int fsi_resume(struct device *dev) | |||
1395 | struct fsi_priv *fsia = &master->fsia; | 1713 | struct fsi_priv *fsia = &master->fsia; |
1396 | struct fsi_priv *fsib = &master->fsib; | 1714 | struct fsi_priv *fsib = &master->fsib; |
1397 | 1715 | ||
1398 | __fsi_resume(fsia, 1, dev); | 1716 | __fsi_resume(fsia, &fsia->playback, dev); |
1399 | __fsi_resume(fsia, 0, dev); | 1717 | __fsi_resume(fsia, &fsia->capture, dev); |
1400 | 1718 | ||
1401 | __fsi_resume(fsib, 1, dev); | 1719 | __fsi_resume(fsib, &fsib->playback, dev); |
1402 | __fsi_resume(fsib, 0, dev); | 1720 | __fsi_resume(fsib, &fsib->capture, dev); |
1403 | 1721 | ||
1404 | return 0; | 1722 | return 0; |
1405 | } | 1723 | } |
1406 | 1724 | ||
1407 | static int fsi_runtime_nop(struct device *dev) | ||
1408 | { | ||
1409 | /* Runtime PM callback shared between ->runtime_suspend() | ||
1410 | * and ->runtime_resume(). Simply returns success. | ||
1411 | * | ||
1412 | * This driver re-initializes all registers after | ||
1413 | * pm_runtime_get_sync() anyway so there is no need | ||
1414 | * to save and restore registers here. | ||
1415 | */ | ||
1416 | return 0; | ||
1417 | } | ||
1418 | |||
1419 | static struct dev_pm_ops fsi_pm_ops = { | 1725 | static struct dev_pm_ops fsi_pm_ops = { |
1420 | .suspend = fsi_suspend, | 1726 | .suspend = fsi_suspend, |
1421 | .resume = fsi_resume, | 1727 | .resume = fsi_resume, |
1422 | .runtime_suspend = fsi_runtime_nop, | ||
1423 | .runtime_resume = fsi_runtime_nop, | ||
1424 | }; | 1728 | }; |
1425 | 1729 | ||
1426 | static struct fsi_core fsi1_core = { | 1730 | static struct fsi_core fsi1_core = { |