linux/drivers/video/msm/mddi_client_nt35399.c
<<
>>
Prefs
   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