[go: nahoru, domu]

12c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
22c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * Common code for AUO-K190X framebuffer drivers
32c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner *
42c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
52c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner *
62c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * This program is free software; you can redistribute it and/or modify
72c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * it under the terms of the GNU General Public License version 2 as
82c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * published by the Free Software Foundation.
92c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/module.h>
122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/kernel.h>
132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/gpio.h>
1416559ae48c76f1ceb970b9719dea62b77eb5d06bGreg Kroah-Hartman#include <linux/platform_device.h>
152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/pm_runtime.h>
162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/fb.h>
172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/delay.h>
182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/uaccess.h>
192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/vmalloc.h>
202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <linux/regulator/consumer.h>
212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include <video/auo_k190xfb.h>
232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#include "auo_k190x.h"
252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstruct panel_info {
272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int w;
282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int h;
292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner};
302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/* table of panel specific parameters to be indexed into by the board drivers */
322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic struct panel_info panel_table[] = {
332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* standard 6" */
342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	[AUOK190X_RESOLUTION_800_600] = {
352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		.w = 800,
362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		.h = 600,
372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	},
382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* standard 9" */
392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	[AUOK190X_RESOLUTION_1024_768] = {
402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		.w = 1024,
412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		.h = 768,
422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	},
43b61f232ff09b6cff22d5186001027438c620da39Heiko Stübner	[AUOK190X_RESOLUTION_600_800] = {
44b61f232ff09b6cff22d5186001027438c620da39Heiko Stübner		.w = 600,
45b61f232ff09b6cff22d5186001027438c620da39Heiko Stübner		.h = 800,
46b61f232ff09b6cff22d5186001027438c620da39Heiko Stübner	},
47b61f232ff09b6cff22d5186001027438c620da39Heiko Stübner	[AUOK190X_RESOLUTION_768_1024] = {
48b61f232ff09b6cff22d5186001027438c620da39Heiko Stübner		.w = 768,
49b61f232ff09b6cff22d5186001027438c620da39Heiko Stübner		.h = 1024,
50b61f232ff09b6cff22d5186001027438c620da39Heiko Stübner	},
512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner};
522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * private I80 interface to the board driver
552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
562c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
572c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190x_issue_data(struct auok190xfb_par *par, u16 data)
582c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_WR, 0);
602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_hdb(par, data);
612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_WR, 1);
622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
632c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data)
652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_DC, 0);
672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_issue_data(par, data);
682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_DC, 1);
692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7146574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner/**
7246574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner * Conversion of 16bit color to 4bit grayscale
7346574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner * does roughly (0.3 * R + 0.6 G + 0.1 B) / 2
7446574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner */
7546574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübnerstatic inline int rgb565_to_gray4(u16 data, struct fb_var_screeninfo *var)
7646574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner{
7746574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	return ((((data & 0xF800) >> var->red.offset) * 77 +
7846574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		 ((data & 0x07E0) >> (var->green.offset + 1)) * 151 +
7946574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		 ((data & 0x1F) >> var->blue.offset) * 28) >> 8 >> 1);
8046574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner}
8146574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
8246574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübnerstatic int auok190x_issue_pixels_rgb565(struct auok190xfb_par *par, int size,
8346574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner					u16 *data)
8446574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner{
8546574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	struct fb_var_screeninfo *var = &par->info->var;
8646574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	struct device *dev = par->info->device;
8746574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	int i;
8846574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	u16 tmp;
8946574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
9046574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	if (size & 7) {
9146574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		dev_err(dev, "issue_pixels: size %d must be a multiple of 8\n",
9246574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner			size);
9346574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		return -EINVAL;
9446574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	}
9546574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
9646574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	for (i = 0; i < (size >> 2); i++) {
9746574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		par->board->set_ctl(par, AUOK190X_I80_WR, 0);
9846574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
9946574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		tmp  = (rgb565_to_gray4(data[4*i], var) & 0x000F);
10046574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		tmp |= (rgb565_to_gray4(data[4*i+1], var) << 4) & 0x00F0;
10146574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		tmp |= (rgb565_to_gray4(data[4*i+2], var) << 8) & 0x0F00;
10246574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		tmp |= (rgb565_to_gray4(data[4*i+3], var) << 12) & 0xF000;
10346574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
10446574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		par->board->set_hdb(par, tmp);
10546574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		par->board->set_ctl(par, AUOK190X_I80_WR, 1);
10646574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	}
10746574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
10846574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	return 0;
10946574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner}
11046574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
11176de404b452305409182748568444994df765d9dHeiko Stübnerstatic int auok190x_issue_pixels_gray8(struct auok190xfb_par *par, int size,
11276de404b452305409182748568444994df765d9dHeiko Stübner				       u16 *data)
1132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
1142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct device *dev = par->info->device;
1152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int i;
1162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	u16 tmp;
1172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (size & 3) {
1192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n",
1202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			size);
1212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return -EINVAL;
1222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
1232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	for (i = 0; i < (size >> 1); i++) {
1252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->board->set_ctl(par, AUOK190X_I80_WR, 0);
1262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* simple reduction of 8bit staticgray to 4bit gray
1282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * combines 4 * 4bit pixel values into a 16bit value
1292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 */
1302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		tmp  = (data[2*i] & 0xF0) >> 4;
1312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		tmp |= (data[2*i] & 0xF000) >> 8;
1322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		tmp |= (data[2*i+1] & 0xF0) << 4;
1332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		tmp |= (data[2*i+1] & 0xF000);
1342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->board->set_hdb(par, tmp);
1362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->board->set_ctl(par, AUOK190X_I80_WR, 1);
1372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
1382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
1402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
1412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
14276de404b452305409182748568444994df765d9dHeiko Stübnerstatic int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
14376de404b452305409182748568444994df765d9dHeiko Stübner				 u16 *data)
14476de404b452305409182748568444994df765d9dHeiko Stübner{
14576de404b452305409182748568444994df765d9dHeiko Stübner	struct fb_info *info = par->info;
14676de404b452305409182748568444994df765d9dHeiko Stübner	struct device *dev = par->info->device;
14776de404b452305409182748568444994df765d9dHeiko Stübner
14876de404b452305409182748568444994df765d9dHeiko Stübner	if (info->var.bits_per_pixel == 8 && info->var.grayscale)
14976de404b452305409182748568444994df765d9dHeiko Stübner		auok190x_issue_pixels_gray8(par, size, data);
15046574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	else if (info->var.bits_per_pixel == 16)
15146574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		auok190x_issue_pixels_rgb565(par, size, data);
15276de404b452305409182748568444994df765d9dHeiko Stübner	else
15376de404b452305409182748568444994df765d9dHeiko Stübner		dev_err(dev, "unsupported color mode (bits: %d, gray: %d)\n",
15476de404b452305409182748568444994df765d9dHeiko Stübner			info->var.bits_per_pixel, info->var.grayscale);
15576de404b452305409182748568444994df765d9dHeiko Stübner
15676de404b452305409182748568444994df765d9dHeiko Stübner	return 0;
15776de404b452305409182748568444994df765d9dHeiko Stübner}
15876de404b452305409182748568444994df765d9dHeiko Stübner
1592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic u16 auok190x_read_data(struct auok190xfb_par *par)
1602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
1612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	u16 data;
1622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1632c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_OE, 0);
1642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	data = par->board->get_hdb(par);
1652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_OE, 1);
1662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return data;
1682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
1692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
1712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * Command interface for the controller drivers
1722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
1732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1742c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnervoid auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data)
1752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
1762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_CS, 0);
1772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_issue_cmd(par, data);
1782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_CS, 1);
1792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
1802c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_send_command_nowait);
1812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnervoid auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd,
1832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				  int argc, u16 *argv)
1842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
1852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int i;
1862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_CS, 0);
1882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_issue_cmd(par, cmd);
1892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	for (i = 0; i < argc; i++)
1912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		auok190x_issue_data(par, argv[i]);
1922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_CS, 1);
1932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
1942c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait);
1952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerint auok190x_send_command(struct auok190xfb_par *par, u16 data)
1972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
1982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int ret;
1992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = par->board->wait_for_rdy(par);
2012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret)
2022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return ret;
2032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_send_command_nowait(par, data);
2052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
2062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
2072c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_send_command);
2082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerint auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd,
2102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			   int argc, u16 *argv)
2112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
2122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int ret;
2132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = par->board->wait_for_rdy(par);
2152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret)
2162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return ret;
2172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_send_cmdargs_nowait(par, cmd, argc, argv);
2192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
2202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
2212c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_send_cmdargs);
2222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerint auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd,
2242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			   int argc, u16 *argv)
2252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
2262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int i, ret;
2272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = par->board->wait_for_rdy(par);
2292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret)
2302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return ret;
2312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_CS, 0);
2332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_issue_cmd(par, cmd);
2342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	for (i = 0; i < argc; i++)
2362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		argv[i] = auok190x_read_data(par);
2372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_CS, 1);
2382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
2402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
2412c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_read_cmdargs);
2422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2432c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnervoid auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd,
2442c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				  int argc, u16 *argv, int size, u16 *data)
2452c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
2462c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int i;
2472c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2482c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_CS, 0);
2492c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2502c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_issue_cmd(par, cmd);
2512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	for (i = 0; i < argc; i++)
2532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		auok190x_issue_data(par, argv[i]);
2542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_issue_pixels(par, size, data);
2562c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2572c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->set_ctl(par, AUOK190X_I80_CS, 1);
2582c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
2592c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait);
2602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerint auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd,
2622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				  int argc, u16 *argv, int size, u16 *data)
2632c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
2642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int ret;
2652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = par->board->wait_for_rdy(par);
2672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret)
2682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return ret;
2692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data);
2712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
2732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
2742c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels);
2752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
2772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * fbdefio callbacks - common on both controllers.
2782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
2792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190xfb_dpy_first_io(struct fb_info *info)
2812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
2822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* tell runtime-pm that we wish to use the device in a short time */
2832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_get(info->device);
2842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
2852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
2862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/* this is called back from the deferred io workqueue */
2872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190xfb_dpy_deferred_io(struct fb_info *info,
2882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				struct list_head *pagelist)
2892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
2902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_deferred_io *fbdefio = info->fbdefio;
2912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
292a1655100ddfa10829b7d3b055611f268a82e335aHeiko Stübner	u16 line_length = info->fix.line_length;
2932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	u16 yres = info->var.yres;
2942c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	u16 y1 = 0, h = 0;
2952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int prev_index = -1;
2962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct page *cur;
2972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int h_inc;
2982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int threshold;
2992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (!list_empty(pagelist))
3012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* the device resume should've been requested through first_io,
3022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * if the resume did not finish until now, wait for it.
3032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 */
3042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		pm_runtime_barrier(info->device);
3052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	else
3062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* We reached this via the fsync or some other way.
3072c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * In either case the first_io function did not run,
3082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * so we runtime_resume the device here synchronously.
3092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 */
3102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		pm_runtime_get_sync(info->device);
3112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* Do a full screen update every n updates to prevent
3132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 * excessive darkening of the Sipix display.
3142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 * If we do this, there is no need to walk the pages.
3152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 */
3162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (par->need_refresh(par)) {
3172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->update_all(par);
3182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto out;
3192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
3202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* height increment is fixed per page */
322a1655100ddfa10829b7d3b055611f268a82e335aHeiko Stübner	h_inc = DIV_ROUND_UP(PAGE_SIZE , line_length);
3232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* calculate number of pages from pixel height */
3252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	threshold = par->consecutive_threshold / h_inc;
3262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (threshold < 1)
3272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		threshold = 1;
3282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* walk the written page list and swizzle the data */
3302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
3312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		if (prev_index < 0) {
3322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			/* just starting so assign first page */
333a1655100ddfa10829b7d3b055611f268a82e335aHeiko Stübner			y1 = (cur->index << PAGE_SHIFT) / line_length;
3342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			h = h_inc;
3352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		} else if ((cur->index - prev_index) <= threshold) {
3362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			/* page is within our threshold for single updates */
3372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			h += h_inc * (cur->index - prev_index);
3382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		} else {
3392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			/* page not consecutive, issue previous update first */
3402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			par->update_partial(par, y1, y1 + h);
3412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			/* start over with our non consecutive page */
343a1655100ddfa10829b7d3b055611f268a82e335aHeiko Stübner			y1 = (cur->index << PAGE_SHIFT) / line_length;
3442c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			h = h_inc;
3452c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		}
3462c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		prev_index = cur->index;
3472c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
3482c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3492c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* if we still have any pages to update we do so now */
3502c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (h >= yres)
3512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* its a full screen update, just do it */
3522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->update_all(par);
3532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	else
3542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->update_partial(par, y1, min((u16) (y1 + h), yres));
3552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3562c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerout:
3572c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_mark_last_busy(info->device);
3582c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_put_autosuspend(info->device);
3592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
3602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
3622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * framebuffer operations
3632c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
3642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
3662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * this is the slow path from userspace. they can seek and write to
3672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * the fb. it's inefficient to do anything less than a full screen draw
3682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
3692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf,
3702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				size_t count, loff_t *ppos)
3712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
3722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
3732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	unsigned long p = *ppos;
3742c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	void *dst;
3752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int err = 0;
3762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	unsigned long total_size;
3772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (info->state != FBINFO_STATE_RUNNING)
3792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return -EPERM;
3802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	total_size = info->fix.smem_len;
3822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (p > total_size)
3842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return -EFBIG;
3852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (count > total_size) {
3872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		err = -EFBIG;
3882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		count = total_size;
3892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
3902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (count + p > total_size) {
3922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		if (!err)
3932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			err = -ENOSPC;
3942c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		count = total_size - p;
3962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
3972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
3982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	dst = (void *)(info->screen_base + p);
3992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (copy_from_user(dst, buf, count))
4012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		err = -EFAULT;
4022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if  (!err)
4042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		*ppos += count;
4052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_all(par);
4072c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return (err) ? err : count;
4092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
4102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190xfb_fillrect(struct fb_info *info,
4122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				   const struct fb_fillrect *rect)
4132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
4142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
4152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	sys_fillrect(info, rect);
4172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_all(par);
4192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
4202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190xfb_copyarea(struct fb_info *info,
4222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				   const struct fb_copyarea *area)
4232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
4242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
4252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	sys_copyarea(info, area);
4272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_all(par);
4292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
4302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190xfb_imageblit(struct fb_info *info,
4322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				const struct fb_image *image)
4332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
4342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
4352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	sys_imageblit(info, image);
4372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_all(par);
4392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
4402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
4412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic int auok190xfb_check_var(struct fb_var_screeninfo *var,
4422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				   struct fb_info *info)
4432c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
44403fc1499f0fb28d4f70b83e8a05652129936486cHeiko Stübner	struct device *dev = info->device;
4454ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	struct auok190xfb_par *par = info->par;
4464ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	struct panel_info *panel = &panel_table[par->resolution];
44703fc1499f0fb28d4f70b83e8a05652129936486cHeiko Stübner	int size;
44803fc1499f0fb28d4f70b83e8a05652129936486cHeiko Stübner
4494ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	/*
45076de404b452305409182748568444994df765d9dHeiko Stübner	 * Color depth
45176de404b452305409182748568444994df765d9dHeiko Stübner	 */
45276de404b452305409182748568444994df765d9dHeiko Stübner
45376de404b452305409182748568444994df765d9dHeiko Stübner	if (var->bits_per_pixel == 8 && var->grayscale == 1) {
45476de404b452305409182748568444994df765d9dHeiko Stübner		/*
45576de404b452305409182748568444994df765d9dHeiko Stübner		 * For 8-bit grayscale, R, G, and B offset are equal.
45676de404b452305409182748568444994df765d9dHeiko Stübner		 */
45776de404b452305409182748568444994df765d9dHeiko Stübner		var->red.length = 8;
45876de404b452305409182748568444994df765d9dHeiko Stübner		var->red.offset = 0;
45976de404b452305409182748568444994df765d9dHeiko Stübner		var->red.msb_right = 0;
46076de404b452305409182748568444994df765d9dHeiko Stübner
46176de404b452305409182748568444994df765d9dHeiko Stübner		var->green.length = 8;
46276de404b452305409182748568444994df765d9dHeiko Stübner		var->green.offset = 0;
46376de404b452305409182748568444994df765d9dHeiko Stübner		var->green.msb_right = 0;
46476de404b452305409182748568444994df765d9dHeiko Stübner
46576de404b452305409182748568444994df765d9dHeiko Stübner		var->blue.length = 8;
46676de404b452305409182748568444994df765d9dHeiko Stübner		var->blue.offset = 0;
46776de404b452305409182748568444994df765d9dHeiko Stübner		var->blue.msb_right = 0;
46876de404b452305409182748568444994df765d9dHeiko Stübner
46976de404b452305409182748568444994df765d9dHeiko Stübner		var->transp.length = 0;
47076de404b452305409182748568444994df765d9dHeiko Stübner		var->transp.offset = 0;
47176de404b452305409182748568444994df765d9dHeiko Stübner		var->transp.msb_right = 0;
47246574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	} else if (var->bits_per_pixel == 16) {
47346574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->red.length = 5;
47446574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->red.offset = 11;
47546574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->red.msb_right = 0;
47646574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
47746574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->green.length = 6;
47846574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->green.offset = 5;
47946574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->green.msb_right = 0;
48046574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
48146574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->blue.length = 5;
48246574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->blue.offset = 0;
48346574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->blue.msb_right = 0;
48446574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
48546574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->transp.length = 0;
48646574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->transp.offset = 0;
48746574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner		var->transp.msb_right = 0;
48876de404b452305409182748568444994df765d9dHeiko Stübner	} else {
48976de404b452305409182748568444994df765d9dHeiko Stübner		dev_warn(dev, "unsupported color mode (bits: %d, grayscale: %d)\n",
49076de404b452305409182748568444994df765d9dHeiko Stübner			info->var.bits_per_pixel, info->var.grayscale);
49176de404b452305409182748568444994df765d9dHeiko Stübner		return -EINVAL;
49276de404b452305409182748568444994df765d9dHeiko Stübner	}
49376de404b452305409182748568444994df765d9dHeiko Stübner
49476de404b452305409182748568444994df765d9dHeiko Stübner	/*
4954ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	 * Dimensions
4964ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	 */
4974ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner
498fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	switch (var->rotate) {
499fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	case FB_ROTATE_UR:
500fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	case FB_ROTATE_UD:
5014ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner		var->xres = panel->w;
5024ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner		var->yres = panel->h;
503fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner		break;
504fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	case FB_ROTATE_CW:
505fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	case FB_ROTATE_CCW:
506fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner		var->xres = panel->h;
507fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner		var->yres = panel->w;
508fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner		break;
509fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	default:
510fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner		dev_dbg(dev, "Invalid rotation request\n");
511fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner		return -EINVAL;
5122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
5132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5144ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	var->xres_virtual = var->xres;
5154ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	var->yres_virtual = var->yres;
5164ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner
5172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/*
5182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 *  Memory limit
5192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 */
5202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
52103fc1499f0fb28d4f70b83e8a05652129936486cHeiko Stübner	size = var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8;
52203fc1499f0fb28d4f70b83e8a05652129936486cHeiko Stübner	if (size > info->fix.smem_len) {
52303fc1499f0fb28d4f70b83e8a05652129936486cHeiko Stübner		dev_err(dev, "Memory limit exceeded, requested %dK\n",
52403fc1499f0fb28d4f70b83e8a05652129936486cHeiko Stübner			size >> 10);
5252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return -ENOMEM;
5262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
5272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
5292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
5302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
53176de404b452305409182748568444994df765d9dHeiko Stübnerstatic int auok190xfb_set_fix(struct fb_info *info)
53276de404b452305409182748568444994df765d9dHeiko Stübner{
53376de404b452305409182748568444994df765d9dHeiko Stübner	struct fb_fix_screeninfo *fix = &info->fix;
53476de404b452305409182748568444994df765d9dHeiko Stübner	struct fb_var_screeninfo *var = &info->var;
53576de404b452305409182748568444994df765d9dHeiko Stübner
53676de404b452305409182748568444994df765d9dHeiko Stübner	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
53776de404b452305409182748568444994df765d9dHeiko Stübner
53876de404b452305409182748568444994df765d9dHeiko Stübner	fix->type = FB_TYPE_PACKED_PIXELS;
53976de404b452305409182748568444994df765d9dHeiko Stübner	fix->accel = FB_ACCEL_NONE;
54076de404b452305409182748568444994df765d9dHeiko Stübner	fix->visual = (var->grayscale) ? FB_VISUAL_STATIC_PSEUDOCOLOR
54176de404b452305409182748568444994df765d9dHeiko Stübner				       : FB_VISUAL_TRUECOLOR;
54276de404b452305409182748568444994df765d9dHeiko Stübner	fix->xpanstep = 0;
54376de404b452305409182748568444994df765d9dHeiko Stübner	fix->ypanstep = 0;
54476de404b452305409182748568444994df765d9dHeiko Stübner	fix->ywrapstep = 0;
54576de404b452305409182748568444994df765d9dHeiko Stübner
54676de404b452305409182748568444994df765d9dHeiko Stübner	return 0;
54776de404b452305409182748568444994df765d9dHeiko Stübner}
54876de404b452305409182748568444994df765d9dHeiko Stübner
54946574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübnerstatic int auok190xfb_set_par(struct fb_info *info)
55046574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner{
55146574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	struct auok190xfb_par *par = info->par;
55246574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
553fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	par->rotation = info->var.rotate;
55446574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	auok190xfb_set_fix(info);
55546574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
556fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	/* reinit the controller to honor the rotation */
557fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	par->init(par);
558fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner
559fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	/* wait for init to complete */
560fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	par->board->wait_for_rdy(par);
561fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner
56246574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	return 0;
56346574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner}
56446574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner
5652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic struct fb_ops auok190xfb_ops = {
5662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	.owner		= THIS_MODULE,
5672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	.fb_read	= fb_sys_read,
5682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	.fb_write	= auok190xfb_write,
5692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	.fb_fillrect	= auok190xfb_fillrect,
5702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	.fb_copyarea	= auok190xfb_copyarea,
5712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	.fb_imageblit	= auok190xfb_imageblit,
5722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	.fb_check_var	= auok190xfb_check_var,
57346574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	.fb_set_par     = auok190xfb_set_par,
5742c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner};
5752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
5772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * Controller-functions common to both K1900 and K1901
5782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
5792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic int auok190x_read_temperature(struct auok190xfb_par *par)
5812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
5822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct device *dev = par->info->device;
5832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	u16 data[4];
5842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int temp;
5852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_get_sync(dev);
5872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	mutex_lock(&(par->io_lock));
5892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
5912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	mutex_unlock(&(par->io_lock));
5932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5942c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_mark_last_busy(dev);
5952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_put_autosuspend(dev);
5962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
5972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* sanitize and split of half-degrees for now */
5982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1);
5992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* handle positive and negative temperatures */
6012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (temp >= 201)
6022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return (255 - temp + 1) * (-1);
6032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	else
6042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return temp;
6052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
6062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6072c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190x_identify(struct auok190xfb_par *par)
6082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
6092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct device *dev = par->info->device;
6102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	u16 data[4];
6112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_get_sync(dev);
6132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	mutex_lock(&(par->io_lock));
6152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
6172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	mutex_unlock(&(par->io_lock));
6192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK;
6212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]);
6232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]);
6242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->panel_model = AUOK190X_VERSION_MODEL(data[2]);
6252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->tcon_version = AUOK190X_VERSION_TCON(data[3]);
6272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->lut_version = AUOK190X_VERSION_LUT(data[3]);
6282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x",
6302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->panel_size_int, par->panel_size_float, par->panel_model,
6312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->epd_type, par->tcon_version, par->lut_version);
6322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_mark_last_busy(dev);
6342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_put_autosuspend(dev);
6352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
6362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
6382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * Sysfs functions
6392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
6402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic ssize_t update_mode_show(struct device *dev,
6422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				struct device_attribute *attr, char *buf)
6432c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
6442c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = dev_get_drvdata(dev);
6452c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
6462c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6472c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return sprintf(buf, "%d\n", par->update_mode);
6482c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
6492c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6502c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic ssize_t update_mode_store(struct device *dev,
6512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				 struct device_attribute *attr,
6522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				 const char *buf, size_t count)
6532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
6542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = dev_get_drvdata(dev);
6552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
6562c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int mode, ret;
6572c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6582c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = kstrtoint(buf, 10, &mode);
6592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret)
6602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return ret;
6612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_mode = mode;
6632c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* if we enter a better mode, do a full update */
6652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (par->last_mode > 1 && mode < par->last_mode)
6662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->update_all(par);
6672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return count;
6692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
6702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic ssize_t flash_show(struct device *dev, struct device_attribute *attr,
6722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			  char *buf)
6732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
6742c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = dev_get_drvdata(dev);
6752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
6762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return sprintf(buf, "%d\n", par->flash);
6782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
6792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic ssize_t flash_store(struct device *dev, struct device_attribute *attr,
6812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			   const char *buf, size_t count)
6822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
6832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = dev_get_drvdata(dev);
6842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
6852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int flash, ret;
6862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = kstrtoint(buf, 10, &flash);
6882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret)
6892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return ret;
6902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (flash > 0)
6922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->flash = 1;
6932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	else
6942c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->flash = 0;
6952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return count;
6972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
6982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
6992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic ssize_t temp_show(struct device *dev, struct device_attribute *attr,
7002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			 char *buf)
7012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
7022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = dev_get_drvdata(dev);
7032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
7042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int temp;
7052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	temp = auok190x_read_temperature(par);
7072c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return sprintf(buf, "%d\n", temp);
7082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
7092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic DEVICE_ATTR(update_mode, 0644, update_mode_show, update_mode_store);
7112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic DEVICE_ATTR(flash, 0644, flash_show, flash_store);
7122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic DEVICE_ATTR(temp, 0644, temp_show, NULL);
7132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic struct attribute *auok190x_attributes[] = {
7152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	&dev_attr_update_mode.attr,
7162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	&dev_attr_flash.attr,
7172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	&dev_attr_temp.attr,
7182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	NULL
7192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner};
7202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic const struct attribute_group auok190x_attr_group = {
7222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	.attrs		= auok190x_attributes,
7232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner};
7242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic int auok190x_power(struct auok190xfb_par *par, bool on)
7262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
7272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190x_board *board = par->board;
7282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int ret;
7292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (on) {
7312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* We should maintain POWER up for at least 80ms before set
7322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * RST_N and SLP_N to high (TCON spec 20100803_v35 p59)
7332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 */
7342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		ret = regulator_enable(par->regulator);
7352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		if (ret)
7362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			return ret;
7372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		msleep(200);
7392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		gpio_set_value(board->gpio_nrst, 1);
7402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		gpio_set_value(board->gpio_nsleep, 1);
7412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		msleep(200);
7422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	} else {
7432c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		regulator_disable(par->regulator);
7442c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		gpio_set_value(board->gpio_nrst, 0);
7452c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		gpio_set_value(board->gpio_nsleep, 0);
7462c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
7472c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7482c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
7492c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
7502c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
7522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * Recovery - powercycle the controller
7532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
7542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic void auok190x_recover(struct auok190xfb_par *par)
7562c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
7574e0ab85bb9097ecc422d4237f9eec155993f2902Heiko Stübner	struct device *dev = par->info->device;
7584e0ab85bb9097ecc422d4237f9eec155993f2902Heiko Stübner
7592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_power(par, 0);
7602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	msleep(100);
7612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_power(par, 1);
7622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7634e0ab85bb9097ecc422d4237f9eec155993f2902Heiko Stübner	/* after powercycling the device, it's always active */
7644e0ab85bb9097ecc422d4237f9eec155993f2902Heiko Stübner	pm_runtime_set_active(dev);
7654e0ab85bb9097ecc422d4237f9eec155993f2902Heiko Stübner	par->standby = 0;
7664e0ab85bb9097ecc422d4237f9eec155993f2902Heiko Stübner
7672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->init(par);
7682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* wait for init to complete */
7702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->wait_for_rdy(par);
7712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
7722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
7742c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * Power-management
7752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
7762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#ifdef CONFIG_PM
7782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic int auok190x_runtime_suspend(struct device *dev)
7792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
7802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct platform_device *pdev = to_platform_device(dev);
7812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = platform_get_drvdata(pdev);
7822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
7832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190x_board *board = par->board;
7842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	u16 standby_param;
7852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* take and keep the lock until we are resumed, as the controller
7872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 * will never reach the non-busy state when in standby mode
7882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 */
7892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	mutex_lock(&(par->io_lock));
7902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (par->standby) {
7922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n");
7932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		mutex_unlock(&(par->io_lock));
7942c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return 0;
7952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
7962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
7972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* according to runtime_pm.txt runtime_suspend only means, that the
7982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 * device will not process data and will not communicate with the CPU
7992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 * As we hold the lock, this stays true even without standby
8002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 */
8012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
8022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "runtime suspend without standby\n");
8032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto finish;
8042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	} else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) {
8052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* for some TCON versions STANDBY expects a parameter (0) but
8062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * it seems the real tcon version has to be determined yet.
8072c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 */
8082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "runtime suspend with additional empty param\n");
8092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		standby_param = 0;
8102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1,
8112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				      &standby_param);
8122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	} else {
8132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "runtime suspend without param\n");
8142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		auok190x_send_command(par, AUOK190X_CMD_STANDBY);
8152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
8162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	msleep(64);
8182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerfinish:
8202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->standby = 1;
8212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
8232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
8242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic int auok190x_runtime_resume(struct device *dev)
8262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
8272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct platform_device *pdev = to_platform_device(dev);
8282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = platform_get_drvdata(pdev);
8292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
8302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190x_board *board = par->board;
8312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (!par->standby) {
8332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n");
8342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return 0;
8352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
8362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
8382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "runtime resume without standby\n");
8392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	} else {
8402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* when in standby, controller is always busy
8412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * and only accepts the wakeup command
8422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 */
8432c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "runtime resume from standby\n");
8442c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP);
8452c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8462c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		msleep(160);
8472c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8482c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* wait for the controller to be ready and release the lock */
8492c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		board->wait_for_rdy(par);
8502c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
8512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->standby = 0;
8532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	mutex_unlock(&(par->io_lock));
8552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8562c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
8572c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
8582c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic int auok190x_suspend(struct device *dev)
8602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
8612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct platform_device *pdev = to_platform_device(dev);
8622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = platform_get_drvdata(pdev);
8632c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
8642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190x_board *board = par->board;
8652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int ret;
8662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	dev_dbg(dev, "suspend\n");
8682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
8692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* suspend via powering off the ic */
8702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "suspend with broken standby\n");
8712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		auok190x_power(par, 0);
8732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	} else {
8742c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "suspend using sleep\n");
8752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* the sleep state can only be entered from the standby state.
8772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * pm_runtime_get_noresume gets called before the suspend call.
8782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * So the devices usage count is >0 but it is not necessarily
8792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * active.
8802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 */
8812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		if (!pm_runtime_status_suspended(dev)) {
8822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			ret = auok190x_runtime_suspend(dev);
8832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			if (ret < 0) {
8842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				dev_err(dev, "auok190x_runtime_suspend failed with %d\n",
8852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner					ret);
8862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				return ret;
8872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			}
8882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			par->manual_standby = 1;
8892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		}
8902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		gpio_direction_output(board->gpio_nsleep, 0);
8922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
8932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8942c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	msleep(100);
8952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
8972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
8982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
8992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerstatic int auok190x_resume(struct device *dev)
9002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
9012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct platform_device *pdev = to_platform_device(dev);
9022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = platform_get_drvdata(pdev);
9032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
9042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190x_board *board = par->board;
9052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	dev_dbg(dev, "resume\n");
9072c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
9082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "resume with broken standby\n");
9092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		auok190x_power(par, 1);
9112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->init(par);
9132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	} else {
9142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_dbg(dev, "resume from sleep\n");
9152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* device should be in runtime suspend when we were suspended
9172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * and pm_runtime_put_sync gets called after this function.
9182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 * So there is no need to touch the standby mode here at all.
9192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 */
9202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		gpio_direction_output(board->gpio_nsleep, 1);
9212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		msleep(100);
9222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* an additional init call seems to be necessary after sleep */
9242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		auok190x_runtime_resume(dev);
9252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		par->init(par);
9262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		/* if we were runtime-suspended before, suspend again*/
9282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		if (!par->manual_standby)
9292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			auok190x_runtime_suspend(dev);
9302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		else
9312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			par->manual_standby = 0;
9322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
9332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
9352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
9362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner#endif
9372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnerconst struct dev_pm_ops auok190x_pm = {
9392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume,
9402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			   NULL)
9412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume)
9422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner};
9432c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_pm);
9442c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9452c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner/*
9462c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner * Common probe and remove code
9472c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner */
9482c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
94948c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanint auok190x_common_probe(struct platform_device *pdev,
95048c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartman			  struct auok190x_init_data *init)
9512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
9522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190x_board *board = init->board;
9532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par;
9542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info;
9552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct panel_info *panel;
9562c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	int videomemorysize, ret;
9572c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	unsigned char *videomemory;
9582c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* check board contents */
9602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (!board->init || !board->cleanup || !board->wait_for_rdy
9612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	    || !board->set_ctl || !board->set_hdb || !board->get_hdb
9622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	    || !board->setup_irq)
9632c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return -EINVAL;
9642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev);
9662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (!info)
9672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		return -ENOMEM;
9682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par = info->par;
9702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->info = info;
9712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board = board;
9722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->recover = auok190x_recover;
9732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_partial = init->update_partial;
9742c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_all = init->update_all;
9752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->need_refresh = init->need_refresh;
9762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->init = init->init;
9772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* init update modes */
9792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_cnt = 0;
9802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->update_mode = -1;
9812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->last_mode = -1;
9822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->flash = 0;
9832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->regulator = regulator_get(info->device, "vdd");
9852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (IS_ERR(par->regulator)) {
9862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		ret = PTR_ERR(par->regulator);
9872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "Failed to get regulator: %d\n", ret);
9882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_reg;
9892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
9902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = board->init(par);
9922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret) {
9932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "board init failed, %d\n", ret);
9942c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_board;
9952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
9962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
9972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep");
9982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret) {
9992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "could not request sleep gpio, %d\n",
10002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			ret);
10012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_gpio1;
10022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
10032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = gpio_direction_output(board->gpio_nsleep, 0);
10052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret) {
10062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "could not set sleep gpio, %d\n", ret);
10072c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_gpio2;
10082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
10092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = gpio_request(board->gpio_nrst, "AUOK190x reset");
10112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret) {
10122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "could not request reset gpio, %d\n",
10132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			ret);
10142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_gpio2;
10152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
10162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = gpio_direction_output(board->gpio_nrst, 0);
10182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret) {
10192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "could not set reset gpio, %d\n", ret);
10202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_gpio3;
10212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
10222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = auok190x_power(par, 1);
10242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret) {
10252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "could not power on the device, %d\n",
10262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner			ret);
10272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_gpio3;
10282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
10292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	mutex_init(&par->io_lock);
10312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	init_waitqueue_head(&par->waitq);
10332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = par->board->setup_irq(par->info);
10352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret) {
10362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "could not setup ready-irq, %d\n", ret);
10372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_irq;
10382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
10392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* wait for init to complete */
10412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->board->wait_for_rdy(par);
10422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10432c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/*
10442c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 * From here on the controller can talk to us
10452c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 */
10462c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10472c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* initialise fix, var, resolution and rotation */
10482c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10492c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	strlcpy(info->fix.id, init->id, 16);
10502c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->var.bits_per_pixel = 8;
10512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->var.grayscale = 1;
10522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	panel = &panel_table[board->resolution];
10542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->resolution = board->resolution;
1056fd3871aa5c0d108b89858263254b49d9bca2dc53Heiko Stübner	par->rotation = 0;
10572c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10582c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* videomemory handling */
10592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
106046574c72c701e45da1e0a2e944df885fcd2db668Heiko Stübner	videomemorysize = roundup((panel->w * panel->h) * 2, PAGE_SIZE);
10612c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	videomemory = vmalloc(videomemorysize);
10622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (!videomemory) {
10632c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		ret = -ENOMEM;
10642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_irq;
10652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
10662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	memset(videomemory, 0, videomemorysize);
10682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->screen_base = (char *)videomemory;
10692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->fix.smem_len = videomemorysize;
10702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
10722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->fbops = &auok190xfb_ops;
10732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10744ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	ret = auok190xfb_check_var(&info->var, info);
10754ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner	if (ret)
10764ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner		goto err_defio;
10774ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner
107876de404b452305409182748568444994df765d9dHeiko Stübner	auok190xfb_set_fix(info);
10794ea80d35b4e0cdb23c42d2664fb745f0afe397d1Heiko Stübner
10802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* deferred io init */
10812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->fbdefio = devm_kzalloc(info->device,
10832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				     sizeof(struct fb_deferred_io),
10842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner				     GFP_KERNEL);
10852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (!info->fbdefio) {
10862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "Failed to allocate memory\n");
10872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		ret = -ENOMEM;
10882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_defio;
10892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
10902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
1091a895d57da04a4a24cda996e1a72425ff7e7e6c22Masanari Iida	dev_dbg(info->device, "targeting %d frames per second\n", board->fps);
10922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->fbdefio->delay = HZ / board->fps;
10932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->fbdefio->first_io = auok190xfb_dpy_first_io,
10942c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io,
10952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	fb_deferred_io_init(info);
10962c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10972c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* color map */
10982c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
10992c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = fb_alloc_cmap(&info->cmap, 256, 0);
11002c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret < 0) {
11012c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		dev_err(info->device, "Failed to allocate colormap\n");
11022c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_cmap;
11032c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	}
11042c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11052c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* controller init */
11062c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11072c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->consecutive_threshold = 100;
11082c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->init(par);
11092c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_identify(par);
11102c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11112c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	platform_set_drvdata(pdev, info);
11122c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11132c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = register_framebuffer(info);
11142c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret < 0)
11152c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_regfb;
11162c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11172c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group);
11182c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	if (ret)
11192c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		goto err_sysfs;
11202c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11212c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n",
11222c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 info->node, info->var.xres, info->var.yres,
11232c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner		 videomemorysize >> 10);
11242c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11252c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	/* increase autosuspend_delay when we use alternative methods
11262c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 * for runtime_pm
11272c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	 */
11282c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN)
11292c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner					? 1000 : 200;
11302c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11312c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_set_active(info->device);
11322c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_enable(info->device);
11332c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay);
11342c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_use_autosuspend(info->device);
11352c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11362c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
11372c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11382c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_sysfs:
11392c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	unregister_framebuffer(info);
11402c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_regfb:
11412c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	fb_dealloc_cmap(&info->cmap);
11422c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_cmap:
11432c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	fb_deferred_io_cleanup(info);
11442c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_defio:
11452c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	vfree((void *)info->screen_base);
11462c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_irq:
11472c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_power(par, 0);
11482c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_gpio3:
11492c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	gpio_free(board->gpio_nrst);
11502c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_gpio2:
11512c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	gpio_free(board->gpio_nsleep);
11522c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_gpio1:
11532c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	board->cleanup(par);
11542c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_board:
11552c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	regulator_put(par->regulator);
11562c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübnererr_reg:
11572c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	framebuffer_release(info);
11582c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11592c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return ret;
11602c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
11612c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_common_probe);
11622c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
116348c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanint  auok190x_common_remove(struct platform_device *pdev)
11642c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner{
11652c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct fb_info *info = platform_get_drvdata(pdev);
11662c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190xfb_par *par = info->par;
11672c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	struct auok190x_board *board = par->board;
11682c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11692c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	pm_runtime_disable(info->device);
11702c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11712c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	sysfs_remove_group(&info->device->kobj, &auok190x_attr_group);
11722c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11732c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	unregister_framebuffer(info);
11742c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11752c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	fb_dealloc_cmap(&info->cmap);
11762c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11772c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	fb_deferred_io_cleanup(info);
11782c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11792c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	vfree((void *)info->screen_base);
11802c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11812c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	auok190x_power(par, 0);
11822c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11832c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	gpio_free(board->gpio_nrst);
11842c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	gpio_free(board->gpio_nsleep);
11852c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11862c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	board->cleanup(par);
11872c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11882c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	regulator_put(par->regulator);
11892c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11902c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	framebuffer_release(info);
11912c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11922c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner	return 0;
11932c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner}
11942c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerEXPORT_SYMBOL_GPL(auok190x_common_remove);
11952c8304d3125b9c75797a35037945df63869bfdf6Heiko Stübner
11962c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerMODULE_DESCRIPTION("Common code for AUO-K190X controllers");
11972c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerMODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
11982c8304d3125b9c75797a35037945df63869bfdf6Heiko StübnerMODULE_LICENSE("GPL");
1199