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_START             (1 << 0)
  35
  36#define MIPI_CAL_AUTOCAL_CTRL           0x01
  37
  38#define MIPI_CAL_STATUS                 0x02
  39#define MIPI_CAL_STATUS_DONE            (1 << 16)
  40#define MIPI_CAL_STATUS_ACTIVE          (1 <<  0)
  41
  42#define MIPI_CAL_CONFIG_CSIA            0x05
  43#define MIPI_CAL_CONFIG_CSIB            0x06
  44#define MIPI_CAL_CONFIG_CSIC            0x07
  45#define MIPI_CAL_CONFIG_CSID            0x08
  46#define MIPI_CAL_CONFIG_CSIE            0x09
  47#define MIPI_CAL_CONFIG_DSIA            0x0e
  48#define MIPI_CAL_CONFIG_DSIB            0x0f
  49#define MIPI_CAL_CONFIG_DSIC            0x10
  50#define MIPI_CAL_CONFIG_DSID            0x11
  51
  52#define MIPI_CAL_CONFIG_SELECT          (1 << 21)
  53#define MIPI_CAL_CONFIG_HSPDOS(x)       (((x) & 0x1f) << 16)
  54#define MIPI_CAL_CONFIG_HSPUOS(x)       (((x) & 0x1f) <<  8)
  55#define MIPI_CAL_CONFIG_TERMOS(x)       (((x) & 0x1f) <<  0)
  56
  57#define MIPI_CAL_BIAS_PAD_CFG0          0x16
  58#define MIPI_CAL_BIAS_PAD_PDVCLAMP      (1 << 1)
  59#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF  (1 << 0)
  60
  61#define MIPI_CAL_BIAS_PAD_CFG1          0x17
  62
  63#define MIPI_CAL_BIAS_PAD_CFG2          0x18
  64#define MIPI_CAL_BIAS_PAD_PDVREG        (1 << 1)
  65
  66static const struct module {
  67        unsigned long reg;
  68} modules[] = {
  69        { .reg = MIPI_CAL_CONFIG_CSIA },
  70        { .reg = MIPI_CAL_CONFIG_CSIB },
  71        { .reg = MIPI_CAL_CONFIG_CSIC },
  72        { .reg = MIPI_CAL_CONFIG_CSID },
  73        { .reg = MIPI_CAL_CONFIG_CSIE },
  74        { .reg = MIPI_CAL_CONFIG_DSIA },
  75        { .reg = MIPI_CAL_CONFIG_DSIB },
  76        { .reg = MIPI_CAL_CONFIG_DSIC },
  77        { .reg = MIPI_CAL_CONFIG_DSID },
  78};
  79
  80struct tegra_mipi {
  81        void __iomem *regs;
  82        struct mutex lock;
  83        struct clk *clk;
  84};
  85
  86struct tegra_mipi_device {
  87        struct platform_device *pdev;
  88        struct tegra_mipi *mipi;
  89        struct device *device;
  90        unsigned long pads;
  91};
  92
  93static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi,
  94                                             unsigned long reg)
  95{
  96        return readl(mipi->regs + (reg << 2));
  97}
  98
  99static inline void tegra_mipi_writel(struct tegra_mipi *mipi,
 100                                     unsigned long value, unsigned long reg)
 101{
 102        writel(value, mipi->regs + (reg << 2));
 103}
 104
 105struct tegra_mipi_device *tegra_mipi_request(struct device *device)
 106{
 107        struct device_node *np = device->of_node;
 108        struct tegra_mipi_device *dev;
 109        struct of_phandle_args args;
 110        int err;
 111
 112        err = of_parse_phandle_with_args(np, "nvidia,mipi-calibrate",
 113                                         "#nvidia,mipi-calibrate-cells", 0,
 114                                         &args);
 115        if (err < 0)
 116                return ERR_PTR(err);
 117
 118        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 119        if (!dev) {
 120                of_node_put(args.np);
 121                err = -ENOMEM;
 122                goto out;
 123        }
 124
 125        dev->pdev = of_find_device_by_node(args.np);
 126        if (!dev->pdev) {
 127                of_node_put(args.np);
 128                err = -ENODEV;
 129                goto free;
 130        }
 131
 132        of_node_put(args.np);
 133
 134        dev->mipi = platform_get_drvdata(dev->pdev);
 135        if (!dev->mipi) {
 136                err = -EPROBE_DEFER;
 137                goto pdev_put;
 138        }
 139
 140        dev->pads = args.args[0];
 141        dev->device = device;
 142
 143        return dev;
 144
 145pdev_put:
 146        platform_device_put(dev->pdev);
 147free:
 148        kfree(dev);
 149out:
 150        return ERR_PTR(err);
 151}
 152EXPORT_SYMBOL(tegra_mipi_request);
 153
 154void tegra_mipi_free(struct tegra_mipi_device *device)
 155{
 156        platform_device_put(device->pdev);
 157        kfree(device);
 158}
 159EXPORT_SYMBOL(tegra_mipi_free);
 160
 161static int tegra_mipi_wait(struct tegra_mipi *mipi)
 162{
 163        unsigned long timeout = jiffies + msecs_to_jiffies(250);
 164        unsigned long value;
 165
 166        while (time_before(jiffies, timeout)) {
 167                value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS);
 168                if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 &&
 169                    (value & MIPI_CAL_STATUS_DONE) != 0)
 170                        return 0;
 171
 172                usleep_range(10, 50);
 173        }
 174
 175        return -ETIMEDOUT;
 176}
 177
 178int tegra_mipi_calibrate(struct tegra_mipi_device *device)
 179{
 180        unsigned long value;
 181        unsigned int i;
 182        int err;
 183
 184        err = clk_enable(device->mipi->clk);
 185        if (err < 0)
 186                return err;
 187
 188        mutex_lock(&device->mipi->lock);
 189
 190        value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0);
 191        value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
 192        value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
 193        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
 194
 195        value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
 196        value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
 197        tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
 198
 199        for (i = 0; i < ARRAY_SIZE(modules); i++) {
 200                if (device->pads & BIT(i))
 201                        value = MIPI_CAL_CONFIG_SELECT |
 202                                MIPI_CAL_CONFIG_HSPDOS(0) |
 203                                MIPI_CAL_CONFIG_HSPUOS(4) |
 204                                MIPI_CAL_CONFIG_TERMOS(5);
 205                else
 206                        value = 0;
 207
 208                tegra_mipi_writel(device->mipi, value, modules[i].reg);
 209        }
 210
 211        tegra_mipi_writel(device->mipi, MIPI_CAL_CTRL_START, MIPI_CAL_CTRL);
 212
 213        err = tegra_mipi_wait(device->mipi);
 214
 215        mutex_unlock(&device->mipi->lock);
 216        clk_disable(device->mipi->clk);
 217
 218        return err;
 219}
 220EXPORT_SYMBOL(tegra_mipi_calibrate);
 221
 222static int tegra_mipi_probe(struct platform_device *pdev)
 223{
 224        struct tegra_mipi *mipi;
 225        struct resource *res;
 226        int err;
 227
 228        mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL);
 229        if (!mipi)
 230                return -ENOMEM;
 231
 232        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 233        mipi->regs = devm_ioremap_resource(&pdev->dev, res);
 234        if (IS_ERR(mipi->regs))
 235                return PTR_ERR(mipi->regs);
 236
 237        mutex_init(&mipi->lock);
 238
 239        mipi->clk = devm_clk_get(&pdev->dev, NULL);
 240        if (IS_ERR(mipi->clk)) {
 241                dev_err(&pdev->dev, "failed to get clock\n");
 242                return PTR_ERR(mipi->clk);
 243        }
 244
 245        err = clk_prepare(mipi->clk);
 246        if (err < 0)
 247                return err;
 248
 249        platform_set_drvdata(pdev, mipi);
 250
 251        return 0;
 252}
 253
 254static int tegra_mipi_remove(struct platform_device *pdev)
 255{
 256        struct tegra_mipi *mipi = platform_get_drvdata(pdev);
 257
 258        clk_unprepare(mipi->clk);
 259
 260        return 0;
 261}
 262
 263static struct of_device_id tegra_mipi_of_match[] = {
 264        { .compatible = "nvidia,tegra114-mipi", },
 265        { },
 266};
 267
 268struct platform_driver tegra_mipi_driver = {
 269        .driver = {
 270                .name = "tegra-mipi",
 271                .of_match_table = tegra_mipi_of_match,
 272        },
 273        .probe = tegra_mipi_probe,
 274        .remove = tegra_mipi_remove,
 275};
 276