diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-05-20 06:00:43 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-05-20 06:00:43 -0400 |
commit | d71f4cece4bd97d05592836202fc04ff2e7817e3 (patch) | |
tree | 6c877c7a938758b1323d9c97d46b9c536e618c69 /sound/soc/sh/fsi.c | |
parent | 19008bdacb9f7841166ebafe0aef361ee582ffbf (diff) | |
parent | ad8332c1302bcb4f80d593fd3eb477be9d7f5604 (diff) |
Merge branch 'topic/asoc' into for-linus
Conflicts:
sound/soc/codecs/ad1938.c
Diffstat (limited to 'sound/soc/sh/fsi.c')
-rw-r--r-- | sound/soc/sh/fsi.c | 191 |
1 files changed, 135 insertions, 56 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 8dc966f45c36..3396a0db06ba 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -41,14 +41,19 @@ | |||
41 | #define MUTE_ST 0x0028 | 41 | #define MUTE_ST 0x0028 |
42 | #define REG_END MUTE_ST | 42 | #define REG_END MUTE_ST |
43 | 43 | ||
44 | |||
45 | #define CPU_INT_ST 0x01F4 | ||
46 | #define CPU_IEMSK 0x01F8 | ||
47 | #define CPU_IMSK 0x01FC | ||
44 | #define INT_ST 0x0200 | 48 | #define INT_ST 0x0200 |
45 | #define IEMSK 0x0204 | 49 | #define IEMSK 0x0204 |
46 | #define IMSK 0x0208 | 50 | #define IMSK 0x0208 |
47 | #define MUTE 0x020C | 51 | #define MUTE 0x020C |
48 | #define CLK_RST 0x0210 | 52 | #define CLK_RST 0x0210 |
49 | #define SOFT_RST 0x0214 | 53 | #define SOFT_RST 0x0214 |
50 | #define MREG_START INT_ST | 54 | #define FIFO_SZ 0x0218 |
51 | #define MREG_END SOFT_RST | 55 | #define MREG_START CPU_INT_ST |
56 | #define MREG_END FIFO_SZ | ||
52 | 57 | ||
53 | /* DO_FMT */ | 58 | /* DO_FMT */ |
54 | /* DI_FMT */ | 59 | /* DI_FMT */ |
@@ -80,6 +85,17 @@ | |||
80 | #define INT_A_IN (1 << 4) | 85 | #define INT_A_IN (1 << 4) |
81 | #define INT_A_OUT (1 << 0) | 86 | #define INT_A_OUT (1 << 0) |
82 | 87 | ||
88 | /* SOFT_RST */ | ||
89 | #define PBSR (1 << 12) /* Port B Software Reset */ | ||
90 | #define PASR (1 << 8) /* Port A Software Reset */ | ||
91 | #define IR (1 << 4) /* Interrupt Reset */ | ||
92 | #define FSISR (1 << 0) /* Software Reset */ | ||
93 | |||
94 | /* FIFO_SZ */ | ||
95 | #define OUT_SZ_MASK 0x7 | ||
96 | #define BO_SZ_SHIFT 8 | ||
97 | #define AO_SZ_SHIFT 0 | ||
98 | |||
83 | #define FSI_RATES SNDRV_PCM_RATE_8000_96000 | 99 | #define FSI_RATES SNDRV_PCM_RATE_8000_96000 |
84 | 100 | ||
85 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | 101 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) |
@@ -105,11 +121,18 @@ struct fsi_priv { | |||
105 | int periods; | 121 | int periods; |
106 | }; | 122 | }; |
107 | 123 | ||
124 | struct fsi_regs { | ||
125 | u32 int_st; | ||
126 | u32 iemsk; | ||
127 | u32 imsk; | ||
128 | }; | ||
129 | |||
108 | struct fsi_master { | 130 | struct fsi_master { |
109 | void __iomem *base; | 131 | void __iomem *base; |
110 | int irq; | 132 | int irq; |
111 | struct fsi_priv fsia; | 133 | struct fsi_priv fsia; |
112 | struct fsi_priv fsib; | 134 | struct fsi_priv fsib; |
135 | struct fsi_regs *regs; | ||
113 | struct sh_fsi_platform_info *info; | 136 | struct sh_fsi_platform_info *info; |
114 | spinlock_t lock; | 137 | spinlock_t lock; |
115 | }; | 138 | }; |
@@ -317,7 +340,7 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) | |||
317 | /************************************************************************ | 340 | /************************************************************************ |
318 | 341 | ||
319 | 342 | ||
320 | ctrl function | 343 | irq function |
321 | 344 | ||
322 | 345 | ||
323 | ************************************************************************/ | 346 | ************************************************************************/ |
@@ -326,8 +349,8 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) | |||
326 | u32 data = fsi_port_ab_io_bit(fsi, is_play); | 349 | u32 data = fsi_port_ab_io_bit(fsi, is_play); |
327 | struct fsi_master *master = fsi_get_master(fsi); | 350 | struct fsi_master *master = fsi_get_master(fsi); |
328 | 351 | ||
329 | fsi_master_mask_set(master, IMSK, data, data); | 352 | fsi_master_mask_set(master, master->regs->imsk, data, data); |
330 | fsi_master_mask_set(master, IEMSK, data, data); | 353 | fsi_master_mask_set(master, master->regs->iemsk, data, data); |
331 | } | 354 | } |
332 | 355 | ||
333 | static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) | 356 | static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) |
@@ -335,10 +358,39 @@ static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) | |||
335 | u32 data = fsi_port_ab_io_bit(fsi, is_play); | 358 | u32 data = fsi_port_ab_io_bit(fsi, is_play); |
336 | struct fsi_master *master = fsi_get_master(fsi); | 359 | struct fsi_master *master = fsi_get_master(fsi); |
337 | 360 | ||
338 | fsi_master_mask_set(master, IMSK, data, 0); | 361 | fsi_master_mask_set(master, master->regs->imsk, data, 0); |
339 | fsi_master_mask_set(master, IEMSK, data, 0); | 362 | fsi_master_mask_set(master, master->regs->iemsk, data, 0); |
363 | } | ||
364 | |||
365 | static u32 fsi_irq_get_status(struct fsi_master *master) | ||
366 | { | ||
367 | return fsi_master_read(master, master->regs->int_st); | ||
368 | } | ||
369 | |||
370 | static void fsi_irq_clear_all_status(struct fsi_master *master) | ||
371 | { | ||
372 | fsi_master_write(master, master->regs->int_st, 0x0000000); | ||
340 | } | 373 | } |
341 | 374 | ||
375 | static void fsi_irq_clear_status(struct fsi_priv *fsi) | ||
376 | { | ||
377 | u32 data = 0; | ||
378 | struct fsi_master *master = fsi_get_master(fsi); | ||
379 | |||
380 | data |= fsi_port_ab_io_bit(fsi, 0); | ||
381 | data |= fsi_port_ab_io_bit(fsi, 1); | ||
382 | |||
383 | /* clear interrupt factor */ | ||
384 | fsi_master_mask_set(master, master->regs->int_st, data, 0); | ||
385 | } | ||
386 | |||
387 | /************************************************************************ | ||
388 | |||
389 | |||
390 | ctrl function | ||
391 | |||
392 | |||
393 | ************************************************************************/ | ||
342 | static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) | 394 | static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) |
343 | { | 395 | { |
344 | u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); | 396 | u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); |
@@ -350,41 +402,61 @@ static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) | |||
350 | fsi_master_mask_set(master, CLK_RST, val, 0); | 402 | fsi_master_mask_set(master, CLK_RST, val, 0); |
351 | } | 403 | } |
352 | 404 | ||
353 | static void fsi_irq_init(struct fsi_priv *fsi, int is_play) | 405 | static void fsi_fifo_init(struct fsi_priv *fsi, |
406 | int is_play, | ||
407 | struct snd_soc_dai *dai) | ||
354 | { | 408 | { |
355 | u32 data; | 409 | struct fsi_master *master = fsi_get_master(fsi); |
356 | u32 ctrl; | 410 | u32 ctrl, shift, i; |
357 | 411 | ||
358 | data = fsi_port_ab_io_bit(fsi, is_play); | 412 | /* get on-chip RAM capacity */ |
359 | ctrl = is_play ? DOFF_CTL : DIFF_CTL; | 413 | shift = fsi_master_read(master, FIFO_SZ); |
414 | shift >>= fsi_is_port_a(fsi) ? AO_SZ_SHIFT : BO_SZ_SHIFT; | ||
415 | shift &= OUT_SZ_MASK; | ||
416 | fsi->fifo_max = 256 << shift; | ||
417 | dev_dbg(dai->dev, "fifo = %d words\n", fsi->fifo_max); | ||
360 | 418 | ||
361 | /* set IMSK */ | 419 | /* |
362 | fsi_irq_disable(fsi, is_play); | 420 | * The maximum number of sample data varies depending |
421 | * on the number of channels selected for the format. | ||
422 | * | ||
423 | * FIFOs are used in 4-channel units in 3-channel mode | ||
424 | * and in 8-channel units in 5- to 7-channel mode | ||
425 | * meaning that more FIFOs than the required size of DPRAM | ||
426 | * are used. | ||
427 | * | ||
428 | * ex) if 256 words of DP-RAM is connected | ||
429 | * 1 channel: 256 (256 x 1 = 256) | ||
430 | * 2 channels: 128 (128 x 2 = 256) | ||
431 | * 3 channels: 64 ( 64 x 3 = 192) | ||
432 | * 4 channels: 64 ( 64 x 4 = 256) | ||
433 | * 5 channels: 32 ( 32 x 5 = 160) | ||
434 | * 6 channels: 32 ( 32 x 6 = 192) | ||
435 | * 7 channels: 32 ( 32 x 7 = 224) | ||
436 | * 8 channels: 32 ( 32 x 8 = 256) | ||
437 | */ | ||
438 | for (i = 1; i < fsi->chan; i <<= 1) | ||
439 | fsi->fifo_max >>= 1; | ||
440 | dev_dbg(dai->dev, "%d channel %d store\n", fsi->chan, fsi->fifo_max); | ||
441 | |||
442 | ctrl = is_play ? DOFF_CTL : DIFF_CTL; | ||
363 | 443 | ||
364 | /* set interrupt generation factor */ | 444 | /* set interrupt generation factor */ |
365 | fsi_reg_write(fsi, ctrl, IRQ_HALF); | 445 | fsi_reg_write(fsi, ctrl, IRQ_HALF); |
366 | 446 | ||
367 | /* clear FIFO */ | 447 | /* clear FIFO */ |
368 | fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); | 448 | fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); |
369 | |||
370 | /* clear interrupt factor */ | ||
371 | fsi_master_mask_set(fsi_get_master(fsi), INT_ST, data, 0); | ||
372 | } | 449 | } |
373 | 450 | ||
374 | static void fsi_soft_all_reset(struct fsi_master *master) | 451 | static void fsi_soft_all_reset(struct fsi_master *master) |
375 | { | 452 | { |
376 | u32 status = fsi_master_read(master, SOFT_RST); | ||
377 | |||
378 | /* port AB reset */ | 453 | /* port AB reset */ |
379 | status &= 0x000000ff; | 454 | fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0); |
380 | fsi_master_write(master, SOFT_RST, status); | ||
381 | mdelay(10); | 455 | mdelay(10); |
382 | 456 | ||
383 | /* soft reset */ | 457 | /* soft reset */ |
384 | status &= 0x000000f0; | 458 | fsi_master_mask_set(master, SOFT_RST, FSISR, 0); |
385 | fsi_master_write(master, SOFT_RST, status); | 459 | fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR); |
386 | status |= 0x00000001; | ||
387 | fsi_master_write(master, SOFT_RST, status); | ||
388 | mdelay(10); | 460 | mdelay(10); |
389 | } | 461 | } |
390 | 462 | ||
@@ -559,12 +631,11 @@ static int fsi_data_pop(struct fsi_priv *fsi, int startup) | |||
559 | static irqreturn_t fsi_interrupt(int irq, void *data) | 631 | static irqreturn_t fsi_interrupt(int irq, void *data) |
560 | { | 632 | { |
561 | struct fsi_master *master = data; | 633 | struct fsi_master *master = data; |
562 | u32 status = fsi_master_read(master, SOFT_RST) & ~0x00000010; | 634 | u32 int_st = fsi_irq_get_status(master); |
563 | u32 int_st = fsi_master_read(master, INT_ST); | ||
564 | 635 | ||
565 | /* clear irq status */ | 636 | /* clear irq status */ |
566 | fsi_master_write(master, SOFT_RST, status); | 637 | fsi_master_mask_set(master, SOFT_RST, IR, 0); |
567 | fsi_master_write(master, SOFT_RST, status | 0x00000010); | 638 | fsi_master_mask_set(master, SOFT_RST, IR, IR); |
568 | 639 | ||
569 | if (int_st & INT_A_OUT) | 640 | if (int_st & INT_A_OUT) |
570 | fsi_data_push(&master->fsia, 0); | 641 | fsi_data_push(&master->fsia, 0); |
@@ -575,7 +646,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
575 | if (int_st & INT_B_IN) | 646 | if (int_st & INT_B_IN) |
576 | fsi_data_pop(&master->fsib, 0); | 647 | fsi_data_pop(&master->fsib, 0); |
577 | 648 | ||
578 | fsi_master_write(master, INT_ST, 0x0000000); | 649 | fsi_irq_clear_all_status(master); |
579 | 650 | ||
580 | return IRQ_HANDLED; | 651 | return IRQ_HANDLED; |
581 | } | 652 | } |
@@ -669,29 +740,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
669 | dev_err(dai->dev, "unknown format.\n"); | 740 | dev_err(dai->dev, "unknown format.\n"); |
670 | return -EINVAL; | 741 | return -EINVAL; |
671 | } | 742 | } |
672 | |||
673 | switch (fsi->chan) { | ||
674 | case 1: | ||
675 | fsi->fifo_max = 256; | ||
676 | break; | ||
677 | case 2: | ||
678 | fsi->fifo_max = 128; | ||
679 | break; | ||
680 | case 3: | ||
681 | case 4: | ||
682 | fsi->fifo_max = 64; | ||
683 | break; | ||
684 | case 5: | ||
685 | case 6: | ||
686 | case 7: | ||
687 | case 8: | ||
688 | fsi->fifo_max = 32; | ||
689 | break; | ||
690 | default: | ||
691 | dev_err(dai->dev, "channel size error.\n"); | ||
692 | return -EINVAL; | ||
693 | } | ||
694 | |||
695 | fsi_reg_write(fsi, reg, data); | 743 | fsi_reg_write(fsi, reg, data); |
696 | 744 | ||
697 | /* | 745 | /* |
@@ -700,8 +748,12 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
700 | if (is_master) | 748 | if (is_master) |
701 | fsi_clk_ctrl(fsi, 1); | 749 | fsi_clk_ctrl(fsi, 1); |
702 | 750 | ||
703 | /* irq setting */ | 751 | /* irq clear */ |
704 | fsi_irq_init(fsi, is_play); | 752 | fsi_irq_disable(fsi, is_play); |
753 | fsi_irq_clear_status(fsi); | ||
754 | |||
755 | /* fifo init */ | ||
756 | fsi_fifo_init(fsi, is_play, dai); | ||
705 | 757 | ||
706 | return ret; | 758 | return ret; |
707 | } | 759 | } |
@@ -913,6 +965,7 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform); | |||
913 | static int fsi_probe(struct platform_device *pdev) | 965 | static int fsi_probe(struct platform_device *pdev) |
914 | { | 966 | { |
915 | struct fsi_master *master; | 967 | struct fsi_master *master; |
968 | const struct platform_device_id *id_entry; | ||
916 | struct resource *res; | 969 | struct resource *res; |
917 | unsigned int irq; | 970 | unsigned int irq; |
918 | int ret; | 971 | int ret; |
@@ -922,6 +975,12 @@ static int fsi_probe(struct platform_device *pdev) | |||
922 | return -ENODEV; | 975 | return -ENODEV; |
923 | } | 976 | } |
924 | 977 | ||
978 | id_entry = pdev->id_entry; | ||
979 | if (!id_entry) { | ||
980 | dev_err(&pdev->dev, "unknown fsi device\n"); | ||
981 | return -ENODEV; | ||
982 | } | ||
983 | |||
925 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 984 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
926 | irq = platform_get_irq(pdev, 0); | 985 | irq = platform_get_irq(pdev, 0); |
927 | if (!res || (int)irq <= 0) { | 986 | if (!res || (int)irq <= 0) { |
@@ -950,6 +1009,7 @@ static int fsi_probe(struct platform_device *pdev) | |||
950 | master->fsia.master = master; | 1009 | master->fsia.master = master; |
951 | master->fsib.base = master->base + 0x40; | 1010 | master->fsib.base = master->base + 0x40; |
952 | master->fsib.master = master; | 1011 | master->fsib.master = master; |
1012 | master->regs = (struct fsi_regs *)id_entry->driver_data; | ||
953 | spin_lock_init(&master->lock); | 1013 | spin_lock_init(&master->lock); |
954 | 1014 | ||
955 | pm_runtime_enable(&pdev->dev); | 1015 | pm_runtime_enable(&pdev->dev); |
@@ -962,7 +1022,8 @@ static int fsi_probe(struct platform_device *pdev) | |||
962 | 1022 | ||
963 | fsi_soft_all_reset(master); | 1023 | fsi_soft_all_reset(master); |
964 | 1024 | ||
965 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); | 1025 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, |
1026 | id_entry->name, master); | ||
966 | if (ret) { | 1027 | if (ret) { |
967 | dev_err(&pdev->dev, "irq request err\n"); | 1028 | dev_err(&pdev->dev, "irq request err\n"); |
968 | goto exit_iounmap; | 1029 | goto exit_iounmap; |
@@ -1029,6 +1090,23 @@ static struct dev_pm_ops fsi_pm_ops = { | |||
1029 | .runtime_resume = fsi_runtime_nop, | 1090 | .runtime_resume = fsi_runtime_nop, |
1030 | }; | 1091 | }; |
1031 | 1092 | ||
1093 | static struct fsi_regs fsi_regs = { | ||
1094 | .int_st = INT_ST, | ||
1095 | .iemsk = IEMSK, | ||
1096 | .imsk = IMSK, | ||
1097 | }; | ||
1098 | |||
1099 | static struct fsi_regs fsi2_regs = { | ||
1100 | .int_st = CPU_INT_ST, | ||
1101 | .iemsk = CPU_IEMSK, | ||
1102 | .imsk = CPU_IMSK, | ||
1103 | }; | ||
1104 | |||
1105 | static struct platform_device_id fsi_id_table[] = { | ||
1106 | { "sh_fsi", (kernel_ulong_t)&fsi_regs }, | ||
1107 | { "sh_fsi2", (kernel_ulong_t)&fsi2_regs }, | ||
1108 | }; | ||
1109 | |||
1032 | static struct platform_driver fsi_driver = { | 1110 | static struct platform_driver fsi_driver = { |
1033 | .driver = { | 1111 | .driver = { |
1034 | .name = "sh_fsi", | 1112 | .name = "sh_fsi", |
@@ -1036,6 +1114,7 @@ static struct platform_driver fsi_driver = { | |||
1036 | }, | 1114 | }, |
1037 | .probe = fsi_probe, | 1115 | .probe = fsi_probe, |
1038 | .remove = fsi_remove, | 1116 | .remove = fsi_remove, |
1117 | .id_table = fsi_id_table, | ||
1039 | }; | 1118 | }; |
1040 | 1119 | ||
1041 | static int __init fsi_mobile_init(void) | 1120 | static int __init fsi_mobile_init(void) |