linux/drivers/staging/msm/tvenc.c
<<
>>
Prefs
   1/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
   2 *
   3 * This program is free software; you can redistribute it and/or modify
   4 * it under the terms of the GNU General Public License version 2 and
   5 * only version 2 as published by the Free Software Foundation.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 *
  12 * You should have received a copy of the GNU General Public License
  13 * along with this program; if not, write to the Free Software
  14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15 * 02110-1301, USA.
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/kernel.h>
  20#include <linux/sched.h>
  21#include <linux/time.h>
  22#include <linux/init.h>
  23#include <linux/interrupt.h>
  24#include <linux/spinlock.h>
  25#include <linux/delay.h>
  26#include <mach/hardware.h>
  27#include <linux/io.h>
  28
  29#include <asm/system.h>
  30#include <asm/mach-types.h>
  31#include <linux/semaphore.h>
  32#include <linux/uaccess.h>
  33#include <linux/clk.h>
  34#include <linux/platform_device.h>
  35#include <linux/pm_qos_params.h>
  36
  37#define TVENC_C
  38#include "tvenc.h"
  39#include "msm_fb.h"
  40
  41static int tvenc_probe(struct platform_device *pdev);
  42static int tvenc_remove(struct platform_device *pdev);
  43
  44static int tvenc_off(struct platform_device *pdev);
  45static int tvenc_on(struct platform_device *pdev);
  46
  47static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
  48static int pdev_list_cnt;
  49
  50static struct clk *tvenc_clk;
  51static struct clk *tvdac_clk;
  52
  53static struct platform_driver tvenc_driver = {
  54        .probe = tvenc_probe,
  55        .remove = tvenc_remove,
  56        .suspend = NULL,
  57//      .suspend_late = NULL,
  58//      .resume_early = NULL,
  59        .resume = NULL,
  60        .shutdown = NULL,
  61        .driver = {
  62                   .name = "tvenc",
  63                   },
  64};
  65
  66static struct tvenc_platform_data *tvenc_pdata;
  67
  68static int tvenc_off(struct platform_device *pdev)
  69{
  70        int ret = 0;
  71
  72        ret = panel_next_off(pdev);
  73
  74        clk_disable(tvenc_clk);
  75        clk_disable(tvdac_clk);
  76
  77        if (tvenc_pdata && tvenc_pdata->pm_vid_en)
  78                ret = tvenc_pdata->pm_vid_en(0);
  79
  80        //pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
  81        //                              PM_QOS_DEFAULT_VALUE);
  82
  83        if (ret)
  84                printk(KERN_ERR "%s: pm_vid_en(off) failed! %d\n",
  85                __func__, ret);
  86
  87        return ret;
  88}
  89
  90static int tvenc_on(struct platform_device *pdev)
  91{
  92        int ret = 0;
  93
  94//      pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
  95//                              128000);
  96        if (tvenc_pdata && tvenc_pdata->pm_vid_en)
  97                ret = tvenc_pdata->pm_vid_en(1);
  98
  99        if (ret) {
 100                printk(KERN_ERR "%s: pm_vid_en(on) failed! %d\n",
 101                __func__, ret);
 102                return ret;
 103        }
 104
 105        clk_enable(tvenc_clk);
 106        clk_enable(tvdac_clk);
 107
 108        ret = panel_next_on(pdev);
 109
 110        return ret;
 111}
 112
 113void tvenc_gen_test_pattern(struct msm_fb_data_type *mfd)
 114{
 115        uint32 reg = 0, i;
 116
 117        reg = readl(MSM_TV_ENC_CTL);
 118        reg |= TVENC_CTL_TEST_PATT_EN;
 119
 120        for (i = 0; i < 3; i++) {
 121                TV_OUT(TV_ENC_CTL, 0);  /* disable TV encoder */
 122
 123                switch (i) {
 124                        /*
 125                         * TV Encoder - Color Bar Test Pattern
 126                         */
 127                case 0:
 128                        reg |= TVENC_CTL_TPG_CLRBAR;
 129                        break;
 130                        /*
 131                         * TV Encoder - Red Frame Test Pattern
 132                         */
 133                case 1:
 134                        reg |= TVENC_CTL_TPG_REDCLR;
 135                        break;
 136                        /*
 137                         * TV Encoder - Modulated Ramp Test Pattern
 138                         */
 139                default:
 140                        reg |= TVENC_CTL_TPG_MODRAMP;
 141                        break;
 142                }
 143
 144                TV_OUT(TV_ENC_CTL, reg);
 145                mdelay(5000);
 146
 147                switch (i) {
 148                        /*
 149                         * TV Encoder - Color Bar Test Pattern
 150                         */
 151                case 0:
 152                        reg &= ~TVENC_CTL_TPG_CLRBAR;
 153                        break;
 154                        /*
 155                         * TV Encoder - Red Frame Test Pattern
 156                         */
 157                case 1:
 158                        reg &= ~TVENC_CTL_TPG_REDCLR;
 159                        break;
 160                        /*
 161                         * TV Encoder - Modulated Ramp Test Pattern
 162                         */
 163                default:
 164                        reg &= ~TVENC_CTL_TPG_MODRAMP;
 165                        break;
 166                }
 167        }
 168}
 169
 170static int tvenc_resource_initialized;
 171
 172static int tvenc_probe(struct platform_device *pdev)
 173{
 174        struct msm_fb_data_type *mfd;
 175        struct platform_device *mdp_dev = NULL;
 176        struct msm_fb_panel_data *pdata = NULL;
 177        int rc;
 178
 179        if (pdev->id == 0) {
 180                tvenc_base = ioremap(pdev->resource[0].start,
 181                                        pdev->resource[0].end -
 182                                        pdev->resource[0].start + 1);
 183                if (!tvenc_base) {
 184                        printk(KERN_ERR
 185                                "tvenc_base ioremap failed!\n");
 186                        return -ENOMEM;
 187                }
 188                tvenc_pdata = pdev->dev.platform_data;
 189                tvenc_resource_initialized = 1;
 190                return 0;
 191        }
 192
 193        if (!tvenc_resource_initialized)
 194                return -EPERM;
 195
 196        mfd = platform_get_drvdata(pdev);
 197
 198        if (!mfd)
 199                return -ENODEV;
 200
 201        if (mfd->key != MFD_KEY)
 202                return -EINVAL;
 203
 204        if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
 205                return -ENOMEM;
 206
 207        if (tvenc_base == NULL)
 208                return -ENOMEM;
 209
 210        mdp_dev = platform_device_alloc("mdp", pdev->id);
 211        if (!mdp_dev)
 212                return -ENOMEM;
 213
 214        /*
 215         * link to the latest pdev
 216         */
 217        mfd->pdev = mdp_dev;
 218        mfd->dest = DISPLAY_TV;
 219
 220        /*
 221         * alloc panel device data
 222         */
 223        if (platform_device_add_data
 224            (mdp_dev, pdev->dev.platform_data,
 225             sizeof(struct msm_fb_panel_data))) {
 226                printk(KERN_ERR "tvenc_probe: platform_device_add_data failed!\n");
 227                platform_device_put(mdp_dev);
 228                return -ENOMEM;
 229        }
 230        /*
 231         * data chain
 232         */
 233        pdata = mdp_dev->dev.platform_data;
 234        pdata->on = tvenc_on;
 235        pdata->off = tvenc_off;
 236        pdata->next = pdev;
 237
 238        /*
 239         * get/set panel specific fb info
 240         */
 241        mfd->panel_info = pdata->panel_info;
 242        mfd->fb_imgType = MDP_YCRYCB_H2V1;
 243
 244        /*
 245         * set driver data
 246         */
 247        platform_set_drvdata(mdp_dev, mfd);
 248
 249        /*
 250         * register in mdp driver
 251         */
 252        rc = platform_device_add(mdp_dev);
 253        if (rc)
 254                goto tvenc_probe_err;
 255
 256        pdev_list[pdev_list_cnt++] = pdev;
 257        return 0;
 258
 259tvenc_probe_err:
 260        platform_device_put(mdp_dev);
 261        return rc;
 262}
 263
 264static int tvenc_remove(struct platform_device *pdev)
 265{
 266//      pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc");
 267        return 0;
 268}
 269
 270static int tvenc_register_driver(void)
 271{
 272        return platform_driver_register(&tvenc_driver);
 273}
 274
 275static int __init tvenc_driver_init(void)
 276{
 277        tvenc_clk = clk_get(NULL, "tv_enc_clk");
 278        tvdac_clk = clk_get(NULL, "tv_dac_clk");
 279
 280        if (IS_ERR(tvenc_clk)) {
 281                printk(KERN_ERR "error: can't get tvenc_clk!\n");
 282                return PTR_ERR(tvenc_clk);
 283        }
 284
 285        if (IS_ERR(tvdac_clk)) {
 286                printk(KERN_ERR "error: can't get tvdac_clk!\n");
 287                clk_put(tvenc_clk);
 288                return PTR_ERR(tvdac_clk);
 289        }
 290
 291//      pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
 292//                              PM_QOS_DEFAULT_VALUE);
 293        return tvenc_register_driver();
 294}
 295
 296module_init(tvenc_driver_init);
 297