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/delay.h>
  25#include <linux/host1x.h>
  26#include <linux/io.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{
 211        struct device_node *np = device->of_node;
 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
 296static int tegra_mipi_wait(struct tegra_mipi *mipi)
 297{
 298        unsigned long timeout = jiffies + msecs_to_jiffies(250);
 299        u32 value;
 300
 301        while (time_before(jiffies, timeout)) {
 302                value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS);
 303                if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 &&
 304                    (value & MIPI_CAL_STATUS_DONE) != 0)
 305                        return 0;
 306
 307                usleep_range(10, 50);
 308        }
 309
 310        return -ETIMEDOUT;
 311}
 312
 313int tegra_mipi_calibrate(struct tegra_mipi_device *device)
 314{
 315        const struct tegra_mipi_soc *soc = device->mipi->soc;
 316        unsigned int i;
 317        u32 value;
 318        int err;
 319
 320        err = clk_enable(device->mipi->clk);
 321        if (err < 0)
 322                return err;
 323
 324        mutex_lock(&device->mipi->lock);
 325
 326        value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc->pad_drive_down_ref) |
 327                MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc->pad_drive_up_ref);
 328        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG1);
 329
 330        value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
 331        value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
 332        value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
 333        value |= MIPI_CAL_BIAS_PAD_VCLAMP(soc->pad_vclamp_level);
 334        value |= MIPI_CAL_BIAS_PAD_VAUXP(soc->pad_vauxp_level);
 335        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
 336
 337        for (i = 0; i < soc->num_pads; i++) {
 338                u32 clk = 0, data = 0;
 339
 340                if (device->pads & BIT(i)) {
 341                        data = MIPI_CAL_CONFIG_SELECT |
 342                               MIPI_CAL_CONFIG_HSPDOS(soc->hspdos) |
 343                               MIPI_CAL_CONFIG_HSPUOS(soc->hspuos) |
 344                               MIPI_CAL_CONFIG_TERMOS(soc->termos);
 345                        clk = MIPI_CAL_CONFIG_SELECT |
 346                              MIPI_CAL_CONFIG_HSCLKPDOSD(soc->hsclkpdos) |
 347                              MIPI_CAL_CONFIG_HSCLKPUOSD(soc->hsclkpuos);
 348                }
 349
 350                tegra_mipi_writel(device->mipi, data, soc->pads[i].data);
 351
 352                if (soc->has_clk_lane && soc->pads[i].clk != 0)
 353                        tegra_mipi_writel(device->mipi, clk, soc->pads[i].clk);
 354        }
 355
 356        value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
 357        value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf);
 358        value &= ~MIPI_CAL_CTRL_PRESCALE(0x3);
 359        value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa);
 360        value |= MIPI_CAL_CTRL_PRESCALE(0x2);
 361
 362        if (!soc->clock_enable_override)
 363                value &= ~MIPI_CAL_CTRL_CLKEN_OVR;
 364        else
 365                value |= MIPI_CAL_CTRL_CLKEN_OVR;
 366
 367        tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
 368
 369        /* clear any pending status bits */
 370        value = tegra_mipi_readl(device->mipi, MIPI_CAL_STATUS);
 371        tegra_mipi_writel(device->mipi, value, MIPI_CAL_STATUS);
 372
 373        value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
 374        value |= MIPI_CAL_CTRL_START;
 375        tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
 376
 377        err = tegra_mipi_wait(device->mipi);
 378
 379        mutex_unlock(&device->mipi->lock);
 380        clk_disable(device->mipi->clk);
 381
 382        return err;
 383}
 384EXPORT_SYMBOL(tegra_mipi_calibrate);
 385
 386static const struct tegra_mipi_pad tegra114_mipi_pads[] = {
 387        { .data = MIPI_CAL_CONFIG_CSIA },
 388        { .data = MIPI_CAL_CONFIG_CSIB },
 389        { .data = MIPI_CAL_CONFIG_CSIC },
 390        { .data = MIPI_CAL_CONFIG_CSID },
 391        { .data = MIPI_CAL_CONFIG_CSIE },
 392        { .data = MIPI_CAL_CONFIG_DSIA },
 393        { .data = MIPI_CAL_CONFIG_DSIB },
 394        { .data = MIPI_CAL_CONFIG_DSIC },
 395        { .data = MIPI_CAL_CONFIG_DSID },
 396};
 397
 398static const struct tegra_mipi_soc tegra114_mipi_soc = {
 399        .has_clk_lane = false,
 400        .pads = tegra114_mipi_pads,
 401        .num_pads = ARRAY_SIZE(tegra114_mipi_pads),
 402        .clock_enable_override = true,
 403        .needs_vclamp_ref = true,
 404        .pad_drive_down_ref = 0x2,
 405        .pad_drive_up_ref = 0x0,
 406        .pad_vclamp_level = 0x0,
 407        .pad_vauxp_level = 0x0,
 408        .hspdos = 0x0,
 409        .hspuos = 0x4,
 410        .termos = 0x5,
 411        .hsclkpdos = 0x0,
 412        .hsclkpuos = 0x4,
 413};
 414
 415static const struct tegra_mipi_pad tegra124_mipi_pads[] = {
 416        { .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
 417        { .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
 418        { .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
 419        { .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
 420        { .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK  },
 421        { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK  },
 422        { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK  },
 423};
 424
 425static const struct tegra_mipi_soc tegra124_mipi_soc = {
 426        .has_clk_lane = true,
 427        .pads = tegra124_mipi_pads,
 428        .num_pads = ARRAY_SIZE(tegra124_mipi_pads),
 429        .clock_enable_override = true,
 430        .needs_vclamp_ref = true,
 431        .pad_drive_down_ref = 0x2,
 432        .pad_drive_up_ref = 0x0,
 433        .pad_vclamp_level = 0x0,
 434        .pad_vauxp_level = 0x0,
 435        .hspdos = 0x0,
 436        .hspuos = 0x0,
 437        .termos = 0x0,
 438        .hsclkpdos = 0x1,
 439        .hsclkpuos = 0x2,
 440};
 441
 442static const struct tegra_mipi_soc tegra132_mipi_soc = {
 443        .has_clk_lane = true,
 444        .pads = tegra124_mipi_pads,
 445        .num_pads = ARRAY_SIZE(tegra124_mipi_pads),
 446        .clock_enable_override = false,
 447        .needs_vclamp_ref = false,
 448        .pad_drive_down_ref = 0x0,
 449        .pad_drive_up_ref = 0x3,
 450        .pad_vclamp_level = 0x0,
 451        .pad_vauxp_level = 0x0,
 452        .hspdos = 0x0,
 453        .hspuos = 0x0,
 454        .termos = 0x0,
 455        .hsclkpdos = 0x3,
 456        .hsclkpuos = 0x2,
 457};
 458
 459static const struct tegra_mipi_pad tegra210_mipi_pads[] = {
 460        { .data = MIPI_CAL_CONFIG_CSIA, .clk = 0 },
 461        { .data = MIPI_CAL_CONFIG_CSIB, .clk = 0 },
 462        { .data = MIPI_CAL_CONFIG_CSIC, .clk = 0 },
 463        { .data = MIPI_CAL_CONFIG_CSID, .clk = 0 },
 464        { .data = MIPI_CAL_CONFIG_CSIE, .clk = 0 },
 465        { .data = MIPI_CAL_CONFIG_CSIF, .clk = 0 },
 466        { .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK },
 467        { .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK },
 468        { .data = MIPI_CAL_CONFIG_DSIC, .clk = MIPI_CAL_CONFIG_DSIC_CLK },
 469        { .data = MIPI_CAL_CONFIG_DSID, .clk = MIPI_CAL_CONFIG_DSID_CLK },
 470};
 471
 472static const struct tegra_mipi_soc tegra210_mipi_soc = {
 473        .has_clk_lane = true,
 474        .pads = tegra210_mipi_pads,
 475        .num_pads = ARRAY_SIZE(tegra210_mipi_pads),
 476        .clock_enable_override = true,
 477        .needs_vclamp_ref = false,
 478        .pad_drive_down_ref = 0x0,
 479        .pad_drive_up_ref = 0x3,
 480        .pad_vclamp_level = 0x1,
 481        .pad_vauxp_level = 0x1,
 482        .hspdos = 0x0,
 483        .hspuos = 0x2,
 484        .termos = 0x0,
 485        .hsclkpdos = 0x0,
 486        .hsclkpuos = 0x2,
 487};
 488
 489static const struct of_device_id tegra_mipi_of_match[] = {
 490        { .compatible = "nvidia,tegra114-mipi", .data = &tegra114_mipi_soc },
 491        { .compatible = "nvidia,tegra124-mipi", .data = &tegra124_mipi_soc },
 492        { .compatible = "nvidia,tegra132-mipi", .data = &tegra132_mipi_soc },
 493        { .compatible = "nvidia,tegra210-mipi", .data = &tegra210_mipi_soc },
 494        { },
 495};
 496
 497static int tegra_mipi_probe(struct platform_device *pdev)
 498{
 499        const struct of_device_id *match;
 500        struct tegra_mipi *mipi;
 501        struct resource *res;
 502        int err;
 503
 504        match = of_match_node(tegra_mipi_of_match, pdev->dev.of_node);
 505        if (!match)
 506                return -ENODEV;
 507
 508        mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL);
 509        if (!mipi)
 510                return -ENOMEM;
 511
 512        mipi->soc = match->data;
 513        mipi->dev = &pdev->dev;
 514
 515        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 516        mipi->regs = devm_ioremap_resource(&pdev->dev, res);
 517        if (IS_ERR(mipi->regs))
 518                return PTR_ERR(mipi->regs);
 519
 520        mutex_init(&mipi->lock);
 521
 522        mipi->clk = devm_clk_get(&pdev->dev, NULL);
 523        if (IS_ERR(mipi->clk)) {
 524                dev_err(&pdev->dev, "failed to get clock\n");
 525                return PTR_ERR(mipi->clk);
 526        }
 527
 528        err = clk_prepare(mipi->clk);
 529        if (err < 0)
 530                return err;
 531
 532        platform_set_drvdata(pdev, mipi);
 533
 534        return 0;
 535}
 536
 537static int tegra_mipi_remove(struct platform_device *pdev)
 538{
 539        struct tegra_mipi *mipi = platform_get_drvdata(pdev);
 540
 541        clk_unprepare(mipi->clk);
 542
 543        return 0;
 544}
 545
 546struct platform_driver tegra_mipi_driver = {
 547        .driver = {
 548                .name = "tegra-mipi",
 549                .of_match_table = tegra_mipi_of_match,
 550        },
 551        .probe = tegra_mipi_probe,
 552        .remove = tegra_mipi_remove,
 553};
 554