/* locking: called with info->lock held */ static int sh_mobile_lcdc_notify(struct notifier_block *nb, unsigned long action, void *data) { struct fb_event *event = data; struct fb_info *info = event->info; struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; int ret; if (&ch->lcdc->notifier != nb) return NOTIFY_DONE; dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", __func__, action, event->data); switch(action) { case FB_EVENT_SUSPEND: if (try_module_get(board_cfg->owner) && board_cfg->display_off) { board_cfg->display_off(board_cfg->board_data); module_put(board_cfg->owner); } pm_runtime_put(info->device); sh_mobile_lcdc_stop(ch->lcdc); break; case FB_EVENT_RESUME: mutex_lock(&ch->open_lock); sh_mobile_fb_reconfig(info); mutex_unlock(&ch->open_lock); /* HDMI must be enabled before LCDC configuration */ if (try_module_get(board_cfg->owner) && board_cfg->display_on) { board_cfg->display_on(board_cfg->board_data, info); module_put(board_cfg->owner); } ret = sh_mobile_lcdc_start(ch->lcdc); if (!ret) pm_runtime_get_sync(info->device); } return NOTIFY_OK; }
/* * Locking: both .fb_release() and .fb_open() are called with info->lock held if * user == 1, or with console sem held, if user == 0. */ static int sh_mobile_release(struct fb_info *info, int user) { struct sh_mobile_lcdc_chan *ch = info->par; mutex_lock(&ch->open_lock); dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); ch->use_count--; /* Nothing to reconfigure, when called from fbcon */ if (user) { console_lock(); sh_mobile_fb_reconfig(info); console_unlock(); } mutex_unlock(&ch->open_lock); return 0; }