static int fb_probe()

in fbdev/da8xx-fb.c [1331:1540]


static int fb_probe(struct platform_device *device)
{
	struct da8xx_lcdc_platform_data *fb_pdata =
						dev_get_platdata(&device->dev);
	struct lcd_ctrl_config *lcd_cfg;
	struct fb_videomode *lcdc_info;
	struct fb_info *da8xx_fb_info;
	struct da8xx_fb_par *par;
	struct clk *tmp_lcdc_clk;
	int ret;
	unsigned long ulcm;

	if (fb_pdata == NULL) {
		dev_err(&device->dev, "Can not get platform data\n");
		return -ENOENT;
	}

	lcdc_info = da8xx_fb_get_videomode(device);
	if (lcdc_info == NULL)
		return -ENODEV;

	da8xx_fb_reg_base = devm_platform_ioremap_resource(device, 0);
	if (IS_ERR(da8xx_fb_reg_base))
		return PTR_ERR(da8xx_fb_reg_base);

	tmp_lcdc_clk = devm_clk_get(&device->dev, "fck");
	if (IS_ERR(tmp_lcdc_clk)) {
		dev_err(&device->dev, "Can not get device clock\n");
		return PTR_ERR(tmp_lcdc_clk);
	}

	pm_runtime_enable(&device->dev);
	pm_runtime_get_sync(&device->dev);

	/* Determine LCD IP Version */
	switch (lcdc_read(LCD_PID_REG)) {
	case 0x4C100102:
		lcd_revision = LCD_VERSION_1;
		break;
	case 0x4F200800:
	case 0x4F201000:
		lcd_revision = LCD_VERSION_2;
		break;
	default:
		dev_warn(&device->dev, "Unknown PID Reg value 0x%x, "
				"defaulting to LCD revision 1\n",
				lcdc_read(LCD_PID_REG));
		lcd_revision = LCD_VERSION_1;
		break;
	}

	lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data;

	if (!lcd_cfg) {
		ret = -EINVAL;
		goto err_pm_runtime_disable;
	}

	da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par),
					&device->dev);
	if (!da8xx_fb_info) {
		ret = -ENOMEM;
		goto err_pm_runtime_disable;
	}

	par = da8xx_fb_info->par;
	par->dev = &device->dev;
	par->lcdc_clk = tmp_lcdc_clk;
	par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk);

	par->lcd_supply = devm_regulator_get_optional(&device->dev, "lcd");
	if (IS_ERR(par->lcd_supply)) {
		if (PTR_ERR(par->lcd_supply) == -EPROBE_DEFER) {
			ret = -EPROBE_DEFER;
			goto err_release_fb;
		}

		par->lcd_supply = NULL;
	} else {
		ret = regulator_enable(par->lcd_supply);
		if (ret)
			goto err_release_fb;
	}

	fb_videomode_to_var(&da8xx_fb_var, lcdc_info);
	par->cfg = *lcd_cfg;

	da8xx_fb_lcd_reset();

	/* allocate frame buffer */
	par->vram_size = lcdc_info->xres * lcdc_info->yres * lcd_cfg->bpp;
	ulcm = lcm((lcdc_info->xres * lcd_cfg->bpp)/8, PAGE_SIZE);
	par->vram_size = roundup(par->vram_size/8, ulcm);
	par->vram_size = par->vram_size * LCD_NUM_BUFFERS;

	par->vram_virt = dmam_alloc_coherent(par->dev,
					     par->vram_size,
					     &par->vram_phys,
					     GFP_KERNEL | GFP_DMA);
	if (!par->vram_virt) {
		dev_err(&device->dev,
			"GLCD: kmalloc for frame buffer failed\n");
		ret = -EINVAL;
		goto err_release_fb;
	}

	da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt;
	da8xx_fb_fix.smem_start    = par->vram_phys;
	da8xx_fb_fix.smem_len      = par->vram_size;
	da8xx_fb_fix.line_length   = (lcdc_info->xres * lcd_cfg->bpp) / 8;

	par->dma_start = par->vram_phys;
	par->dma_end   = par->dma_start + lcdc_info->yres *
		da8xx_fb_fix.line_length - 1;

	/* allocate palette buffer */
	par->v_palette_base = dmam_alloc_coherent(par->dev, PALETTE_SIZE,
						  &par->p_palette_base,
						  GFP_KERNEL | GFP_DMA);
	if (!par->v_palette_base) {
		dev_err(&device->dev,
			"GLCD: kmalloc for palette buffer failed\n");
		ret = -EINVAL;
		goto err_release_fb;
	}

	par->irq = platform_get_irq(device, 0);
	if (par->irq < 0) {
		ret = -ENOENT;
		goto err_release_fb;
	}

	da8xx_fb_var.grayscale =
	    lcd_cfg->panel_shade == MONOCHROME ? 1 : 0;
	da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp;

	/* Initialize fbinfo */
	da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;
	da8xx_fb_info->fix = da8xx_fb_fix;
	da8xx_fb_info->var = da8xx_fb_var;
	da8xx_fb_info->fbops = &da8xx_fb_ops;
	da8xx_fb_info->pseudo_palette = par->pseudo_palette;
	da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ?
				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;

	ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
	if (ret)
		goto err_release_fb;
	da8xx_fb_info->cmap.len = par->palette_sz;

	/* initialize var_screeninfo */
	da8xx_fb_var.activate = FB_ACTIVATE_FORCE;
	fb_set_var(da8xx_fb_info, &da8xx_fb_var);

	platform_set_drvdata(device, da8xx_fb_info);

	/* initialize the vsync wait queue */
	init_waitqueue_head(&par->vsync_wait);
	par->vsync_timeout = HZ / 5;
	par->which_dma_channel_done = -1;
	spin_lock_init(&par->lock_for_chan_update);

	/* Register the Frame Buffer  */
	if (register_framebuffer(da8xx_fb_info) < 0) {
		dev_err(&device->dev,
			"GLCD: Frame Buffer Registration Failed!\n");
		ret = -EINVAL;
		goto err_dealloc_cmap;
	}

#ifdef CONFIG_CPU_FREQ
	ret = lcd_da8xx_cpufreq_register(par);
	if (ret) {
		dev_err(&device->dev, "failed to register cpufreq\n");
		goto err_cpu_freq;
	}
#endif

	if (lcd_revision == LCD_VERSION_1)
		lcdc_irq_handler = lcdc_irq_handler_rev01;
	else {
		init_waitqueue_head(&frame_done_wq);
		lcdc_irq_handler = lcdc_irq_handler_rev02;
	}

	ret = devm_request_irq(&device->dev, par->irq, lcdc_irq_handler, 0,
			       DRIVER_NAME, par);
	if (ret)
		goto irq_freq;
	return 0;

irq_freq:
#ifdef CONFIG_CPU_FREQ
	lcd_da8xx_cpufreq_deregister(par);
err_cpu_freq:
#endif
	unregister_framebuffer(da8xx_fb_info);

err_dealloc_cmap:
	fb_dealloc_cmap(&da8xx_fb_info->cmap);

err_release_fb:
	framebuffer_release(da8xx_fb_info);

err_pm_runtime_disable:
	pm_runtime_put_sync(&device->dev);
	pm_runtime_disable(&device->dev);

	return ret;
}