linux/drivers/media/platform/s5p-tv/mixer_drv.c
<<
>>
Prefs
   1/*
   2 * Samsung TV Mixer 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 "mixer.h"
  15
  16#include <linux/module.h>
  17#include <linux/platform_device.h>
  18#include <linux/io.h>
  19#include <linux/interrupt.h>
  20#include <linux/irq.h>
  21#include <linux/fb.h>
  22#include <linux/delay.h>
  23#include <linux/pm_runtime.h>
  24#include <linux/clk.h>
  25
  26MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
  27MODULE_DESCRIPTION("Samsung MIXER");
  28MODULE_LICENSE("GPL");
  29
  30/* --------- DRIVER PARAMETERS ---------- */
  31
  32static struct mxr_output_conf mxr_output_conf[] = {
  33        {
  34                .output_name = "S5P HDMI connector",
  35                .module_name = "s5p-hdmi",
  36                .cookie = 1,
  37        },
  38        {
  39                .output_name = "S5P SDO connector",
  40                .module_name = "s5p-sdo",
  41                .cookie = 0,
  42        },
  43};
  44
  45void mxr_get_mbus_fmt(struct mxr_device *mdev,
  46        struct v4l2_mbus_framefmt *mbus_fmt)
  47{
  48        struct v4l2_subdev *sd;
  49        int ret;
  50
  51        mutex_lock(&mdev->mutex);
  52        sd = to_outsd(mdev);
  53        ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
  54        WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
  55        mutex_unlock(&mdev->mutex);
  56}
  57
  58void mxr_streamer_get(struct mxr_device *mdev)
  59{
  60        mutex_lock(&mdev->mutex);
  61        ++mdev->n_streamer;
  62        mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
  63        if (mdev->n_streamer == 1) {
  64                struct v4l2_subdev *sd = to_outsd(mdev);
  65                struct v4l2_mbus_framefmt mbus_fmt;
  66                struct mxr_resources *res = &mdev->res;
  67                int ret;
  68
  69                if (to_output(mdev)->cookie == 0)
  70                        clk_set_parent(res->sclk_mixer, res->sclk_dac);
  71                else
  72                        clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
  73                mxr_reg_s_output(mdev, to_output(mdev)->cookie);
  74
  75                ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
  76                WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
  77                ret = v4l2_subdev_call(sd, video, s_stream, 1);
  78                WARN(ret, "starting stream failed for output %s\n", sd->name);
  79
  80                mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
  81                mxr_reg_streamon(mdev);
  82                ret = mxr_reg_wait4vsync(mdev);
  83                WARN(ret, "failed to get vsync (%d) from output\n", ret);
  84        }
  85        mutex_unlock(&mdev->mutex);
  86        mxr_reg_dump(mdev);
  87        /* FIXME: what to do when streaming fails? */
  88}
  89
  90void mxr_streamer_put(struct mxr_device *mdev)
  91{
  92        mutex_lock(&mdev->mutex);
  93        --mdev->n_streamer;
  94        mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
  95        if (mdev->n_streamer == 0) {
  96                int ret;
  97                struct v4l2_subdev *sd = to_outsd(mdev);
  98
  99                mxr_reg_streamoff(mdev);
 100                /* vsync applies Mixer setup */
 101                ret = mxr_reg_wait4vsync(mdev);
 102                WARN(ret, "failed to get vsync (%d) from output\n", ret);
 103                ret = v4l2_subdev_call(sd, video, s_stream, 0);
 104                WARN(ret, "stopping stream failed for output %s\n", sd->name);
 105        }
 106        WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
 107                mdev->n_streamer);
 108        mutex_unlock(&mdev->mutex);
 109        mxr_reg_dump(mdev);
 110}
 111
 112void mxr_output_get(struct mxr_device *mdev)
 113{
 114        mutex_lock(&mdev->mutex);
 115        ++mdev->n_output;
 116        mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
 117        /* turn on auxiliary driver */
 118        if (mdev->n_output == 1)
 119                v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
 120        mutex_unlock(&mdev->mutex);
 121}
 122
 123void mxr_output_put(struct mxr_device *mdev)
 124{
 125        mutex_lock(&mdev->mutex);
 126        --mdev->n_output;
 127        mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
 128        /* turn on auxiliary driver */
 129        if (mdev->n_output == 0)
 130                v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
 131        WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
 132                mdev->n_output);
 133        mutex_unlock(&mdev->mutex);
 134}
 135
 136int mxr_power_get(struct mxr_device *mdev)
 137{
 138        int ret = pm_runtime_get_sync(mdev->dev);
 139
 140        /* returning 1 means that power is already enabled,
 141         * so zero success be returned */
 142        if (IS_ERR_VALUE(ret))
 143                return ret;
 144        return 0;
 145}
 146
 147void mxr_power_put(struct mxr_device *mdev)
 148{
 149        pm_runtime_put_sync(mdev->dev);
 150}
 151
 152/* --------- RESOURCE MANAGEMENT -------------*/
 153
 154static int mxr_acquire_plat_resources(struct mxr_device *mdev,
 155                                      struct platform_device *pdev)
 156{
 157        struct resource *res;
 158        int ret;
 159
 160        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
 161        if (res == NULL) {
 162                mxr_err(mdev, "get memory resource failed.\n");
 163                ret = -ENXIO;
 164                goto fail;
 165        }
 166
 167        mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
 168        if (mdev->res.mxr_regs == NULL) {
 169                mxr_err(mdev, "register mapping failed.\n");
 170                ret = -ENXIO;
 171                goto fail;
 172        }
 173
 174        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
 175        if (res == NULL) {
 176                mxr_err(mdev, "get memory resource failed.\n");
 177                ret = -ENXIO;
 178                goto fail_mxr_regs;
 179        }
 180
 181        mdev->res.vp_regs = ioremap(res->start, resource_size(res));
 182        if (mdev->res.vp_regs == NULL) {
 183                mxr_err(mdev, "register mapping failed.\n");
 184                ret = -ENXIO;
 185                goto fail_mxr_regs;
 186        }
 187
 188        res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
 189        if (res == NULL) {
 190                mxr_err(mdev, "get interrupt resource failed.\n");
 191                ret = -ENXIO;
 192                goto fail_vp_regs;
 193        }
 194
 195        ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
 196        if (ret) {
 197                mxr_err(mdev, "request interrupt failed.\n");
 198                goto fail_vp_regs;
 199        }
 200        mdev->res.irq = res->start;
 201
 202        return 0;
 203
 204fail_vp_regs:
 205        iounmap(mdev->res.vp_regs);
 206
 207fail_mxr_regs:
 208        iounmap(mdev->res.mxr_regs);
 209
 210fail:
 211        return ret;
 212}
 213
 214static void mxr_resource_clear_clocks(struct mxr_resources *res)
 215{
 216        res->mixer      = ERR_PTR(-EINVAL);
 217        res->vp         = ERR_PTR(-EINVAL);
 218        res->sclk_mixer = ERR_PTR(-EINVAL);
 219        res->sclk_hdmi  = ERR_PTR(-EINVAL);
 220        res->sclk_dac   = ERR_PTR(-EINVAL);
 221}
 222
 223static void mxr_release_plat_resources(struct mxr_device *mdev)
 224{
 225        free_irq(mdev->res.irq, mdev);
 226        iounmap(mdev->res.vp_regs);
 227        iounmap(mdev->res.mxr_regs);
 228}
 229
 230static void mxr_release_clocks(struct mxr_device *mdev)
 231{
 232        struct mxr_resources *res = &mdev->res;
 233
 234        if (!IS_ERR(res->sclk_dac))
 235                clk_put(res->sclk_dac);
 236        if (!IS_ERR(res->sclk_hdmi))
 237                clk_put(res->sclk_hdmi);
 238        if (!IS_ERR(res->sclk_mixer))
 239                clk_put(res->sclk_mixer);
 240        if (!IS_ERR(res->vp))
 241                clk_put(res->vp);
 242        if (!IS_ERR(res->mixer))
 243                clk_put(res->mixer);
 244}
 245
 246static int mxr_acquire_clocks(struct mxr_device *mdev)
 247{
 248        struct mxr_resources *res = &mdev->res;
 249        struct device *dev = mdev->dev;
 250
 251        mxr_resource_clear_clocks(res);
 252
 253        res->mixer = clk_get(dev, "mixer");
 254        if (IS_ERR(res->mixer)) {
 255                mxr_err(mdev, "failed to get clock 'mixer'\n");
 256                goto fail;
 257        }
 258        res->vp = clk_get(dev, "vp");
 259        if (IS_ERR(res->vp)) {
 260                mxr_err(mdev, "failed to get clock 'vp'\n");
 261                goto fail;
 262        }
 263        res->sclk_mixer = clk_get(dev, "sclk_mixer");
 264        if (IS_ERR(res->sclk_mixer)) {
 265                mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
 266                goto fail;
 267        }
 268        res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
 269        if (IS_ERR(res->sclk_hdmi)) {
 270                mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
 271                goto fail;
 272        }
 273        res->sclk_dac = clk_get(dev, "sclk_dac");
 274        if (IS_ERR(res->sclk_dac)) {
 275                mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
 276                goto fail;
 277        }
 278
 279        return 0;
 280fail:
 281        mxr_release_clocks(mdev);
 282        return -ENODEV;
 283}
 284
 285static int mxr_acquire_resources(struct mxr_device *mdev,
 286                                 struct platform_device *pdev)
 287{
 288        int ret;
 289        ret = mxr_acquire_plat_resources(mdev, pdev);
 290
 291        if (ret)
 292                goto fail;
 293
 294        ret = mxr_acquire_clocks(mdev);
 295        if (ret)
 296                goto fail_plat;
 297
 298        mxr_info(mdev, "resources acquired\n");
 299        return 0;
 300
 301fail_plat:
 302        mxr_release_plat_resources(mdev);
 303fail:
 304        mxr_err(mdev, "resources acquire failed\n");
 305        return ret;
 306}
 307
 308static void mxr_release_resources(struct mxr_device *mdev)
 309{
 310        mxr_release_clocks(mdev);
 311        mxr_release_plat_resources(mdev);
 312        memset(&mdev->res, 0, sizeof(mdev->res));
 313        mxr_resource_clear_clocks(&mdev->res);
 314}
 315
 316static void mxr_release_layers(struct mxr_device *mdev)
 317{
 318        int i;
 319
 320        for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
 321                if (mdev->layer[i])
 322                        mxr_layer_release(mdev->layer[i]);
 323}
 324
 325static int mxr_acquire_layers(struct mxr_device *mdev,
 326                              struct mxr_platform_data *pdata)
 327{
 328        mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
 329        mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
 330        mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
 331
 332        if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
 333                mxr_err(mdev, "failed to acquire layers\n");
 334                goto fail;
 335        }
 336
 337        return 0;
 338
 339fail:
 340        mxr_release_layers(mdev);
 341        return -ENODEV;
 342}
 343
 344/* ---------- POWER MANAGEMENT ----------- */
 345
 346static int mxr_runtime_resume(struct device *dev)
 347{
 348        struct mxr_device *mdev = to_mdev(dev);
 349        struct mxr_resources *res = &mdev->res;
 350        int ret;
 351
 352        mxr_dbg(mdev, "resume - start\n");
 353        mutex_lock(&mdev->mutex);
 354        /* turn clocks on */
 355        ret = clk_prepare_enable(res->mixer);
 356        if (ret < 0) {
 357                dev_err(mdev->dev, "clk_prepare_enable(mixer) failed\n");
 358                goto fail;
 359        }
 360        ret = clk_prepare_enable(res->vp);
 361        if (ret < 0) {
 362                dev_err(mdev->dev, "clk_prepare_enable(vp) failed\n");
 363                goto fail_mixer;
 364        }
 365        ret = clk_prepare_enable(res->sclk_mixer);
 366        if (ret < 0) {
 367                dev_err(mdev->dev, "clk_prepare_enable(sclk_mixer) failed\n");
 368                goto fail_vp;
 369        }
 370        /* apply default configuration */
 371        mxr_reg_reset(mdev);
 372        mxr_dbg(mdev, "resume - finished\n");
 373
 374        mutex_unlock(&mdev->mutex);
 375        return 0;
 376
 377fail_vp:
 378        clk_disable_unprepare(res->vp);
 379fail_mixer:
 380        clk_disable_unprepare(res->mixer);
 381fail:
 382        mutex_unlock(&mdev->mutex);
 383        dev_err(mdev->dev, "resume failed\n");
 384        return ret;
 385}
 386
 387static int mxr_runtime_suspend(struct device *dev)
 388{
 389        struct mxr_device *mdev = to_mdev(dev);
 390        struct mxr_resources *res = &mdev->res;
 391        mxr_dbg(mdev, "suspend - start\n");
 392        mutex_lock(&mdev->mutex);
 393        /* turn clocks off */
 394        clk_disable_unprepare(res->sclk_mixer);
 395        clk_disable_unprepare(res->vp);
 396        clk_disable_unprepare(res->mixer);
 397        mutex_unlock(&mdev->mutex);
 398        mxr_dbg(mdev, "suspend - finished\n");
 399        return 0;
 400}
 401
 402static const struct dev_pm_ops mxr_pm_ops = {
 403        .runtime_suspend = mxr_runtime_suspend,
 404        .runtime_resume  = mxr_runtime_resume,
 405};
 406
 407/* --------- DRIVER INITIALIZATION ---------- */
 408
 409static int mxr_probe(struct platform_device *pdev)
 410{
 411        struct device *dev = &pdev->dev;
 412        struct mxr_platform_data *pdata = dev->platform_data;
 413        struct mxr_device *mdev;
 414        int ret;
 415
 416        /* mdev does not exist yet so no mxr_dbg is used */
 417        dev_info(dev, "probe start\n");
 418
 419        mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
 420        if (!mdev) {
 421                dev_err(dev, "not enough memory.\n");
 422                ret = -ENOMEM;
 423                goto fail;
 424        }
 425
 426        /* setup pointer to master device */
 427        mdev->dev = dev;
 428
 429        mutex_init(&mdev->mutex);
 430        spin_lock_init(&mdev->reg_slock);
 431        init_waitqueue_head(&mdev->event_queue);
 432
 433        /* acquire resources: regs, irqs, clocks, regulators */
 434        ret = mxr_acquire_resources(mdev, pdev);
 435        if (ret)
 436                goto fail_mem;
 437
 438        /* configure resources for video output */
 439        ret = mxr_acquire_video(mdev, mxr_output_conf,
 440                ARRAY_SIZE(mxr_output_conf));
 441        if (ret)
 442                goto fail_resources;
 443
 444        /* configure layers */
 445        ret = mxr_acquire_layers(mdev, pdata);
 446        if (ret)
 447                goto fail_video;
 448
 449        pm_runtime_enable(dev);
 450
 451        mxr_info(mdev, "probe successful\n");
 452        return 0;
 453
 454fail_video:
 455        mxr_release_video(mdev);
 456
 457fail_resources:
 458        mxr_release_resources(mdev);
 459
 460fail_mem:
 461        kfree(mdev);
 462
 463fail:
 464        dev_info(dev, "probe failed\n");
 465        return ret;
 466}
 467
 468static int mxr_remove(struct platform_device *pdev)
 469{
 470        struct device *dev = &pdev->dev;
 471        struct mxr_device *mdev = to_mdev(dev);
 472
 473        pm_runtime_disable(dev);
 474
 475        mxr_release_layers(mdev);
 476        mxr_release_video(mdev);
 477        mxr_release_resources(mdev);
 478
 479        kfree(mdev);
 480
 481        dev_info(dev, "remove successful\n");
 482        return 0;
 483}
 484
 485static struct platform_driver mxr_driver __refdata = {
 486        .probe = mxr_probe,
 487        .remove = mxr_remove,
 488        .driver = {
 489                .name = MXR_DRIVER_NAME,
 490                .owner = THIS_MODULE,
 491                .pm = &mxr_pm_ops,
 492        }
 493};
 494
 495static int __init mxr_init(void)
 496{
 497        int i, ret;
 498        static const char banner[] __initconst =
 499                "Samsung TV Mixer driver, "
 500                "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
 501        pr_info("%s\n", banner);
 502
 503        /* Loading auxiliary modules */
 504        for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
 505                request_module(mxr_output_conf[i].module_name);
 506
 507        ret = platform_driver_register(&mxr_driver);
 508        if (ret != 0) {
 509                pr_err("s5p-tv: registration of MIXER driver failed\n");
 510                return -ENXIO;
 511        }
 512
 513        return 0;
 514}
 515module_init(mxr_init);
 516
 517static void __exit mxr_exit(void)
 518{
 519        platform_driver_unregister(&mxr_driver);
 520}
 521module_exit(mxr_exit);
 522