diff options
| author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2010-11-23 21:44:06 -0500 |
|---|---|---|
| committer | Paul Mundt <lethal@linux-sh.org> | 2010-11-24 01:29:56 -0500 |
| commit | d4bc99b977e3a1dd10a84a01ebe59ac2ccebf0cd (patch) | |
| tree | 441a72709a1dd40ac84b89cec8b036f00960a96b | |
| parent | e8ee13a818db4954517cea7da6e7c15b9656eb00 (diff) | |
ARM: mach-shmobile: ap4evb: FSI clock use proper process for HDMI
Current AP4 FSI set_rate function used bogus clock process
which didn't care enable/disable and clk->usecound.
To solve this issue, this patch also modify FSI driver to call
set_rate with enough options.
This patch modify it.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
| -rw-r--r-- | arch/arm/mach-shmobile/board-ap4evb.c | 58 | ||||
| -rw-r--r-- | arch/arm/mach-shmobile/clock-sh7372.c | 2 | ||||
| -rw-r--r-- | include/sound/sh_fsi.h | 6 | ||||
| -rw-r--r-- | sound/soc/sh/fsi.c | 19 |
4 files changed, 67 insertions, 18 deletions
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index d3260542b943..61c1068198ec 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c | |||
| @@ -567,40 +567,72 @@ static struct platform_device *qhd_devices[] __initdata = { | |||
| 567 | 567 | ||
| 568 | /* FSI */ | 568 | /* FSI */ |
| 569 | #define IRQ_FSI evt2irq(0x1840) | 569 | #define IRQ_FSI evt2irq(0x1840) |
| 570 | static int __fsi_set_rate(struct clk *clk, long rate, int enable) | ||
| 571 | { | ||
| 572 | int ret = 0; | ||
| 573 | |||
| 574 | if (rate <= 0) | ||
| 575 | return ret; | ||
| 570 | 576 | ||
| 571 | static int fsi_set_rate(int is_porta, int rate) | 577 | if (enable) { |
| 578 | ret = clk_set_rate(clk, clk_round_rate(clk, rate)); | ||
| 579 | if (0 == ret) | ||
| 580 | ret = clk_enable(clk); | ||
| 581 | } else { | ||
| 582 | clk_disable(clk); | ||
| 583 | } | ||
| 584 | |||
| 585 | return ret; | ||
| 586 | } | ||
| 587 | |||
| 588 | static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) | ||
| 572 | { | 589 | { |
| 573 | struct clk *fsib_clk; | 590 | struct clk *fsib_clk; |
| 574 | struct clk *fdiv_clk = &sh7372_fsidivb_clk; | 591 | struct clk *fdiv_clk = &sh7372_fsidivb_clk; |
| 592 | long fsib_rate = 0; | ||
| 593 | long fdiv_rate = 0; | ||
| 594 | int ackmd_bpfmd; | ||
| 575 | int ret; | 595 | int ret; |
| 576 | 596 | ||
| 577 | /* set_rate is not needed if port A */ | 597 | /* set_rate is not needed if port A */ |
| 578 | if (is_porta) | 598 | if (is_porta) |
| 579 | return 0; | 599 | return 0; |
| 580 | 600 | ||
| 581 | fsib_clk = clk_get(NULL, "fsib_clk"); | ||
| 582 | if (IS_ERR(fsib_clk)) | ||
| 583 | return -EINVAL; | ||
| 584 | |||
| 585 | switch (rate) { | 601 | switch (rate) { |
| 586 | case 44100: | 602 | case 44100: |
| 587 | clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 11283000)); | 603 | fsib_rate = rate * 256; |
| 588 | ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; | 604 | ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; |
| 589 | break; | 605 | break; |
| 590 | case 48000: | 606 | case 48000: |
| 591 | clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000)); | 607 | fsib_rate = 85428000; /* around 48kHz x 256 x 7 */ |
| 592 | clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000)); | 608 | fdiv_rate = rate * 256; |
| 593 | ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; | 609 | ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; |
| 594 | break; | 610 | break; |
| 595 | default: | 611 | default: |
| 596 | pr_err("unsupported rate in FSI2 port B\n"); | 612 | pr_err("unsupported rate in FSI2 port B\n"); |
| 597 | ret = -EINVAL; | 613 | return -EINVAL; |
| 598 | break; | ||
| 599 | } | 614 | } |
| 600 | 615 | ||
| 616 | /* FSI B setting */ | ||
| 617 | fsib_clk = clk_get(dev, "ickb"); | ||
| 618 | if (IS_ERR(fsib_clk)) | ||
| 619 | return -EIO; | ||
| 620 | |||
| 621 | ret = __fsi_set_rate(fsib_clk, fsib_rate, enable); | ||
| 601 | clk_put(fsib_clk); | 622 | clk_put(fsib_clk); |
| 623 | if (ret < 0) | ||
| 624 | return ret; | ||
| 602 | 625 | ||
| 603 | return ret; | 626 | /* FSI DIV setting */ |
| 627 | ret = __fsi_set_rate(fdiv_clk, fdiv_rate, enable); | ||
| 628 | if (ret < 0) { | ||
| 629 | /* disable FSI B */ | ||
| 630 | if (enable) | ||
| 631 | __fsi_set_rate(fsib_clk, fsib_rate, 0); | ||
| 632 | return ret; | ||
| 633 | } | ||
| 634 | |||
| 635 | return ackmd_bpfmd; | ||
| 604 | } | 636 | } |
| 605 | 637 | ||
| 606 | static struct sh_fsi_platform_info fsi_info = { | 638 | static struct sh_fsi_platform_info fsi_info = { |
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 13226323e4e0..4191e2921127 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c | |||
| @@ -471,7 +471,7 @@ static int fsidiv_set_rate(struct clk *clk, | |||
| 471 | return -ENOENT; | 471 | return -ENOENT; |
| 472 | 472 | ||
| 473 | __raw_writel(idx << 16, clk->mapping->base); | 473 | __raw_writel(idx << 16, clk->mapping->base); |
| 474 | return fsidiv_enable(clk); | 474 | return 0; |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 477 | static struct clk_ops fsidiv_clk_ops = { | 477 | static struct clk_ops fsidiv_clk_ops = { |
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index fa60cbda90a4..d79894192ae3 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h | |||
| @@ -85,7 +85,9 @@ | |||
| 85 | * ACK_MD (FSI2) | 85 | * ACK_MD (FSI2) |
| 86 | * CKG1 (FSI) | 86 | * CKG1 (FSI) |
| 87 | * | 87 | * |
| 88 | * err: return value < 0 | 88 | * err : return value < 0 |
| 89 | * no change : return value == 0 | ||
| 90 | * change xMD : return value > 0 | ||
| 89 | * | 91 | * |
| 90 | * 0x-00000AB | 92 | * 0x-00000AB |
| 91 | * | 93 | * |
| @@ -111,7 +113,7 @@ | |||
| 111 | struct sh_fsi_platform_info { | 113 | struct sh_fsi_platform_info { |
| 112 | unsigned long porta_flags; | 114 | unsigned long porta_flags; |
| 113 | unsigned long portb_flags; | 115 | unsigned long portb_flags; |
| 114 | int (*set_rate)(int is_porta, int rate); /* for master mode */ | 116 | int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); |
| 115 | }; | 117 | }; |
| 116 | 118 | ||
| 117 | #endif /* __SOUND_FSI_H */ | 119 | #endif /* __SOUND_FSI_H */ |
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 507e709f2807..136414f163e9 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
| @@ -132,6 +132,8 @@ struct fsi_priv { | |||
| 132 | struct fsi_stream playback; | 132 | struct fsi_stream playback; |
| 133 | struct fsi_stream capture; | 133 | struct fsi_stream capture; |
| 134 | 134 | ||
| 135 | long rate; | ||
| 136 | |||
| 135 | u32 mst_ctrl; | 137 | u32 mst_ctrl; |
| 136 | }; | 138 | }; |
| 137 | 139 | ||
| @@ -854,10 +856,17 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | |||
| 854 | { | 856 | { |
| 855 | struct fsi_priv *fsi = fsi_get_priv(substream); | 857 | struct fsi_priv *fsi = fsi_get_priv(substream); |
| 856 | int is_play = fsi_is_play(substream); | 858 | int is_play = fsi_is_play(substream); |
| 859 | struct fsi_master *master = fsi_get_master(fsi); | ||
| 860 | int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); | ||
| 857 | 861 | ||
| 858 | fsi_irq_disable(fsi, is_play); | 862 | fsi_irq_disable(fsi, is_play); |
| 859 | fsi_clk_ctrl(fsi, 0); | 863 | fsi_clk_ctrl(fsi, 0); |
| 860 | 864 | ||
| 865 | set_rate = master->info->set_rate; | ||
| 866 | if (set_rate && fsi->rate) | ||
| 867 | set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); | ||
| 868 | fsi->rate = 0; | ||
| 869 | |||
| 861 | pm_runtime_put_sync(dai->dev); | 870 | pm_runtime_put_sync(dai->dev); |
| 862 | } | 871 | } |
| 863 | 872 | ||
| @@ -891,9 +900,10 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | |||
| 891 | { | 900 | { |
| 892 | struct fsi_priv *fsi = fsi_get_priv(substream); | 901 | struct fsi_priv *fsi = fsi_get_priv(substream); |
| 893 | struct fsi_master *master = fsi_get_master(fsi); | 902 | struct fsi_master *master = fsi_get_master(fsi); |
| 894 | int (*set_rate)(int is_porta, int rate) = master->info->set_rate; | 903 | int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); |
| 895 | int fsi_ver = master->core->ver; | 904 | int fsi_ver = master->core->ver; |
| 896 | int is_play = fsi_is_play(substream); | 905 | int is_play = fsi_is_play(substream); |
| 906 | long rate = params_rate(params); | ||
| 897 | int ret; | 907 | int ret; |
| 898 | 908 | ||
| 899 | /* if slave mode, set_rate is not needed */ | 909 | /* if slave mode, set_rate is not needed */ |
| @@ -901,10 +911,15 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | |||
| 901 | return 0; | 911 | return 0; |
| 902 | 912 | ||
| 903 | /* it is error if no set_rate */ | 913 | /* it is error if no set_rate */ |
| 914 | set_rate = master->info->set_rate; | ||
| 904 | if (!set_rate) | 915 | if (!set_rate) |
| 905 | return -EIO; | 916 | return -EIO; |
| 906 | 917 | ||
| 907 | ret = set_rate(fsi_is_port_a(fsi), params_rate(params)); | 918 | ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); |
| 919 | if (ret < 0) /* error */ | ||
| 920 | return ret; | ||
| 921 | |||
| 922 | fsi->rate = rate; | ||
| 908 | if (ret > 0) { | 923 | if (ret > 0) { |
| 909 | u32 data = 0; | 924 | u32 data = 0; |
| 910 | 925 | ||
