From 2669efec085bfc02006a452e1b5930f28bab959b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 31 Oct 2010 10:43:14 -0400 Subject: ARM: mach-shmobile: ap4evb: Add HDMI sound support Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 46 ++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-shmobile/board-ap4evb.c') diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 46ca4d4abf91..32d9e2816e56 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -565,12 +565,50 @@ static struct platform_device *qhd_devices[] __initdata = { /* FSI */ #define IRQ_FSI evt2irq(0x1840) + +static int fsi_set_rate(int is_porta, int rate) +{ + struct clk *fsib_clk; + struct clk *fdiv_clk = &sh7372_fsidivb_clk; + 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 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; + break; + default: + pr_err("unsupported rate in FSI2 port B\n"); + ret = -EINVAL; + break; + } + + clk_put(fsib_clk); + + return ret; +} + static struct sh_fsi_platform_info fsi_info = { .porta_flags = SH_FSI_BRS_INV | SH_FSI_OUT_SLAVE_MODE | SH_FSI_IN_SLAVE_MODE | SH_FSI_OFMT(PCM) | SH_FSI_IFMT(PCM), + + .portb_flags = SH_FSI_BRS_INV | + SH_FSI_BRM_INV | + SH_FSI_LRS_INV | + SH_FSI_OFMT(SPDIF), + .set_rate = fsi_set_rate, }; static struct resource fsi_resources[] = { @@ -634,6 +672,7 @@ static struct platform_device lcdc1_device = { static struct sh_mobile_hdmi_info hdmi_info = { .lcd_chan = &sh_mobile_lcdc1_info.ch[0], .lcd_dev = &lcdc1_device.dev, + .flags = HDMI_SND_SRC_SPDIF, }; static struct resource hdmi_resources[] = { @@ -992,6 +1031,7 @@ static void __init ap4evb_map_io(void) #define GPIO_PORT9CR 0xE6051009 #define GPIO_PORT10CR 0xE605100A +#define USCCR1 0xE6058144 static void __init ap4evb_init(void) { u32 srcr4; @@ -1062,7 +1102,7 @@ static void __init ap4evb_init(void) /* setup USB phy */ __raw_writew(0x8a0a, 0xE6058130); /* USBCR2 */ - /* enable FSI2 */ + /* enable FSI2 port A (ak4643) */ gpio_request(GPIO_FN_FSIAIBT, NULL); gpio_request(GPIO_FN_FSIAILR, NULL); gpio_request(GPIO_FN_FSIAISLD, NULL); @@ -1079,6 +1119,10 @@ static void __init ap4evb_init(void) gpio_request(GPIO_PORT41, NULL); gpio_direction_input(GPIO_PORT41); + /* setup FSI2 port B (HDMI) */ + gpio_request(GPIO_FN_FSIBCK, NULL); + __raw_writew(__raw_readw(USCCR1) & ~(1 << 6), USCCR1); /* use SPDIF */ + /* set SPU2 clock to 119.6 MHz */ clk = clk_get(NULL, "spu_clk"); if (!IS_ERR(clk)) { -- cgit v1.2.3 From 2e351ec61c35fac01ed1fb1ce35c183bf85e780c Mon Sep 17 00:00:00 2001 From: Yusuke Goda Date: Mon, 8 Nov 2010 05:45:09 +0000 Subject: ARM: mach-shmobile: ap4evb: Mark NOR boot loader partitions read-only. This makes the loader and bootenv partitions read-only under MTD for the on-board NOR flash. Signed-off-by: Yusuke Goda Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/mach-shmobile/board-ap4evb.c') diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 32d9e2816e56..63c2fcac8e1e 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -163,11 +163,13 @@ static struct mtd_partition nor_flash_partitions[] = { .name = "loader", .offset = 0x00000000, .size = 512 * 1024, + .mask_flags = MTD_WRITEABLE, }, { .name = "bootenv", .offset = MTDPART_OFS_APPEND, .size = 512 * 1024, + .mask_flags = MTD_WRITEABLE, }, { .name = "kernel_ro", -- cgit v1.2.3 From 574490e30a2a07cd7bc7ee7f63f1e61375a0359b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Nov 2010 03:11:09 +0000 Subject: ARM: mach-shmobile: ap4evb: add fsib 44100Hz rate Tested-by: Tony SIM Tested-by: TAKEI Mitsuharu Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/arm/mach-shmobile/board-ap4evb.c') diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 63c2fcac8e1e..d3260542b943 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -583,6 +583,10 @@ static int fsi_set_rate(int is_porta, int rate) 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; + 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)); -- cgit v1.2.3 From d4bc99b977e3a1dd10a84a01ebe59ac2ccebf0cd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 24 Nov 2010 02:44:06 +0000 Subject: 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 | 58 +++++++++++++++++++++++++++-------- arch/arm/mach-shmobile/clock-sh7372.c | 2 +- include/sound/sh_fsi.h | 6 ++-- sound/soc/sh/fsi.c | 19 ++++++++++-- 4 files changed, 67 insertions(+), 18 deletions(-) (limited to 'arch/arm/mach-shmobile/board-ap4evb.c') 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; + + if (rate <= 0) + return ret; -static int fsi_set_rate(int is_porta, int rate) + 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; } + /* FSI B setting */ + fsib_clk = clk_get(dev, "ickb"); + if (IS_ERR(fsib_clk)) + return -EIO; + + ret = __fsi_set_rate(fsib_clk, fsib_rate, enable); clk_put(fsib_clk); + if (ret < 0) + return ret; - 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; -- cgit v1.2.3 From 22de4e1fe446794acaebdf19dcaff4256d659972 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:17 +0000 Subject: 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(-) (limited to 'arch/arm/mach-shmobile/board-ap4evb.c') 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 @@ out: 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 */ -- cgit v1.2.3 From 421b446abeec55bed1251fab80cb5c12be58b773 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 19 Nov 2010 07:23:52 +0000 Subject: 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(-) (limited to 'arch/arm/mach-shmobile/board-ap4evb.c') 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; } -- cgit v1.2.3