1/* drivers/video/msm_fb/mddi_client_nt35399.c 2 * 3 * Support for Novatek NT35399 MDDI client of Sapphire 4 * 5 * Copyright (C) 2008 HTC Incorporated 6 * Author: Solomon Chiu (solomon_chiu@htc.com) 7 * 8 * This software is licensed under the terms of the GNU General Public 9 * License version 2, as published by the Free Software Foundation, and 10 * may be copied, distributed, and modified under those terms. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18#include <linux/module.h> 19#include <linux/kernel.h> 20#include <linux/platform_device.h> 21#include <linux/interrupt.h> 22#include <linux/sched.h> 23#include <linux/gpio.h> 24#include <linux/slab.h> 25#include <linux/platform_data/video-msm_fb.h> 26 27static DECLARE_WAIT_QUEUE_HEAD(nt35399_vsync_wait); 28 29struct panel_info { 30 struct msm_mddi_client_data *client_data; 31 struct platform_device pdev; 32 struct msm_panel_data panel_data; 33 struct msmfb_callback *fb_callback; 34 struct work_struct panel_work; 35 struct workqueue_struct *fb_wq; 36 int nt35399_got_int; 37}; 38 39static void 40nt35399_request_vsync(struct msm_panel_data *panel_data, 41 struct msmfb_callback *callback) 42{ 43 struct panel_info *panel = container_of(panel_data, struct panel_info, 44 panel_data); 45 struct msm_mddi_client_data *client_data = panel->client_data; 46 47 panel->fb_callback = callback; 48 if (panel->nt35399_got_int) { 49 panel->nt35399_got_int = 0; 50 client_data->activate_link(client_data); /* clears interrupt */ 51 } 52} 53 54static void nt35399_wait_vsync(struct msm_panel_data *panel_data) 55{ 56 struct panel_info *panel = container_of(panel_data, struct panel_info, 57 panel_data); 58 struct msm_mddi_client_data *client_data = panel->client_data; 59 60 if (panel->nt35399_got_int) { 61 panel->nt35399_got_int = 0; 62 client_data->activate_link(client_data); /* clears interrupt */ 63 } 64 65 if (wait_event_timeout(nt35399_vsync_wait, panel->nt35399_got_int, 66 HZ/2) == 0) 67 printk(KERN_ERR "timeout waiting for VSYNC\n"); 68 69 panel->nt35399_got_int = 0; 70 /* interrupt clears when screen dma starts */ 71} 72 73static int nt35399_suspend(struct msm_panel_data *panel_data) 74{ 75 struct panel_info *panel = container_of(panel_data, struct panel_info, 76 panel_data); 77 struct msm_mddi_client_data *client_data = panel->client_data; 78 79 struct msm_mddi_bridge_platform_data *bridge_data = 80 client_data->private_client_data; 81 int ret; 82 83 ret = bridge_data->uninit(bridge_data, client_data); 84 if (ret) { 85 printk(KERN_INFO "mddi nt35399 client: non zero return from " 86 "uninit\n"); 87 return ret; 88 } 89 client_data->suspend(client_data); 90 return 0; 91} 92 93static int nt35399_resume(struct msm_panel_data *panel_data) 94{ 95 struct panel_info *panel = container_of(panel_data, struct panel_info, 96 panel_data); 97 struct msm_mddi_client_data *client_data = panel->client_data; 98 99 struct msm_mddi_bridge_platform_data *bridge_data = 100 client_data->private_client_data; 101 int ret; 102 103 client_data->resume(client_data); 104 ret = bridge_data->init(bridge_data, client_data); 105 if (ret) 106 return ret; 107 return 0; 108} 109 110static int nt35399_blank(struct msm_panel_data *panel_data) 111{ 112 struct panel_info *panel = container_of(panel_data, struct panel_info, 113 panel_data); 114 struct msm_mddi_client_data *client_data = panel->client_data; 115 struct msm_mddi_bridge_platform_data *bridge_data = 116 client_data->private_client_data; 117 118 return bridge_data->blank(bridge_data, client_data); 119} 120 121static int nt35399_unblank(struct msm_panel_data *panel_data) 122{ 123 struct panel_info *panel = container_of(panel_data, struct panel_info, 124 panel_data); 125 struct msm_mddi_client_data *client_data = panel->client_data; 126 struct msm_mddi_bridge_platform_data *bridge_data = 127 client_data->private_client_data; 128 129 return bridge_data->unblank(bridge_data, client_data); 130} 131 132irqreturn_t nt35399_vsync_interrupt(int irq, void *data) 133{ 134 struct panel_info *panel = data; 135 136 panel->nt35399_got_int = 1; 137 138 if (panel->fb_callback) { 139 panel->fb_callback->func(panel->fb_callback); 140 panel->fb_callback = NULL; 141 } 142 143 wake_up(&nt35399_vsync_wait); 144 145 return IRQ_HANDLED; 146} 147 148static int setup_vsync(struct panel_info *panel, int init) 149{ 150 int ret; 151 int gpio = 97; 152 unsigned int irq; 153 154 if (!init) { 155 ret = 0; 156 goto uninit; 157 } 158 ret = gpio_request_one(gpio, GPIOF_IN, "vsync"); 159 if (ret) 160 goto err_request_gpio_failed; 161 162 ret = irq = gpio_to_irq(gpio); 163 if (ret < 0) 164 goto err_get_irq_num_failed; 165 166 ret = request_irq(irq, nt35399_vsync_interrupt, IRQF_TRIGGER_RISING, 167 "vsync", panel); 168 if (ret) 169 goto err_request_irq_failed; 170 171 printk(KERN_INFO "vsync on gpio %d now %d\n", 172 gpio, gpio_get_value(gpio)); 173 return 0; 174 175uninit: 176 free_irq(gpio_to_irq(gpio), panel->client_data); 177err_request_irq_failed: 178err_get_irq_num_failed: 179 gpio_free(gpio); 180err_request_gpio_failed: 181 return ret; 182} 183 184static int mddi_nt35399_probe(struct platform_device *pdev) 185{ 186 struct msm_mddi_client_data *client_data = pdev->dev.platform_data; 187 struct msm_mddi_bridge_platform_data *bridge_data = 188 client_data->private_client_data; 189 190 int ret; 191 192 struct panel_info *panel = devm_kzalloc(&pdev->dev, 193 sizeof(struct panel_info), 194 GFP_KERNEL); 195 196 printk(KERN_DEBUG "%s: enter.\n", __func__); 197 198 if (!panel) 199 return -ENOMEM; 200 platform_set_drvdata(pdev, panel); 201 202 ret = setup_vsync(panel, 1); 203 if (ret) { 204 dev_err(&pdev->dev, "mddi_nt35399_setup_vsync failed\n"); 205 return ret; 206 } 207 208 panel->client_data = client_data; 209 panel->panel_data.suspend = nt35399_suspend; 210 panel->panel_data.resume = nt35399_resume; 211 panel->panel_data.wait_vsync = nt35399_wait_vsync; 212 panel->panel_data.request_vsync = nt35399_request_vsync; 213 panel->panel_data.blank = nt35399_blank; 214 panel->panel_data.unblank = nt35399_unblank; 215 panel->panel_data.fb_data = &bridge_data->fb_data; 216 panel->panel_data.caps = 0; 217 218 panel->pdev.name = "msm_panel"; 219 panel->pdev.id = pdev->id; 220 panel->pdev.resource = client_data->fb_resource; 221 panel->pdev.num_resources = 1; 222 panel->pdev.dev.platform_data = &panel->panel_data; 223 224 if (bridge_data->init) 225 bridge_data->init(bridge_data, client_data); 226 227 platform_device_register(&panel->pdev); 228 229 return 0; 230} 231 232static int mddi_nt35399_remove(struct platform_device *pdev) 233{ 234 struct panel_info *panel = platform_get_drvdata(pdev); 235 236 setup_vsync(panel, 0); 237 return 0; 238} 239 240static struct platform_driver mddi_client_0bda_8a47 = { 241 .probe = mddi_nt35399_probe, 242 .remove = mddi_nt35399_remove, 243 .driver = { .name = "mddi_c_0bda_8a47" }, 244}; 245 246static int __init mddi_client_nt35399_init(void) 247{ 248 return platform_driver_register(&mddi_client_0bda_8a47); 249} 250 251module_init(mddi_client_nt35399_init); 252 253