/**
 * adf_fbdev_open - default implementation of fbdev open op
 */
int adf_fbdev_open(struct fb_info *info, int user)
{
	struct adf_fbdev *fbdev = info->par;
	int ret;

	mutex_lock(&fbdev->refcount_lock);

	if (unlikely(fbdev->refcount == UINT_MAX)) {
		ret = -EMFILE;
		goto done;
	}

	if (!fbdev->refcount) {
		struct drm_mode_modeinfo mode;
		struct fb_videomode fbmode;
		struct adf_device *dev = adf_interface_parent(fbdev->intf);

		ret = adf_device_attach(dev, fbdev->eng, fbdev->intf);
		if (ret < 0 && ret != -EALREADY)
			goto done;

		ret = adf_fb_alloc(fbdev);
		if (ret < 0)
			goto done;

		adf_interface_current_mode(fbdev->intf, &mode);
		adf_modeinfo_to_fb_videomode(&mode, &fbmode);
		fb_videomode_to_var(&fbdev->info->var, &fbmode);

		adf_fbdev_set_format(fbdev, fbdev->default_format);
		adf_fbdev_fill_modelist(fbdev);
	}

	if (!fbdev_opened_once) {
		fbdev_opened_once = true;
	} else {
		ret = adf_fbdev_post(fbdev);
		if (ret < 0) {
			if (!fbdev->refcount)
				adf_fb_destroy(fbdev);
			goto done;
		}
	}

	fbdev->refcount++;
done:
	mutex_unlock(&fbdev->refcount_lock);
	return ret;
}
/**
 * adf_fbdev_set_par - default implementation of fbdev set_par op
 */
int adf_fbdev_set_par(struct fb_info *info)
{
	struct adf_fbdev *fbdev = info->par;
	struct adf_interface *intf = fbdev->intf;
	struct fb_videomode vmode;
	struct drm_mode_modeinfo mode;
	int ret;
	u32 format = drm_fourcc_from_fb_var(&info->var);

	fb_var_to_videomode(&vmode, &info->var);
	adf_modeinfo_from_fb_videomode(&vmode, &mode);
	ret = adf_interface_set_mode(intf, &mode);
	if (ret < 0)
		return ret;

	ret = adf_fbdev_post(fbdev);
	if (ret < 0)
		return ret;

	if (format != fbdev->format)
		adf_fbdev_set_format(fbdev, format);

	return 0;
}
/**
 * adf_fbdev_open - default implementation of fbdev open op
 */
int adf_fbdev_open(struct fb_info *info, int user)
{
	struct adf_fbdev *fbdev = info->par;
	int ret;

	if (!fbdev->open) {
		struct drm_mode_modeinfo mode;
		struct fb_videomode fbmode;
		struct adf_device *dev = adf_interface_parent(fbdev->intf);

		ret = adf_device_attach(dev, fbdev->eng, fbdev->intf);
		if (ret < 0 && ret != -EALREADY)
			return ret;

		ret = adf_fb_alloc(fbdev);
		if (ret < 0)
			return ret;

		adf_interface_current_mode(fbdev->intf, &mode);
		adf_modeinfo_to_fb_videomode(&mode, &fbmode);
		fb_videomode_to_var(&fbdev->info->var, &fbmode);

		adf_fbdev_set_format(fbdev, fbdev->default_format);
		adf_fbdev_fill_modelist(fbdev);
	}

	ret = adf_fbdev_post(fbdev);
	if (ret < 0) {
		if (!fbdev->open)
			adf_fb_destroy(fbdev);
		return ret;
	}

	fbdev->open = true;
	return 0;
}
/**
 * adf_fbdev_pan_display - default implementation of fbdev pan_display op
 */
int adf_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
	struct adf_fbdev *fbdev = info->par;
	return adf_fbdev_post(fbdev);
}