From 4d048435e9864998f6a6ad16422393d42322716d Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 17 Nov 2010 11:44:00 +0000 Subject: [PATCH 1/7] ARM: mach-shmobile: sh7372 USB0/IIC1 MSTP fix Fix a MSTP assignment problem in the sh7372 clock framework code. The USB drivers should attach to MSTP322 not MSTP33 where IIC1 is located. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 7db31e6c6bf2..d3313a95dbfc 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -647,8 +647,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ - CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */ - CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP323]), /* USB0 */ + CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */ + CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */ From e8ee13a818db4954517cea7da6e7c15b9656eb00 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:22:58 +0000 Subject: [PATCH 2/7] ARM: mach-shmobile: clock-sh7372: remove fsidiv bogus disable Current FSIDIV clock framework had bogus disable. This patch remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 7db31e6c6bf2..13226323e4e0 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -453,10 +453,8 @@ static int fsidiv_enable(struct clk *clk) unsigned long value; value = __raw_readl(clk->mapping->base) >> 16; - if (value < 2) { - fsidiv_disable(clk); + if (value < 2) return -ENOENT; - } __raw_writel((value << 16) | 0x3, clk->mapping->base); @@ -468,11 +466,6 @@ static int fsidiv_set_rate(struct clk *clk, { int idx; - if (clk->parent->rate == rate) { - fsidiv_disable(clk); - return 0; - } - idx = (clk->parent->rate / rate) & 0xffff; if (idx < 2) return -ENOENT; From d4bc99b977e3a1dd10a84a01ebe59ac2ccebf0cd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 24 Nov 2010 02:44:06 +0000 Subject: [PATCH 3/7] 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 Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 60 ++++++++++++++++++++------- arch/arm/mach-shmobile/clock-sh7372.c | 2 +- include/sound/sh_fsi.h | 6 ++- sound/soc/sh/fsi.c | 19 ++++++++- 4 files changed, 68 insertions(+), 19 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 = { /* FSI */ #define IRQ_FSI evt2irq(0x1840) +static int __fsi_set_rate(struct clk *clk, long rate, int enable) +{ + int ret = 0; -static int fsi_set_rate(int is_porta, int rate) + if (rate <= 0) + return ret; + + if (enable) { + ret = clk_set_rate(clk, clk_round_rate(clk, rate)); + if (0 == ret) + ret = clk_enable(clk); + } else { + clk_disable(clk); + } + + return ret; +} + +static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) { struct clk *fsib_clk; struct clk *fdiv_clk = &sh7372_fsidivb_clk; + long fsib_rate = 0; + long fdiv_rate = 0; + int ackmd_bpfmd; int ret; /* set_rate is not needed if port A */ if (is_porta) return 0; - fsib_clk = clk_get(NULL, "fsib_clk"); - if (IS_ERR(fsib_clk)) - return -EINVAL; - switch (rate) { case 44100: - clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 11283000)); - ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; + fsib_rate = rate * 256; + ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; break; case 48000: - clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000)); - clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000)); - ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; + fsib_rate = 85428000; /* around 48kHz x 256 x 7 */ + fdiv_rate = rate * 256; + ackmd_bpfmd = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64; break; default: pr_err("unsupported rate in FSI2 port B\n"); - ret = -EINVAL; - break; + return -EINVAL; } - clk_put(fsib_clk); + /* FSI B setting */ + fsib_clk = clk_get(dev, "ickb"); + if (IS_ERR(fsib_clk)) + return -EIO; - return ret; + ret = __fsi_set_rate(fsib_clk, fsib_rate, enable); + clk_put(fsib_clk); + if (ret < 0) + return ret; + + /* FSI DIV setting */ + ret = __fsi_set_rate(fdiv_clk, fdiv_rate, enable); + if (ret < 0) { + /* disable FSI B */ + if (enable) + __fsi_set_rate(fsib_clk, fsib_rate, 0); + return ret; + } + + return ackmd_bpfmd; } 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, return -ENOENT; __raw_writel(idx << 16, clk->mapping->base); - return fsidiv_enable(clk); + return 0; } 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 @@ * ACK_MD (FSI2) * CKG1 (FSI) * - * err: return value < 0 + * err : return value < 0 + * no change : return value == 0 + * change xMD : return value > 0 * * 0x-00000AB * @@ -111,7 +113,7 @@ struct sh_fsi_platform_info { unsigned long porta_flags; unsigned long portb_flags; - int (*set_rate)(int is_porta, int rate); /* for master mode */ + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); }; #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 { struct fsi_stream playback; struct fsi_stream capture; + long rate; + u32 mst_ctrl; }; @@ -854,10 +856,17 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); int is_play = fsi_is_play(substream); + struct fsi_master *master = fsi_get_master(fsi); + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); fsi_irq_disable(fsi, is_play); fsi_clk_ctrl(fsi, 0); + set_rate = master->info->set_rate; + if (set_rate && fsi->rate) + set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); + fsi->rate = 0; + pm_runtime_put_sync(dai->dev); } @@ -891,9 +900,10 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); struct fsi_master *master = fsi_get_master(fsi); - int (*set_rate)(int is_porta, int rate) = master->info->set_rate; + int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); int fsi_ver = master->core->ver; int is_play = fsi_is_play(substream); + long rate = params_rate(params); int ret; /* if slave mode, set_rate is not needed */ @@ -901,10 +911,15 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, return 0; /* it is error if no set_rate */ + set_rate = master->info->set_rate; if (!set_rate) return -EIO; - ret = set_rate(fsi_is_port_a(fsi), params_rate(params)); + ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); + if (ret < 0) /* error */ + return ret; + + fsi->rate = rate; if (ret > 0) { u32 data = 0; From 22de4e1fe446794acaebdf19dcaff4256d659972 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:17 +0000 Subject: [PATCH 4/7] ARM: mach-shmobile: ap4evb: FSI clock use proper process for ak4642 Current AP4 FSI didn't use set_rate for ak4642, and used dummy rate when init. And FSI driver was modified to always call set_rate. The user which are using FSI set_rate is only AP4 now. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 96 +++++++++++++++++++-------- sound/soc/sh/fsi.c | 8 +-- 2 files changed, 68 insertions(+), 36 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 61c1068198ec..e084b423146e 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -575,7 +575,7 @@ static int __fsi_set_rate(struct clk *clk, long rate, int enable) return ret; if (enable) { - ret = clk_set_rate(clk, clk_round_rate(clk, rate)); + ret = clk_set_rate(clk, rate); if (0 == ret) ret = clk_enable(clk); } else { @@ -585,7 +585,56 @@ static int __fsi_set_rate(struct clk *clk, long rate, int enable) return ret; } -static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) +static int __fsi_set_round_rate(struct clk *clk, long rate, int enable) +{ + return __fsi_set_rate(clk, clk_round_rate(clk, rate), enable); +} + +static int fsi_ak4642_set_rate(struct device *dev, int rate, int enable) +{ + struct clk *fsia_ick; + struct clk *fsiack; + int ret = -EIO; + + fsia_ick = clk_get(dev, "icka"); + if (IS_ERR(fsia_ick)) + return PTR_ERR(fsia_ick); + + /* + * FSIACK is connected to AK4642, + * and use external clock pin from it. + * it is parent of fsia_ick now. + */ + fsiack = clk_get_parent(fsia_ick); + if (!fsiack) + goto fsia_ick_out; + + /* + * we get 1/1 divided clock by setting same rate to fsiack and fsia_ick + * + ** FIXME ** + * Because the freq_table of external clk (fsiack) are all 0, + * the return value of clk_round_rate became 0. + * So, it use __fsi_set_rate here. + */ + ret = __fsi_set_rate(fsiack, rate, enable); + if (ret < 0) + goto fsiack_out; + + ret = __fsi_set_round_rate(fsia_ick, rate, enable); + if ((ret < 0) && enable) + __fsi_set_round_rate(fsiack, rate, 0); /* disable FSI ACK */ + +fsiack_out: + clk_put(fsiack); + +fsia_ick_out: + clk_put(fsia_ick); + + return 0; +} + +static int fsi_hdmi_set_rate(struct device *dev, int rate, int enable) { struct clk *fsib_clk; struct clk *fdiv_clk = &sh7372_fsidivb_clk; @@ -594,10 +643,6 @@ static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) int ackmd_bpfmd; int ret; - /* set_rate is not needed if port A */ - if (is_porta) - return 0; - switch (rate) { case 44100: fsib_rate = rate * 256; @@ -618,23 +663,35 @@ static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) if (IS_ERR(fsib_clk)) return -EIO; - ret = __fsi_set_rate(fsib_clk, fsib_rate, enable); + ret = __fsi_set_round_rate(fsib_clk, fsib_rate, enable); clk_put(fsib_clk); if (ret < 0) return ret; /* FSI DIV setting */ - ret = __fsi_set_rate(fdiv_clk, fdiv_rate, enable); + ret = __fsi_set_round_rate(fdiv_clk, fdiv_rate, enable); if (ret < 0) { /* disable FSI B */ if (enable) - __fsi_set_rate(fsib_clk, fsib_rate, 0); + __fsi_set_round_rate(fsib_clk, fsib_rate, 0); return ret; } return ackmd_bpfmd; } +static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) +{ + int ret; + + if (is_porta) + ret = fsi_ak4642_set_rate(dev, rate, enable); + else + ret = fsi_hdmi_set_rate(dev, rate, enable); + + return ret; +} + static struct sh_fsi_platform_info fsi_info = { .porta_flags = SH_FSI_BRS_INV | SH_FSI_OUT_SLAVE_MODE | @@ -928,23 +985,11 @@ static int __init hdmi_init_pm_clock(void) device_initcall(hdmi_init_pm_clock); -#define FSIACK_DUMMY_RATE 48000 static int __init fsi_init_pm_clock(void) { struct clk *fsia_ick; int ret; - /* - * FSIACK is connected to AK4642, - * and the rate is depend on playing sound rate. - * So, set dummy rate (= 48k) here - */ - ret = clk_set_rate(&sh7372_fsiack_clk, FSIACK_DUMMY_RATE); - if (ret < 0) { - pr_err("Cannot set FSIACK dummy rate: %d\n", ret); - return ret; - } - fsia_ick = clk_get(&fsi_device.dev, "icka"); if (IS_ERR(fsia_ick)) { ret = PTR_ERR(fsia_ick); @@ -953,16 +998,9 @@ static int __init fsi_init_pm_clock(void) } ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk); - if (ret < 0) { - pr_err("Cannot set FSI-A parent: %d\n", ret); - goto out; - } - - ret = clk_set_rate(fsia_ick, FSIACK_DUMMY_RATE); if (ret < 0) - pr_err("Cannot set FSI-A rate: %d\n", ret); + pr_err("Cannot set FSI-A parent: %d\n", ret); -out: clk_put(fsia_ick); return ret; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 136414f163e9..4c2404b1b862 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -902,18 +902,12 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, struct fsi_master *master = fsi_get_master(fsi); int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); int fsi_ver = master->core->ver; - int is_play = fsi_is_play(substream); long rate = params_rate(params); int ret; - /* if slave mode, set_rate is not needed */ - if (!fsi_is_master_mode(fsi, is_play)) - return 0; - - /* it is error if no set_rate */ set_rate = master->info->set_rate; if (!set_rate) - return -EIO; + return 0; ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); if (ret < 0) /* error */ From a57b1a9bdfb61e8d7dc7acc5e2d8bc04c549e668 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:26 +0000 Subject: [PATCH 5/7] ARM: mach-shmobile: clock-sh7372: modify error code Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 4191e2921127..41663e0ca104 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -454,7 +454,7 @@ static int fsidiv_enable(struct clk *clk) value = __raw_readl(clk->mapping->base) >> 16; if (value < 2) - return -ENOENT; + return -EIO; __raw_writel((value << 16) | 0x3, clk->mapping->base); @@ -468,7 +468,7 @@ static int fsidiv_set_rate(struct clk *clk, idx = (clk->parent->rate / rate) & 0xffff; if (idx < 2) - return -ENOENT; + return -EINVAL; __raw_writel(idx << 16, clk->mapping->base); return 0; From b16a2892b9852839307894cc429b7a7b145138a7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:32 +0000 Subject: [PATCH 6/7] ARM: mach-shmobile: clock-sh7372: remove unnecessary fsi clocks Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 41663e0ca104..cbeca2849918 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -602,8 +602,6 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), - CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FSIA]), - CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FSIB]), CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), From 421b446abeec55bed1251fab80cb5c12be58b773 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:52 +0000 Subject: [PATCH 7/7] ARM: mach-shmobile: clock-sh7372: remove bogus pllc2 clock toggling. The PLLC2 clock was utilizing the same sort of enable/disable without regard to usecount approach that the FSIDIV clock was when being used as a PLL pass-through. This forces the enable/disable through the clock framework, which now prevents the clock from being ripped out or modified underneath users that have an existing handle on it. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 5 +++++ arch/arm/mach-shmobile/clock-sh7372.c | 12 ++---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index e084b423146e..d440e5f456ad 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -969,6 +969,11 @@ static int __init hdmi_init_pm_clock(void) goto out; } + ret = clk_enable(&sh7372_pllc2_clk); + if (ret < 0) { + pr_err("Cannot enable pllc2 clock\n"); + goto out; + } pr_debug("PLLC2 set frequency %lu\n", rate); ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk); diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index cbeca2849918..e18a1241a95e 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -230,21 +230,13 @@ static int pllc2_set_rate(struct clk *clk, if (idx < 0) return idx; - if (rate == clk->parent->rate) { - pllc2_disable(clk); - return 0; - } + if (rate == clk->parent->rate) + return -EINVAL; value = __raw_readl(PLLC2CR) & ~(0x3f << 24); - if (value & 0x80000000) - pllc2_disable(clk); - __raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR); - if (value & 0x80000000) - return pllc2_enable(clk); - return 0; }