+#ifdef CONFIG_HAVE_CLK
+static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
+{
+ if (atomic_inc_and_test(&priv->clk_usecnt)) {
+ clk_enable(priv->clk);
+ if (priv->dot_clk)
+ clk_enable(priv->dot_clk);
+ }
+}
+
+static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
+{
+ if (atomic_sub_return(1, &priv->clk_usecnt) == -1) {
+ if (priv->dot_clk)
+ clk_disable(priv->dot_clk);
+ clk_disable(priv->clk);
+ }
+}
+#else
+static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
+static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
+#endif
+
+static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct sh_mobile_lcdc_chan *ch = info->par;
+
+ /* enable clocks before accessing hardware */
+ sh_mobile_lcdc_clk_on(ch->lcdc);
+
+ /* trigger panel update */
+ lcdc_write_chan(ch, LDSM2R, 1);
+}
+
+static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
+{
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+
+ if (fbdefio)
+ schedule_delayed_work(&info->deferred_work, fbdefio->delay);
+}
+
+static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
+{
+ struct sh_mobile_lcdc_priv *priv = data;
+ unsigned long tmp;
+
+ /* acknowledge interrupt */
+ tmp = lcdc_read(priv, _LDINTR);
+ tmp &= 0xffffff00; /* mask in high 24 bits */
+ tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */
+ lcdc_write(priv, _LDINTR, tmp);
+
+ /* disable clocks */
+ sh_mobile_lcdc_clk_off(priv);
+ return IRQ_HANDLED;
+}
+