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