linux/drivers/gpu/host1x/mipi.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013 NVIDIA Corporation
   3 *
   4 * Permission to use, copy, modify, distribute, and sell this software and its
   5 * documentation for any purpose is hereby granted without fee, provided that
   6 * the above copyright notice appear in all copies and that both that copyright
   7 * notice and this permission notice appear in supporting documentation, and
   8 * that the name of the copyright holders not be used in advertising or
   9 * publicity pertaining to distribution of the software without specific,
  10 * written prior permission.  The copyright holders make no representations
  11 * about the suitability of this software for any purpose.  It is provided "as
  12 * is" without express or implied warranty.
  13 *
  14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  20 * OF THIS SOFTWARE.
  21 */
  22
  23#include <linux/clk.h>
  24#include <linux/host1x.h>
  25#include <linux/io.h>
  26#include <linux/iopoll.h>
  27#include <linux/of_platform.h>
  28#include <linux/platform_device.h>
  29#include <linux/slab.h>
  30
  31#include "dev.h"
  32
  33#define MIPI_CAL_CTRL                   0x00
  34#define MIPI_CAL_CTRL_NOISE_FILTER(x)   (((x) & 0xf) << 26)
  35#define MIPI_CAL_CTRL_PRESCALE(x)       (((x) & 0x3) << 24)
  36#define MIPI_CAL_CTRL_CLKEN_OVR         (1 << 4)
  37#define MIPI_CAL_CTRL_START             (1 << 0)
  38
  39#define MIPI_CAL_AUTOCAL_CTRL           0x01
  40
  41#define MIPI_CAL_STATUS                 0x02
  42#define MIPI_CAL_STATUS_DONE            (1 << 16)
  43#define MIPI_CAL_STATUS_ACTIVE          (1 <<  0)
  44
  45#define MIPI_CAL_CONFIG_CSIA            0x05
  46#define MIPI_CAL_CONFIG_CSIB            0x06
  47#define MIPI_CAL_CONFIG_CSIC            0x07
  48#define MIPI_CAL_CONFIG_CSID            0x08
  49#define MIPI_CAL_CONFIG_CSIE            0x09
  50#define MIPI_CAL_CONFIG_CSIF            0x0a
  51#define MIPI_CAL_CONFIG_DSIA            0x0e
  52#define MIPI_CAL_CONFIG_DSIB            0x0f
  53#define MIPI_CAL_CONFIG_DSIC            0x10
  54#define MIPI_CAL_CONFIG_DSID            0x11
  55
  56#define MIPI_CAL_CONFIG_DSIA_CLK        0x19
  57#define MIPI_CAL_CONFIG_DSIB_CLK        0x1a
  58#define MIPI_CAL_CONFIG_CSIAB_CLK       0x1b
  59#define MIPI_CAL_CONFIG_DSIC_CLK        0x1c
  60#define MIPI_CAL_CONFIG_CSICD_CLK       0x1c
  61#define MIPI_CAL_CONFIG_DSID_CLK        0x1d
  62#define MIPI_CAL_CONFIG_CSIE_CLK        0x1d
  63
  64/* for data and clock lanes */
  65#define MIPI_CAL_CONFIG_SELECT          (1 << 21)
  66
  67/* for data lanes */
  68#define MIPI_CAL_CONFIG_HSPDOS(x)       (((x) & 0x1f) << 16)
  69#define MIPI_CAL_CONFIG_HSPUOS(x)       (((x) & 0x1f) <<  8)
  70#define MIPI_CAL_CONFIG_TERMOS(x)       (((x) & 0x1f) <<  0)
  71
  72/* for clock lanes */
  73#define MIPI_CAL_CONFIG_HSCLKPDOSD(x)   (((x) & 0x1f) <<  8)
  74#define MIPI_CAL_CONFIG_HSCLKPUOSD(x)   (((x) & 0x1f) <<  0)
  75
  76#define MIPI_CAL_BIAS_PAD_CFG0          0x16
  77#define MIPI_CAL_BIAS_PAD_PDVCLAMP      (1 << 1)
  78#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF  (1 << 0)
  79
  80#define MIPI_CAL_BIAS_PAD_CFG1          0x17
  81#define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16)
  82#define MIPI_CAL_BIAS_PAD_DRV_UP_REF(x) (((x) & 0x7) << 8)
  83
  84#define MIPI_CAL_BIAS_PAD_CFG2          0x18
  85#define MIPI_CAL_BIAS_PAD_VCLAMP(x)     (((x) & 0x7) << 16)
  86#define MIPI_CAL_BIAS_PAD_VAUXP(x)      (((x) & 0x7) << 4)
  87#define MIPI_CAL_BIAS_PAD_PDVREG        (1 << 1)
  88
  89struct tegra_mipi_pad {
  90        unsigned long data;
  91        unsigned long clk;
  92};
  93
  94struct tegra_mipi_soc {
  95        bool has_clk_lane;
  96        const struct tegra_mipi_pad *pads;
  97        unsigned int num_pads;
  98
  99        bool clock_enable_override;
 100        bool needs_vclamp_ref;
 101
 102        /* bias pad configuration settings */
 103        u8 pad_drive_down_ref;
 104        u8 pad_drive_up_ref;
 105
 106        u8 pad_vclamp_level;
 107        u8 pad_vauxp_level;
 108
 109        /* calibration settings for data lanes */
 110        u8 hspdos;
 111        u8 hspuos;
 112        u8 termos;
 113
 114        /* calibration settings for clock lanes */
 115        u8 hsclkpdos;
 116        u8 hsclkpuos;
 117};
 118
 119struct tegra_mipi {
 120        const struct tegra_mipi_soc *soc;
 121        struct device *dev;
 122        void __iomem *regs;
 123        struct mutex lock;
 124        struct clk *clk;
 125
 126        unsigned long usage_count;
 127};
 128
 129struct tegra_mipi_device {
 130        struct platform_device *pdev;
 131        struct tegra_mipi *mipi;
 132        struct device *device;
 133        unsigned long pads;
 134};
 135
 136static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi,
 137                                   unsigned long offset)
 138{
 139        return readl(mipi->regs + (offset << 2));
 140}
 141
 142static inline void tegra_mipi_writel(struct tegra_mipi *mipi, u32 value,
 143                                     unsigned long offset)
 144{
 145        writel(value, mipi->regs + (offset << 2));
 146}
 147
 148static int tegra_mipi_power_up(struct tegra_mipi *mipi)
 149{
 150        u32 value;
 151        int err;
 152
 153        err = clk_enable(mipi->clk);
 154        if (err < 0)
 155                return err;
 156
 157        value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0);
 158        value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
 159
 160        if (mipi->soc->needs_vclamp_ref)
 161                value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
 162
 163        tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
 164
 165        value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2);
 166        value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
 167        tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
 168
 169        clk_disable(mipi->clk);
 170
 171        return 0;
 172}
 173
 174static int tegra_mipi_power_down(struct tegra_mipi *mipi)
 175{
 176        u32 value;
 177        int err;
 178
 179        err = clk_enable(mipi->clk);
 180        if (err < 0)
 181                return err;
 182
 183        /*
 184         * The MIPI_CAL_BIAS_PAD_PDVREG controls a voltage regulator that
 185         * supplies the DSI pads. This must be kept enabled until none of the
 186         * DSI lanes are used anymore.
 187         */
 188        value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2);
 189        value |= MIPI_CAL_BIAS_PAD_PDVREG;
 190        tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
 191
 192        /*
 193         * MIPI_CAL_BIAS_PAD_PDVCLAMP and MIPI_CAL_BIAS_PAD_E_VCLAMP_REF
 194         * control a regulator that supplies current to the pre-driver logic.
 195         * Powering down this regulator causes DSI to fail, so it must remain
 196         * powered on until none of the DSI lanes are used anymore.
 197         */
 198        value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0);
 199
 200        if (mipi->soc->needs_vclamp_ref)
 201                value &= ~MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
 202
 203        value |= MIPI_CAL_BIAS_PAD_PDVCLAMP;
 204        tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
 205
 206        return 0;
 207}
 208
 209struct tegra_mipi_device *tegra_mipi_request(struct device *device,
 210                                             struct device_node *np)
 211{
 212        struct tegra_mipi_device *dev;
 213        struct of_phandle_args args;
 214        int err;
 215
 216        err = of_parse_phandle_with_args(np, "nvidia,mipi-calibrate",
 217                                         "#nvidia,mipi-calibrate-cells", 0,
 218                                         &args);
 219        if (err < 0)
 220                return ERR_PTR(err);
 221
 222        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 223        if (!dev) {
 224                err = -ENOMEM;
 225                goto out;
 226        }
 227
 228        dev->pdev = of_find_device_by_node(args.np);
 229        if (!dev->pdev) {
 230                err = -ENODEV;
 231                goto free;
 232        }
 233
 234        dev->mipi = platform_get_drvdata(dev->pdev);
 235        if (!dev->mipi) {
 236                err = -EPROBE_DEFER;
 237                goto put;
 238        }
 239
 240        of_node_put(args.np);
 241
 242        dev->pads = args.args[0];
 243        dev->device = device;
 244
 245        return dev;
 246
 247put:
 248        platform_device_put(dev->pdev);
 249free:
 250        kfree(dev);
 251out:
 252        of_node_put(args.np);
 253        return ERR_PTR(err);
 254}
 255EXPORT_SYMBOL(tegra_mipi_request);
 256
 257void tegra_mipi_free(struct tegra_mipi_device *device)
 258{
 259        platform_device_put(device->pdev);
 260        kfree(device);
 261}
 262EXPORT_SYMBOL(tegra_mipi_free);
 263
 264int tegra_mipi_enable(struct tegra_mipi_device *dev)
 265{
 266        int err = 0;
 267
 268        mutex_lock(&dev->mipi->lock);
 269
 270        if (dev->mipi->usage_count++ == 0)
 271                err = tegra_mipi_power_up(dev->mipi);
 272
 273        mutex_unlock(&dev->mipi->lock);
 274
 275        return err;
 276
 277}
 278EXPORT_SYMBOL(tegra_mipi_enable);
 279
 280int tegra_mipi_disable(struct tegra_mipi_device *dev)
 281{
 282        int err = 0;
 283
 284        mutex_lock(&dev->mipi->lock);
 285
 286        if (--dev->mipi->usage_count == 0)
 287                err = tegra_mipi_power_down(dev->mipi);
 288
 289        mutex_unlock(&dev->mipi->lock);
 290
 291        return err;
 292
 293}
 294EXPORT_SYMBOL(tegra_mipi_disable);
 295
 296int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
 297{
 298        struct tegra_mipi *mipi = device->mipi;
 299        void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2);
 300        u32 value;
 301        int err;
 302
 303        err = readl_relaxed_poll_timeout(status_reg, value,
 304                                         !(value & MIPI_CAL_STATUS_ACTIVE) &&
 305                                         (value & MIPI_CAL_STATUS_DONE), 50,
 306                                         250000);
 307        mutex_unlock(&device->mipi->lock);
 308        clk_disable(device->mipi->clk);
 309
 310        return err;
 311}
 312EXPORT_SYMBOL(tegra_mipi_finish_calibration);
 313
 314int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
 315{
 316        const struct tegra_mipi_soc *soc = device->mipi->soc;
 317        unsigned int i;
 318        u32 value;
 319        int err;
 320
 321        err = clk_enable(device->mipi->clk);
 322        if (err < 0)
 323                return err;
 324
 325        mutex_lock(&device->mipi->lock);
 326
 327        value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc->pad_drive_down_ref) |
 328                MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc->pad_drive_up_ref);
 329        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG1);
 330
 331        value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
 332        value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
 333        value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
 334        value |= MIPI_CAL_BIAS_PAD_VCLAMP(soc->pad_vclamp_level);
 335        value |= MIPI_CAL_BIAS_PAD_VAUXP(soc->pad_vauxp_level);
 336        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
 337
 338        for (i = 0; i < soc->num_pads; i++) {
 339                u32 clk = 0, data = 0;
 340
 341                if (device->pads & BIT(i)) {
 342                        data = MIPI_CAL_CONFIG_SELECT |
 343                               MIPI_CAL_CONFIG_HSPDOS(soc->hspdos) |
 344                               MIPI_CAL_CONFIG_HSPUOS(soc->hspuos) |
 345                               MIPI_CAL_CONFIG_TERMOS(soc->termos);
 346                        clk = MIPI_CAL_CONFIG_SELECT |
 347                              MIPI_CAL_CONFIG_HSCLKPDOSD(soc->hsclkpdos) |
 348                              MIPI_CAL_CONFIG_HSCLKPUOSD(soc->hsclkpuos);
 349                }
 350
 351                tegra_mipi_writel(device->mipi, data, soc->pads[i].data);
 352
 353                if (soc->has_clk_lane && soc->pads[i].clk != 0)
 354                        tegra_mipi_writel(device->mipi, clk, soc->pads[i].clk);
 355        }
 356
 357        value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
 358        value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf);
 359        value &= ~MIPI_CAL_CTRL_PRESCALE(0x3);
 360        value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa);
 361        value |= MIPI_CAL_CTRL_PRESCALE(0x2);
 362
 363        if (!soc->clock_enable_override)
 364                value &= ~MIPI_CAL_CTRL_CLKEN_OVR;
 365        else
 366                value |= MIPI_CAL_CTRL_CLKEN_OVR;
 367
 368        tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
 369
 370        /* clear any pending status bits */
 371        value = tegra_mipi_readl(device->mipi, MIPI_CAL_STATUS);
 372        tegra_mipi_writel(device->mipi, value, MIPI_CAL_STATUS);
 373
 374        value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
 375        value |= MIPI_CAL_CTRL_START;
 376        tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
 377
 378        /*
 379         * Wait for min 72uS to let calibration logic finish calibration
 380         * sequence codes before waiting for pads idle state to apply the
 381         * results.
 382         */
 383        usleep_range(75, 80);
 384
 385        return 0;
 386}
 387EXPORT_SYMBOL(tegra_mipi_start_calibration);
 388
 389static const struct tegra_mipi_pad tegra114_mipi_pads[] = {
 390        { .data = MIPI_CAL_CONFIG_CSIA },
 391        { .data = MIPI_CAL_CONFIG_CSIB },
 392        { .data = MIPI_CAL_CONFIG_CSIC },
 393        { .data = MIPI_CAL_CONFIG_CSID },
 394        { .data = MIPI_CAL_CONFIG_CSIE },
 395        { .data = MIPI_CAL_CONFIG_DSIA },
 396        { .data = MIPI_CAL_CONFIG_DSIB },
 397        { .data = MIPI_CAL_CONFIG_DSIC },
 398        { .data = MIPI_CAL_CONFIG_DSID },
 399};
 400
 401static const struct tegra_mipi_soc tegra114_mipi_soc = {
 402        .has_clk_lane = false,
 403        .pads = tegra114_mipi_pads,
 404        .num_pads = ARRAY_SIZE(tegra114_mipi_pads),
 405        .clock_enable_override = true,
 406        .needs_vclamp_ref = true,
 407        .pad_drive_down_ref = 0x2,
 408        .pad_drive_up_ref = 0x0,
 409        .pad_vclamp_level = 0x0,
 410        .pad_vauxp_level = 0x0,
 411        .hspdos = 0x0,
 412        .hspuos = 0x4,
 413        .termos = 0x5,
 414        .hsclkpdos = 0x0,
 415        .hsclkpuos = 0x4,
 416};
 417
 418static const struct tegra_mipi_pad tegra124_mipi_pads[] = {
 419        { .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
 420        { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
 421        { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
 422        { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
 423        { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK  },
 424        { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK  },
 425        { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK  },
 426};
 427
 428static const struct tegra_mipi_soc tegra124_mipi_soc = {
 429        .has_clk_lane = true,
 430        .pads = tegra124_mipi_pads,
 431        .num_pads = ARRAY_SIZE(tegra124_mipi_pads),
 432        .clock_enable_override = true,
 433        .needs_vclamp_ref = true,
 434        .pad_drive_down_ref = 0x2,
 435        .pad_drive_up_ref = 0x0,
 436        .pad_vclamp_level = 0x0,
 437        .pad_vauxp_level = 0x0,
 438        .hspdos = 0x0,
 439        .hspuos = 0x0,
 440        .termos = 0x0,
 441        .hsclkpdos = 0x1,
 442        .hsclkpuos = 0x2,
 443};
 444
 445static const struct tegra_mipi_soc tegra132_mipi_soc = {
 446        .has_clk_lane = true,
 447        .pads = tegra124_mipi_pads,
 448        .num_pads = ARRAY_SIZE(tegra124_mipi_pads),
 449        .clock_enable_override = false,
 450        .needs_vclamp_ref = false,
 451        .pad_drive_down_ref = 0x0,
 452        .pad_drive_up_ref = 0x3,
 453        .pad_vclamp_level = 0x0,
 454        .pad_vauxp_level = 0x0,
 455        .hspdos = 0x0,
 456        .hspuos = 0x0,
 457        .termos = 0x0,
 458        .hsclkpdos = 0x3,
 459        .hsclkpuos = 0x2,
 460};
 461
 462static const struct tegra_mipi_pad tegra210_mipi_pads[] = {
 463        { .data = MIPI_CAL_CONFIG_CSIA, .clk = 0 },
 464        { .data = MIPI_CAL_CONFIG_CSIB, .clk = 0 },
 465        { .data = MIPI_CAL_CONFIG_CSIC, .clk = 0 },
 466        { .data = MIPI_CAL_CONFIG_CSID, .clk = 0 },
 467        { .data = MIPI_CAL_CONFIG_CSIE, .clk = 0 },
 468        { .data = MIPI_CAL_CONFIG_CSIF, .clk = 0 },
 469        { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK },
 470        { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK },
 471        { .data = MIPI_CAL_CONFIG_DSIC, .clk = MIPI_CAL_CONFIG_DSIC_CLK },
 472        { .data = MIPI_CAL_CONFIG_DSID, .clk = MIPI_CAL_CONFIG_DSID_CLK },
 473};
 474
 475static const struct tegra_mipi_soc tegra210_mipi_soc = {
 476        .has_clk_lane = true,
 477        .pads = tegra210_mipi_pads,
 478        .num_pads = ARRAY_SIZE(tegra210_mipi_pads),
 479        .clock_enable_override = true,
 480        .needs_vclamp_ref = false,
 481        .pad_drive_down_ref = 0x0,
 482        .pad_drive_up_ref = 0x3,
 483        .pad_vclamp_level = 0x1,
 484        .pad_vauxp_level = 0x1,
 485        .hspdos = 0x0,
 486        .hspuos = 0x2,
 487        .termos = 0x0,
 488        .hsclkpdos = 0x0,
 489        .hsclkpuos = 0x2,
 490};
 491
 492static const struct of_device_id tegra_mipi_of_match[] = {
 493        { .compatible = "nvidia,tegra114-mipi", .data = &tegra114_mipi_soc },
 494        { .compatible = "nvidia,tegra124-mipi", .data = &tegra124_mipi_soc },
 495        { .compatible = "nvidia,tegra132-mipi", .data = &tegra132_mipi_soc },
 496        { .compatible = "nvidia,tegra210-mipi", .data = &tegra210_mipi_soc },
 497        { },
 498};
 499
 500static int tegra_mipi_probe(struct platform_device *pdev)
 501{
 502        const struct of_device_id *match;
 503        struct tegra_mipi *mipi;
 504        struct resource *res;
 505        int err;
 506
 507        match = of_match_node(tegra_mipi_of_match, pdev->dev.of_node);
 508        if (!match)
 509                return -ENODEV;
 510
 511        mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL);
 512        if (!mipi)
 513                return -ENOMEM;
 514
 515        mipi->soc = match->data;
 516        mipi->dev = &pdev->dev;
 517
 518        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 519        mipi->regs = devm_ioremap_resource(&pdev->dev, res);
 520        if (IS_ERR(mipi->regs))
 521                return PTR_ERR(mipi->regs);
 522
 523        mutex_init(&mipi->lock);
 524
 525        mipi->clk = devm_clk_get(&pdev->dev, NULL);
 526        if (IS_ERR(mipi->clk)) {
 527                dev_err(&pdev->dev, "failed to get clock\n");
 528                return PTR_ERR(mipi->clk);
 529        }
 530
 531        err = clk_prepare(mipi->clk);
 532        if (err < 0)
 533                return err;
 534
 535        platform_set_drvdata(pdev, mipi);
 536
 537        return 0;
 538}
 539
 540static int tegra_mipi_remove(struct platform_device *pdev)
 541{
 542        struct tegra_mipi *mipi = platform_get_drvdata(pdev);
 543
 544        clk_unprepare(mipi->clk);
 545
 546        return 0;
 547}
 548
 549struct platform_driver tegra_mipi_driver = {
 550        .driver = {
 551                .name = "tegra-mipi",
 552                .of_match_table = tegra_mipi_of_match,
 553        },
 554        .probe = tegra_mipi_probe,
 555        .remove = tegra_mipi_remove,
 556};
 557