summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/board-ap4evb.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-shmobile/board-ap4evb.c')
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c211
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;