linux/drivers/media/platform/s5p-tv/sdo_drv.c
<<
>>
Prefs
   1/*
   2 * Samsung Standard Definition Output (SDO) driver
   3 *
   4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
   5 *
   6 * Tomasz Stanislawski, <t.stanislaws@samsung.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published
  10 * by the Free Software Foundiation. either version 2 of the License,
  11 * or (at your option) any later version
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/delay.h>
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/interrupt.h>
  19#include <linux/io.h>
  20#include <linux/irq.h>
  21#include <linux/platform_device.h>
  22#include <linux/pm_runtime.h>
  23#include <linux/regulator/consumer.h>
  24#include <linux/slab.h>
  25
  26#include <media/v4l2-subdev.h>
  27
  28#include "regs-sdo.h"
  29
  30MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
  31MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
  32MODULE_LICENSE("GPL");
  33
  34#define SDO_DEFAULT_STD V4L2_STD_PAL
  35
  36struct sdo_format {
  37        v4l2_std_id id;
  38        /* all modes are 720 pixels wide */
  39        unsigned int height;
  40        unsigned int cookie;
  41};
  42
  43struct sdo_device {
  44        /** pointer to device parent */
  45        struct device *dev;
  46        /** base address of SDO registers */
  47        void __iomem *regs;
  48        /** SDO interrupt */
  49        unsigned int irq;
  50        /** DAC source clock */
  51        struct clk *sclk_dac;
  52        /** DAC clock */
  53        struct clk *dac;
  54        /** DAC physical interface */
  55        struct clk *dacphy;
  56        /** clock for control of VPLL */
  57        struct clk *fout_vpll;
  58        /** regulator for SDO IP power */
  59        struct regulator *vdac;
  60        /** regulator for SDO plug detection */
  61        struct regulator *vdet;
  62        /** subdev used as device interface */
  63        struct v4l2_subdev sd;
  64        /** current format */
  65        const struct sdo_format *fmt;
  66};
  67
  68static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
  69{
  70        return container_of(sd, struct sdo_device, sd);
  71}
  72
  73static inline
  74void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
  75{
  76        u32 old = readl(sdev->regs + reg_id);
  77        value = (value & mask) | (old & ~mask);
  78        writel(value, sdev->regs + reg_id);
  79}
  80
  81static inline
  82void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
  83{
  84        writel(value, sdev->regs + reg_id);
  85}
  86
  87static inline
  88u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
  89{
  90        return readl(sdev->regs + reg_id);
  91}
  92
  93static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
  94{
  95        struct sdo_device *sdev = dev_data;
  96
  97        /* clear interrupt */
  98        sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
  99        return IRQ_HANDLED;
 100}
 101
 102static void sdo_reg_debug(struct sdo_device *sdev)
 103{
 104#define DBGREG(reg_id) \
 105        dev_info(sdev->dev, #reg_id " = %08x\n", \
 106                sdo_read(sdev, reg_id))
 107
 108        DBGREG(SDO_CLKCON);
 109        DBGREG(SDO_CONFIG);
 110        DBGREG(SDO_VBI);
 111        DBGREG(SDO_DAC);
 112        DBGREG(SDO_IRQ);
 113        DBGREG(SDO_IRQMASK);
 114        DBGREG(SDO_VERSION);
 115}
 116
 117static const struct sdo_format sdo_format[] = {
 118        { V4L2_STD_PAL_N,       .height = 576, .cookie = SDO_PAL_N },
 119        { V4L2_STD_PAL_Nc,      .height = 576, .cookie = SDO_PAL_NC },
 120        { V4L2_STD_PAL_M,       .height = 480, .cookie = SDO_PAL_M },
 121        { V4L2_STD_PAL_60,      .height = 480, .cookie = SDO_PAL_60 },
 122        { V4L2_STD_NTSC_443,    .height = 480, .cookie = SDO_NTSC_443 },
 123        { V4L2_STD_PAL,         .height = 576, .cookie = SDO_PAL_BGHID },
 124        { V4L2_STD_NTSC_M,      .height = 480, .cookie = SDO_NTSC_M },
 125};
 126
 127static const struct sdo_format *sdo_find_format(v4l2_std_id id)
 128{
 129        int i;
 130        for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
 131                if (sdo_format[i].id & id)
 132                        return &sdo_format[i];
 133        return NULL;
 134}
 135
 136static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
 137{
 138        *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
 139                V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
 140                V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
 141        return 0;
 142}
 143
 144static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
 145{
 146        struct sdo_device *sdev = sd_to_sdev(sd);
 147        const struct sdo_format *fmt;
 148        fmt = sdo_find_format(std);
 149        if (fmt == NULL)
 150                return -EINVAL;
 151        sdev->fmt = fmt;
 152        return 0;
 153}
 154
 155static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
 156{
 157        *std = sd_to_sdev(sd)->fmt->id;
 158        return 0;
 159}
 160
 161static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
 162        struct v4l2_mbus_framefmt *fmt)
 163{
 164        struct sdo_device *sdev = sd_to_sdev(sd);
 165
 166        if (!sdev->fmt)
 167                return -ENXIO;
 168        /* all modes are 720 pixels wide */
 169        fmt->width = 720;
 170        fmt->height = sdev->fmt->height;
 171        fmt->code = V4L2_MBUS_FMT_FIXED;
 172        fmt->field = V4L2_FIELD_INTERLACED;
 173        fmt->colorspace = V4L2_COLORSPACE_JPEG;
 174        return 0;
 175}
 176
 177static int sdo_s_power(struct v4l2_subdev *sd, int on)
 178{
 179        struct sdo_device *sdev = sd_to_sdev(sd);
 180        struct device *dev = sdev->dev;
 181        int ret;
 182
 183        dev_info(dev, "sdo_s_power(%d)\n", on);
 184
 185        if (on)
 186                ret = pm_runtime_get_sync(dev);
 187        else
 188                ret = pm_runtime_put_sync(dev);
 189
 190        /* only values < 0 indicate errors */
 191        return IS_ERR_VALUE(ret) ? ret : 0;
 192}
 193
 194static int sdo_streamon(struct sdo_device *sdev)
 195{
 196        /* set proper clock for Timing Generator */
 197        clk_set_rate(sdev->fout_vpll, 54000000);
 198        dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
 199        clk_get_rate(sdev->fout_vpll));
 200        /* enable clock in SDO */
 201        sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
 202        clk_enable(sdev->dacphy);
 203        /* enable DAC */
 204        sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
 205        sdo_reg_debug(sdev);
 206        return 0;
 207}
 208
 209static int sdo_streamoff(struct sdo_device *sdev)
 210{
 211        int tries;
 212
 213        sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
 214        clk_disable(sdev->dacphy);
 215        sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
 216        for (tries = 100; tries; --tries) {
 217                if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
 218                        break;
 219                mdelay(1);
 220        }
 221        if (tries == 0)
 222                dev_err(sdev->dev, "failed to stop streaming\n");
 223        return tries ? 0 : -EIO;
 224}
 225
 226static int sdo_s_stream(struct v4l2_subdev *sd, int on)
 227{
 228        struct sdo_device *sdev = sd_to_sdev(sd);
 229        return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
 230}
 231
 232static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
 233        .s_power = sdo_s_power,
 234};
 235
 236static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
 237        .s_std_output = sdo_s_std_output,
 238        .g_std_output = sdo_g_std_output,
 239        .g_tvnorms_output = sdo_g_tvnorms_output,
 240        .g_mbus_fmt = sdo_g_mbus_fmt,
 241        .s_stream = sdo_s_stream,
 242};
 243
 244static const struct v4l2_subdev_ops sdo_sd_ops = {
 245        .core = &sdo_sd_core_ops,
 246        .video = &sdo_sd_video_ops,
 247};
 248
 249static int sdo_runtime_suspend(struct device *dev)
 250{
 251        struct v4l2_subdev *sd = dev_get_drvdata(dev);
 252        struct sdo_device *sdev = sd_to_sdev(sd);
 253
 254        dev_info(dev, "suspend\n");
 255        regulator_disable(sdev->vdet);
 256        regulator_disable(sdev->vdac);
 257        clk_disable(sdev->sclk_dac);
 258        return 0;
 259}
 260
 261static int sdo_runtime_resume(struct device *dev)
 262{
 263        struct v4l2_subdev *sd = dev_get_drvdata(dev);
 264        struct sdo_device *sdev = sd_to_sdev(sd);
 265
 266        dev_info(dev, "resume\n");
 267        clk_enable(sdev->sclk_dac);
 268        regulator_enable(sdev->vdac);
 269        regulator_enable(sdev->vdet);
 270
 271        /* software reset */
 272        sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
 273        mdelay(10);
 274        sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
 275
 276        /* setting TV mode */
 277        sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
 278        /* XXX: forcing interlaced mode using undocumented bit */
 279        sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
 280        /* turn all VBI off */
 281        sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
 282                SDO_CVBS_CLOSED_CAPTION_MASK);
 283        /* turn all post processing off */
 284        sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
 285                SDO_COMPENSATION_CVBS_COMP_OFF);
 286        sdo_reg_debug(sdev);
 287        return 0;
 288}
 289
 290static const struct dev_pm_ops sdo_pm_ops = {
 291        .runtime_suspend = sdo_runtime_suspend,
 292        .runtime_resume  = sdo_runtime_resume,
 293};
 294
 295static int sdo_probe(struct platform_device *pdev)
 296{
 297        struct device *dev = &pdev->dev;
 298        struct sdo_device *sdev;
 299        struct resource *res;
 300        int ret = 0;
 301        struct clk *sclk_vpll;
 302
 303        dev_info(dev, "probe start\n");
 304        sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
 305        if (!sdev) {
 306                dev_err(dev, "not enough memory.\n");
 307                ret = -ENOMEM;
 308                goto fail;
 309        }
 310        sdev->dev = dev;
 311
 312        /* mapping registers */
 313        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 314        if (res == NULL) {
 315                dev_err(dev, "get memory resource failed.\n");
 316                ret = -ENXIO;
 317                goto fail;
 318        }
 319
 320        sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
 321        if (sdev->regs == NULL) {
 322                dev_err(dev, "register mapping failed.\n");
 323                ret = -ENXIO;
 324                goto fail;
 325        }
 326
 327        /* acquiring interrupt */
 328        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 329        if (res == NULL) {
 330                dev_err(dev, "get interrupt resource failed.\n");
 331                ret = -ENXIO;
 332                goto fail;
 333        }
 334        ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0,
 335                               "s5p-sdo", sdev);
 336        if (ret) {
 337                dev_err(dev, "request interrupt failed.\n");
 338                goto fail;
 339        }
 340        sdev->irq = res->start;
 341
 342        /* acquire clocks */
 343        sdev->sclk_dac = clk_get(dev, "sclk_dac");
 344        if (IS_ERR(sdev->sclk_dac)) {
 345                dev_err(dev, "failed to get clock 'sclk_dac'\n");
 346                ret = PTR_ERR(sdev->sclk_dac);
 347                goto fail;
 348        }
 349        sdev->dac = clk_get(dev, "dac");
 350        if (IS_ERR(sdev->dac)) {
 351                dev_err(dev, "failed to get clock 'dac'\n");
 352                ret = PTR_ERR(sdev->dac);
 353                goto fail_sclk_dac;
 354        }
 355        sdev->dacphy = clk_get(dev, "dacphy");
 356        if (IS_ERR(sdev->dacphy)) {
 357                dev_err(dev, "failed to get clock 'dacphy'\n");
 358                ret = PTR_ERR(sdev->dacphy);
 359                goto fail_dac;
 360        }
 361        sclk_vpll = clk_get(dev, "sclk_vpll");
 362        if (IS_ERR(sclk_vpll)) {
 363                dev_err(dev, "failed to get clock 'sclk_vpll'\n");
 364                ret = PTR_ERR(sclk_vpll);
 365                goto fail_dacphy;
 366        }
 367        clk_set_parent(sdev->sclk_dac, sclk_vpll);
 368        clk_put(sclk_vpll);
 369        sdev->fout_vpll = clk_get(dev, "fout_vpll");
 370        if (IS_ERR(sdev->fout_vpll)) {
 371                dev_err(dev, "failed to get clock 'fout_vpll'\n");
 372                ret = PTR_ERR(sdev->fout_vpll);
 373                goto fail_dacphy;
 374        }
 375        dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
 376
 377        /* acquire regulator */
 378        sdev->vdac = devm_regulator_get(dev, "vdd33a_dac");
 379        if (IS_ERR(sdev->vdac)) {
 380                dev_err(dev, "failed to get regulator 'vdac'\n");
 381                ret = PTR_ERR(sdev->vdac);
 382                goto fail_fout_vpll;
 383        }
 384        sdev->vdet = devm_regulator_get(dev, "vdet");
 385        if (IS_ERR(sdev->vdet)) {
 386                dev_err(dev, "failed to get regulator 'vdet'\n");
 387                ret = PTR_ERR(sdev->vdet);
 388                goto fail_fout_vpll;
 389        }
 390
 391        /* enable gate for dac clock, because mixer uses it */
 392        clk_enable(sdev->dac);
 393
 394        /* configure power management */
 395        pm_runtime_enable(dev);
 396
 397        /* configuration of interface subdevice */
 398        v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
 399        sdev->sd.owner = THIS_MODULE;
 400        strlcpy(sdev->sd.name, "s5p-sdo", sizeof(sdev->sd.name));
 401
 402        /* set default format */
 403        sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
 404        BUG_ON(sdev->fmt == NULL);
 405
 406        /* keeping subdev in device's private for use by other drivers */
 407        dev_set_drvdata(dev, &sdev->sd);
 408
 409        dev_info(dev, "probe succeeded\n");
 410        return 0;
 411
 412fail_fout_vpll:
 413        clk_put(sdev->fout_vpll);
 414fail_dacphy:
 415        clk_put(sdev->dacphy);
 416fail_dac:
 417        clk_put(sdev->dac);
 418fail_sclk_dac:
 419        clk_put(sdev->sclk_dac);
 420fail:
 421        dev_info(dev, "probe failed\n");
 422        return ret;
 423}
 424
 425static int sdo_remove(struct platform_device *pdev)
 426{
 427        struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
 428        struct sdo_device *sdev = sd_to_sdev(sd);
 429
 430        pm_runtime_disable(&pdev->dev);
 431        clk_disable(sdev->dac);
 432        clk_put(sdev->fout_vpll);
 433        clk_put(sdev->dacphy);
 434        clk_put(sdev->dac);
 435        clk_put(sdev->sclk_dac);
 436
 437        dev_info(&pdev->dev, "remove successful\n");
 438        return 0;
 439}
 440
 441static struct platform_driver sdo_driver __refdata = {
 442        .probe = sdo_probe,
 443        .remove = sdo_remove,
 444        .driver = {
 445                .name = "s5p-sdo",
 446                .owner = THIS_MODULE,
 447                .pm = &sdo_pm_ops,
 448        }
 449};
 450
 451module_platform_driver(sdo_driver);
 452