diff options
Diffstat (limited to 'arch/arm/mach-shmobile/board-ap4evb.c')
-rw-r--r-- | arch/arm/mach-shmobile/board-ap4evb.c | 211 |
1 files changed, 139 insertions, 72 deletions
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index d3260542b94..b1222dc4338 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -501,7 +501,12 @@ static struct platform_device keysc_device = { static struct resource mipidsi0_resources[] = { [0] = { .start = 0xffc60000, - .end = 0xffc68fff, + .end = 0xffc63073, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0xffc68000, + .end = 0xffc680ef, .flags = IORESOURCE_MEM, }, }; @@ -509,6 +514,7 @@ static struct resource mipidsi0_resources[] = { static struct sh_mipi_dsi_info mipidsi0_info = { .data_format = MIPI_RGB888, .lcd_chan = &lcdc_info.ch[0], + .vsynw_offset = 17, }; static struct platform_device mipidsi0_device = { @@ -521,84 +527,135 @@ static struct platform_device mipidsi0_device = { }, }; -/* This function will disappear when we switch to (runtime) PM */ -static int __init ap4evb_init_display_clk(void) +static struct platform_device *qhd_devices[] __initdata = { + &mipidsi0_device, + &keysc_device, +}; +#endif /* CONFIG_AP4EVB_QHD */ + +/* FSI */ +#define IRQ_FSI evt2irq(0x1840) +static int __fsi_set_rate(struct clk *clk, long rate, int enable) { - struct clk *lcdc_clk; - struct clk *dsitx_clk; - int ret; + int ret = 0; - lcdc_clk = clk_get(&lcdc_device.dev, "sh_mobile_lcdc_fb.0"); - if (IS_ERR(lcdc_clk)) - return PTR_ERR(lcdc_clk); + if (rate <= 0) + return ret; - dsitx_clk = clk_get(&mipidsi0_device.dev, "sh-mipi-dsi.0"); - if (IS_ERR(dsitx_clk)) { - ret = PTR_ERR(dsitx_clk); - goto eclkdsitxget; + if (enable) { + ret = clk_set_rate(clk, rate); + if (0 == ret) + ret = clk_enable(clk); + } else { + clk_disable(clk); } - ret = clk_enable(lcdc_clk); - if (ret < 0) - goto eclklcdcon; + return ret; +} - ret = clk_enable(dsitx_clk); - if (ret < 0) - goto eclkdsitxon; +static int __fsi_set_round_rate(struct clk *clk, long rate, int enable) +{ + return __fsi_set_rate(clk, clk_round_rate(clk, rate), enable); +} - return 0; +static int fsi_ak4642_set_rate(struct device *dev, int rate, int enable) +{ + struct clk *fsia_ick; + struct clk *fsiack; + int ret = -EIO; -eclkdsitxon: - clk_disable(lcdc_clk); -eclklcdcon: - clk_put(dsitx_clk); -eclkdsitxget: - clk_put(lcdc_clk); + fsia_ick = clk_get(dev, "icka"); + if (IS_ERR(fsia_ick)) + return PTR_ERR(fsia_ick); - return ret; -} -device_initcall(ap4evb_init_display_clk); + /* + * 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; -static struct platform_device *qhd_devices[] __initdata = { - &mipidsi0_device, - &keysc_device, -}; -#endif /* CONFIG_AP4EVB_QHD */ + /* + * 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; -/* FSI */ -#define IRQ_FSI evt2irq(0x1840) + ret = __fsi_set_round_rate(fsia_ick, rate, enable); + if ((ret < 0) && enable) + __fsi_set_round_rate(fsiack, rate, 0); /* disable FSI ACK */ -static int fsi_set_rate(int is_porta, int rate) +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; + 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_round_rate(fsib_clk, fsib_rate, enable); clk_put(fsib_clk); + if (ret < 0) + return ret; + + /* FSI DIV setting */ + ret = __fsi_set_round_rate(fdiv_clk, fdiv_rate, enable); + if (ret < 0) { + /* disable FSI B */ + if (enable) + __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; } @@ -675,10 +732,15 @@ static struct platform_device lcdc1_device = { }, }; +static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq, + unsigned long *parent_freq); + + 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, + .clk_optimize_parent = ap4evb_clk_optimize, }; static struct resource hdmi_resources[] = { @@ -705,6 +767,25 @@ static struct platform_device hdmi_device = { }, }; +static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq, + unsigned long *parent_freq) +{ + struct clk *hdmi_ick = clk_get(&hdmi_device.dev, "ick"); + long error; + + if (IS_ERR(hdmi_ick)) { + int ret = PTR_ERR(hdmi_ick); + pr_err("Cannot get HDMI ICK: %d\n", ret); + return ret; + } + + error = clk_round_parent(hdmi_ick, target, best_freq, parent_freq, 1, 64); + + clk_put(hdmi_ick); + + return error; +} + static struct gpio_led ap4evb_leds[] = { { .name = "led4", @@ -880,6 +961,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); @@ -896,23 +982,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); @@ -921,16 +995,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; |