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 <mach/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(gpio, "vsync");
 159        if (ret)
 160                goto err_request_gpio_failed;
 161
 162        ret = gpio_direction_input(gpio);
 163        if (ret)
 164                goto err_gpio_direction_input_failed;
 165
 166        ret = irq = gpio_to_irq(gpio);
 167        if (ret < 0)
 168                goto err_get_irq_num_failed;
 169
 170        ret = request_irq(irq, nt35399_vsync_interrupt, IRQF_TRIGGER_RISING,
 171                          "vsync", panel);
 172        if (ret)
 173                goto err_request_irq_failed;
 174
 175        printk(KERN_INFO "vsync on gpio %d now %d\n",
 176               gpio, gpio_get_value(gpio));
 177        return 0;
 178
 179uninit:
 180        free_irq(gpio_to_irq(gpio), panel->client_data);
 181err_request_irq_failed:
 182err_get_irq_num_failed:
 183err_gpio_direction_input_failed:
 184        gpio_free(gpio);
 185err_request_gpio_failed:
 186        return ret;
 187}
 188
 189static int mddi_nt35399_probe(struct platform_device *pdev)
 190{
 191        struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
 192        struct msm_mddi_bridge_platform_data *bridge_data =
 193                client_data->private_client_data;
 194
 195        int ret;
 196
 197        struct panel_info *panel = kzalloc(sizeof(struct panel_info),
 198                                           GFP_KERNEL);
 199
 200        printk(KERN_DEBUG "%s: enter.\n", __func__);
 201
 202        if (!panel)
 203                return -ENOMEM;
 204        platform_set_drvdata(pdev, panel);
 205
 206        ret = setup_vsync(panel, 1);
 207        if (ret) {
 208                dev_err(&pdev->dev, "mddi_nt35399_setup_vsync failed\n");
 209                return ret;
 210        }
 211
 212        panel->client_data = client_data;
 213        panel->panel_data.suspend = nt35399_suspend;
 214        panel->panel_data.resume = nt35399_resume;
 215        panel->panel_data.wait_vsync = nt35399_wait_vsync;
 216        panel->panel_data.request_vsync = nt35399_request_vsync;
 217        panel->panel_data.blank = nt35399_blank;
 218        panel->panel_data.unblank = nt35399_unblank;
 219        panel->panel_data.fb_data = &bridge_data->fb_data;
 220        panel->panel_data.caps = 0;
 221
 222        panel->pdev.name = "msm_panel";
 223        panel->pdev.id = pdev->id;
 224        panel->pdev.resource = client_data->fb_resource;
 225        panel->pdev.num_resources = 1;
 226        panel->pdev.dev.platform_data = &panel->panel_data;
 227
 228        if (bridge_data->init)
 229                bridge_data->init(bridge_data, client_data);
 230
 231        platform_device_register(&panel->pdev);
 232
 233        return 0;
 234}
 235
 236static int mddi_nt35399_remove(struct platform_device *pdev)
 237{
 238        struct panel_info *panel = platform_get_drvdata(pdev);
 239
 240        setup_vsync(panel, 0);
 241        kfree(panel);
 242        return 0;
 243}
 244
 245static struct platform_driver mddi_client_0bda_8a47 = {
 246        .probe = mddi_nt35399_probe,
 247        .remove = mddi_nt35399_remove,
 248        .driver = { .name = "mddi_c_0bda_8a47" },
 249};
 250
 251static int __init mddi_client_nt35399_init(void)
 252{
 253        return platform_driver_register(&mddi_client_0bda_8a47);
 254}
 255
 256module_init(mddi_client_nt35399_init);
 257
 258
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.