linux/drivers/media/platform/s5p-fimc/mipi-csis.c
<<
>>
Prefs
   1/*
   2 * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
   3 *
   4 * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
   5 * Sylwester Nawrocki <s.nawrocki@samsung.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/clk.h>
  13#include <linux/delay.h>
  14#include <linux/device.h>
  15#include <linux/errno.h>
  16#include <linux/interrupt.h>
  17#include <linux/io.h>
  18#include <linux/irq.h>
  19#include <linux/kernel.h>
  20#include <linux/memory.h>
  21#include <linux/module.h>
  22#include <linux/platform_device.h>
  23#include <linux/pm_runtime.h>
  24#include <linux/regulator/consumer.h>
  25#include <linux/slab.h>
  26#include <linux/spinlock.h>
  27#include <linux/videodev2.h>
  28#include <media/v4l2-subdev.h>
  29#include <linux/platform_data/mipi-csis.h>
  30#include "mipi-csis.h"
  31
  32static int debug;
  33module_param(debug, int, 0644);
  34MODULE_PARM_DESC(debug, "Debug level (0-2)");
  35
  36/* Register map definition */
  37
  38/* CSIS global control */
  39#define S5PCSIS_CTRL                    0x00
  40#define S5PCSIS_CTRL_DPDN_DEFAULT       (0 << 31)
  41#define S5PCSIS_CTRL_DPDN_SWAP          (1 << 31)
  42#define S5PCSIS_CTRL_ALIGN_32BIT        (1 << 20)
  43#define S5PCSIS_CTRL_UPDATE_SHADOW      (1 << 16)
  44#define S5PCSIS_CTRL_WCLK_EXTCLK        (1 << 8)
  45#define S5PCSIS_CTRL_RESET              (1 << 4)
  46#define S5PCSIS_CTRL_ENABLE             (1 << 0)
  47
  48/* D-PHY control */
  49#define S5PCSIS_DPHYCTRL                0x04
  50#define S5PCSIS_DPHYCTRL_HSS_MASK       (0x1f << 27)
  51#define S5PCSIS_DPHYCTRL_ENABLE         (0x1f << 0)
  52
  53#define S5PCSIS_CONFIG                  0x08
  54#define S5PCSIS_CFG_FMT_YCBCR422_8BIT   (0x1e << 2)
  55#define S5PCSIS_CFG_FMT_RAW8            (0x2a << 2)
  56#define S5PCSIS_CFG_FMT_RAW10           (0x2b << 2)
  57#define S5PCSIS_CFG_FMT_RAW12           (0x2c << 2)
  58/* User defined formats, x = 1...4 */
  59#define S5PCSIS_CFG_FMT_USER(x)         ((0x30 + x - 1) << 2)
  60#define S5PCSIS_CFG_FMT_MASK            (0x3f << 2)
  61#define S5PCSIS_CFG_NR_LANE_MASK        3
  62
  63/* Interrupt mask */
  64#define S5PCSIS_INTMSK                  0x10
  65#define S5PCSIS_INTMSK_EN_ALL           0xf000103f
  66#define S5PCSIS_INTMSK_EVEN_BEFORE      (1 << 31)
  67#define S5PCSIS_INTMSK_EVEN_AFTER       (1 << 30)
  68#define S5PCSIS_INTMSK_ODD_BEFORE       (1 << 29)
  69#define S5PCSIS_INTMSK_ODD_AFTER        (1 << 28)
  70#define S5PCSIS_INTMSK_ERR_SOT_HS       (1 << 12)
  71#define S5PCSIS_INTMSK_ERR_LOST_FS      (1 << 5)
  72#define S5PCSIS_INTMSK_ERR_LOST_FE      (1 << 4)
  73#define S5PCSIS_INTMSK_ERR_OVER         (1 << 3)
  74#define S5PCSIS_INTMSK_ERR_ECC          (1 << 2)
  75#define S5PCSIS_INTMSK_ERR_CRC          (1 << 1)
  76#define S5PCSIS_INTMSK_ERR_UNKNOWN      (1 << 0)
  77
  78/* Interrupt source */
  79#define S5PCSIS_INTSRC                  0x14
  80#define S5PCSIS_INTSRC_EVEN_BEFORE      (1 << 31)
  81#define S5PCSIS_INTSRC_EVEN_AFTER       (1 << 30)
  82#define S5PCSIS_INTSRC_EVEN             (0x3 << 30)
  83#define S5PCSIS_INTSRC_ODD_BEFORE       (1 << 29)
  84#define S5PCSIS_INTSRC_ODD_AFTER        (1 << 28)
  85#define S5PCSIS_INTSRC_ODD              (0x3 << 28)
  86#define S5PCSIS_INTSRC_NON_IMAGE_DATA   (0xff << 28)
  87#define S5PCSIS_INTSRC_ERR_SOT_HS       (0xf << 12)
  88#define S5PCSIS_INTSRC_ERR_LOST_FS      (1 << 5)
  89#define S5PCSIS_INTSRC_ERR_LOST_FE      (1 << 4)
  90#define S5PCSIS_INTSRC_ERR_OVER         (1 << 3)
  91#define S5PCSIS_INTSRC_ERR_ECC          (1 << 2)
  92#define S5PCSIS_INTSRC_ERR_CRC          (1 << 1)
  93#define S5PCSIS_INTSRC_ERR_UNKNOWN      (1 << 0)
  94#define S5PCSIS_INTSRC_ERRORS           0xf03f
  95
  96/* Pixel resolution */
  97#define S5PCSIS_RESOL                   0x2c
  98#define CSIS_MAX_PIX_WIDTH              0xffff
  99#define CSIS_MAX_PIX_HEIGHT             0xffff
 100
 101/* Non-image packet data buffers */
 102#define S5PCSIS_PKTDATA_ODD             0x2000
 103#define S5PCSIS_PKTDATA_EVEN            0x3000
 104#define S5PCSIS_PKTDATA_SIZE            SZ_4K
 105
 106enum {
 107        CSIS_CLK_MUX,
 108        CSIS_CLK_GATE,
 109};
 110
 111static char *csi_clock_name[] = {
 112        [CSIS_CLK_MUX]  = "sclk_csis",
 113        [CSIS_CLK_GATE] = "csis",
 114};
 115#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name)
 116
 117static const char * const csis_supply_name[] = {
 118        "vddcore",  /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */
 119        "vddio",    /* CSIS I/O and PLL (1.8V) supply */
 120};
 121#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name)
 122
 123enum {
 124        ST_POWERED      = 1,
 125        ST_STREAMING    = 2,
 126        ST_SUSPENDED    = 4,
 127};
 128
 129struct s5pcsis_event {
 130        u32 mask;
 131        const char * const name;
 132        unsigned int counter;
 133};
 134
 135static const struct s5pcsis_event s5pcsis_events[] = {
 136        /* Errors */
 137        { S5PCSIS_INTSRC_ERR_SOT_HS,    "SOT Error" },
 138        { S5PCSIS_INTSRC_ERR_LOST_FS,   "Lost Frame Start Error" },
 139        { S5PCSIS_INTSRC_ERR_LOST_FE,   "Lost Frame End Error" },
 140        { S5PCSIS_INTSRC_ERR_OVER,      "FIFO Overflow Error" },
 141        { S5PCSIS_INTSRC_ERR_ECC,       "ECC Error" },
 142        { S5PCSIS_INTSRC_ERR_CRC,       "CRC Error" },
 143        { S5PCSIS_INTSRC_ERR_UNKNOWN,   "Unknown Error" },
 144        /* Non-image data receive events */
 145        { S5PCSIS_INTSRC_EVEN_BEFORE,   "Non-image data before even frame" },
 146        { S5PCSIS_INTSRC_EVEN_AFTER,    "Non-image data after even frame" },
 147        { S5PCSIS_INTSRC_ODD_BEFORE,    "Non-image data before odd frame" },
 148        { S5PCSIS_INTSRC_ODD_AFTER,     "Non-image data after odd frame" },
 149};
 150#define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events)
 151
 152struct csis_pktbuf {
 153        u32 *data;
 154        unsigned int len;
 155};
 156
 157/**
 158 * struct csis_state - the driver's internal state data structure
 159 * @lock: mutex serializing the subdev and power management operations,
 160 *        protecting @format and @flags members
 161 * @pads: CSIS pads array
 162 * @sd: v4l2_subdev associated with CSIS device instance
 163 * @index: the hardware instance index
 164 * @pdev: CSIS platform device
 165 * @regs: mmaped I/O registers memory
 166 * @supplies: CSIS regulator supplies
 167 * @clock: CSIS clocks
 168 * @irq: requested s5p-mipi-csis irq number
 169 * @flags: the state variable for power and streaming control
 170 * @csis_fmt: current CSIS pixel format
 171 * @format: common media bus format for the source and sink pad
 172 * @slock: spinlock protecting structure members below
 173 * @pkt_buf: the frame embedded (non-image) data buffer
 174 * @events: MIPI-CSIS event (error) counters
 175 */
 176struct csis_state {
 177        struct mutex lock;
 178        struct media_pad pads[CSIS_PADS_NUM];
 179        struct v4l2_subdev sd;
 180        u8 index;
 181        struct platform_device *pdev;
 182        void __iomem *regs;
 183        struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
 184        struct clk *clock[NUM_CSIS_CLOCKS];
 185        int irq;
 186        u32 flags;
 187        const struct csis_pix_format *csis_fmt;
 188        struct v4l2_mbus_framefmt format;
 189
 190        spinlock_t slock;
 191        struct csis_pktbuf pkt_buf;
 192        struct s5pcsis_event events[S5PCSIS_NUM_EVENTS];
 193};
 194
 195/**
 196 * struct csis_pix_format - CSIS pixel format description
 197 * @pix_width_alignment: horizontal pixel alignment, width will be
 198 *                       multiple of 2^pix_width_alignment
 199 * @code: corresponding media bus code
 200 * @fmt_reg: S5PCSIS_CONFIG register value
 201 * @data_alignment: MIPI-CSI data alignment in bits
 202 */
 203struct csis_pix_format {
 204        unsigned int pix_width_alignment;
 205        enum v4l2_mbus_pixelcode code;
 206        u32 fmt_reg;
 207        u8 data_alignment;
 208};
 209
 210static const struct csis_pix_format s5pcsis_formats[] = {
 211        {
 212                .code = V4L2_MBUS_FMT_VYUY8_2X8,
 213                .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
 214                .data_alignment = 32,
 215        }, {
 216                .code = V4L2_MBUS_FMT_JPEG_1X8,
 217                .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
 218                .data_alignment = 32,
 219        }, {
 220                .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8,
 221                .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
 222                .data_alignment = 32,
 223        }, {
 224                .code = V4L2_MBUS_FMT_SGRBG8_1X8,
 225                .fmt_reg = S5PCSIS_CFG_FMT_RAW8,
 226                .data_alignment = 24,
 227        }, {
 228                .code = V4L2_MBUS_FMT_SGRBG10_1X10,
 229                .fmt_reg = S5PCSIS_CFG_FMT_RAW10,
 230                .data_alignment = 24,
 231        }, {
 232                .code = V4L2_MBUS_FMT_SGRBG12_1X12,
 233                .fmt_reg = S5PCSIS_CFG_FMT_RAW12,
 234                .data_alignment = 24,
 235        }
 236};
 237
 238#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
 239#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r)
 240
 241static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev)
 242{
 243        return container_of(sdev, struct csis_state, sd);
 244}
 245
 246static const struct csis_pix_format *find_csis_format(
 247        struct v4l2_mbus_framefmt *mf)
 248{
 249        int i;
 250
 251        for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++)
 252                if (mf->code == s5pcsis_formats[i].code)
 253                        return &s5pcsis_formats[i];
 254        return NULL;
 255}
 256
 257static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
 258{
 259        u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
 260
 261        val = on ? val | S5PCSIS_INTMSK_EN_ALL :
 262                   val & ~S5PCSIS_INTMSK_EN_ALL;
 263        s5pcsis_write(state, S5PCSIS_INTMSK, val);
 264}
 265
 266static void s5pcsis_reset(struct csis_state *state)
 267{
 268        u32 val = s5pcsis_read(state, S5PCSIS_CTRL);
 269
 270        s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET);
 271        udelay(10);
 272}
 273
 274static void s5pcsis_system_enable(struct csis_state *state, int on)
 275{
 276        struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
 277        u32 val, mask;
 278
 279        val = s5pcsis_read(state, S5PCSIS_CTRL);
 280        if (on)
 281                val |= S5PCSIS_CTRL_ENABLE;
 282        else
 283                val &= ~S5PCSIS_CTRL_ENABLE;
 284        s5pcsis_write(state, S5PCSIS_CTRL, val);
 285
 286        val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
 287        val &= ~S5PCSIS_DPHYCTRL_ENABLE;
 288        if (on) {
 289                mask = (1 << (pdata->lanes + 1)) - 1;
 290                val |= (mask & S5PCSIS_DPHYCTRL_ENABLE);
 291        }
 292        s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
 293}
 294
 295/* Called with the state.lock mutex held */
 296static void __s5pcsis_set_format(struct csis_state *state)
 297{
 298        struct v4l2_mbus_framefmt *mf = &state->format;
 299        u32 val;
 300
 301        v4l2_dbg(1, debug, &state->sd, "fmt: %#x, %d x %d\n",
 302                 mf->code, mf->width, mf->height);
 303
 304        /* Color format */
 305        val = s5pcsis_read(state, S5PCSIS_CONFIG);
 306        val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg;
 307        s5pcsis_write(state, S5PCSIS_CONFIG, val);
 308
 309        /* Pixel resolution */
 310        val = (mf->width << 16) | mf->height;
 311        s5pcsis_write(state, S5PCSIS_RESOL, val);
 312}
 313
 314static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
 315{
 316        u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
 317
 318        val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27);
 319        s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
 320}
 321
 322static void s5pcsis_set_params(struct csis_state *state)
 323{
 324        struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
 325        u32 val;
 326
 327        val = s5pcsis_read(state, S5PCSIS_CONFIG);
 328        val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1);
 329        s5pcsis_write(state, S5PCSIS_CONFIG, val);
 330
 331        __s5pcsis_set_format(state);
 332        s5pcsis_set_hsync_settle(state, pdata->hs_settle);
 333
 334        val = s5pcsis_read(state, S5PCSIS_CTRL);
 335        if (state->csis_fmt->data_alignment == 32)
 336                val |= S5PCSIS_CTRL_ALIGN_32BIT;
 337        else /* 24-bits */
 338                val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
 339
 340        val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
 341        if (pdata->wclk_source)
 342                val |= S5PCSIS_CTRL_WCLK_EXTCLK;
 343        s5pcsis_write(state, S5PCSIS_CTRL, val);
 344
 345        /* Update the shadow register. */
 346        val = s5pcsis_read(state, S5PCSIS_CTRL);
 347        s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW);
 348}
 349
 350static void s5pcsis_clk_put(struct csis_state *state)
 351{
 352        int i;
 353
 354        for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
 355                if (IS_ERR(state->clock[i]))
 356                        continue;
 357                clk_unprepare(state->clock[i]);
 358                clk_put(state->clock[i]);
 359                state->clock[i] = ERR_PTR(-EINVAL);
 360        }
 361}
 362
 363static int s5pcsis_clk_get(struct csis_state *state)
 364{
 365        struct device *dev = &state->pdev->dev;
 366        int i, ret;
 367
 368        for (i = 0; i < NUM_CSIS_CLOCKS; i++)
 369                state->clock[i] = ERR_PTR(-EINVAL);
 370
 371        for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
 372                state->clock[i] = clk_get(dev, csi_clock_name[i]);
 373                if (IS_ERR(state->clock[i])) {
 374                        ret = PTR_ERR(state->clock[i]);
 375                        goto err;
 376                }
 377                ret = clk_prepare(state->clock[i]);
 378                if (ret < 0) {
 379                        clk_put(state->clock[i]);
 380                        state->clock[i] = ERR_PTR(-EINVAL);
 381                        goto err;
 382                }
 383        }
 384        return 0;
 385err:
 386        s5pcsis_clk_put(state);
 387        dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]);
 388        return ret;
 389}
 390
 391static void dump_regs(struct csis_state *state, const char *label)
 392{
 393        struct {
 394                u32 offset;
 395                const char * const name;
 396        } registers[] = {
 397                { 0x00, "CTRL" },
 398                { 0x04, "DPHYCTRL" },
 399                { 0x08, "CONFIG" },
 400                { 0x0c, "DPHYSTS" },
 401                { 0x10, "INTMSK" },
 402                { 0x2c, "RESOL" },
 403                { 0x38, "SDW_CONFIG" },
 404        };
 405        u32 i;
 406
 407        v4l2_info(&state->sd, "--- %s ---\n", label);
 408
 409        for (i = 0; i < ARRAY_SIZE(registers); i++) {
 410                u32 cfg = s5pcsis_read(state, registers[i].offset);
 411                v4l2_info(&state->sd, "%10s: 0x%08x\n", registers[i].name, cfg);
 412        }
 413}
 414
 415static void s5pcsis_start_stream(struct csis_state *state)
 416{
 417        s5pcsis_reset(state);
 418        s5pcsis_set_params(state);
 419        s5pcsis_system_enable(state, true);
 420        s5pcsis_enable_interrupts(state, true);
 421}
 422
 423static void s5pcsis_stop_stream(struct csis_state *state)
 424{
 425        s5pcsis_enable_interrupts(state, false);
 426        s5pcsis_system_enable(state, false);
 427}
 428
 429static void s5pcsis_clear_counters(struct csis_state *state)
 430{
 431        unsigned long flags;
 432        int i;
 433
 434        spin_lock_irqsave(&state->slock, flags);
 435        for (i = 0; i < S5PCSIS_NUM_EVENTS; i++)
 436                state->events[i].counter = 0;
 437        spin_unlock_irqrestore(&state->slock, flags);
 438}
 439
 440static void s5pcsis_log_counters(struct csis_state *state, bool non_errors)
 441{
 442        int i = non_errors ? S5PCSIS_NUM_EVENTS : S5PCSIS_NUM_EVENTS - 4;
 443        unsigned long flags;
 444
 445        spin_lock_irqsave(&state->slock, flags);
 446
 447        for (i--; i >= 0; i--) {
 448                if (state->events[i].counter > 0 || debug)
 449                        v4l2_info(&state->sd, "%s events: %d\n",
 450                                  state->events[i].name,
 451                                  state->events[i].counter);
 452        }
 453        spin_unlock_irqrestore(&state->slock, flags);
 454}
 455
 456/*
 457 * V4L2 subdev operations
 458 */
 459static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
 460{
 461        struct csis_state *state = sd_to_csis_state(sd);
 462        struct device *dev = &state->pdev->dev;
 463
 464        if (on)
 465                return pm_runtime_get_sync(dev);
 466
 467        return pm_runtime_put_sync(dev);
 468}
 469
 470static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
 471{
 472        struct csis_state *state = sd_to_csis_state(sd);
 473        int ret = 0;
 474
 475        v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n",
 476                 __func__, enable, state->flags);
 477
 478        if (enable) {
 479                s5pcsis_clear_counters(state);
 480                ret = pm_runtime_get_sync(&state->pdev->dev);
 481                if (ret && ret != 1)
 482                        return ret;
 483        }
 484
 485        mutex_lock(&state->lock);
 486        if (enable) {
 487                if (state->flags & ST_SUSPENDED) {
 488                        ret = -EBUSY;
 489                        goto unlock;
 490                }
 491                s5pcsis_start_stream(state);
 492                state->flags |= ST_STREAMING;
 493        } else {
 494                s5pcsis_stop_stream(state);
 495                state->flags &= ~ST_STREAMING;
 496                if (debug > 0)
 497                        s5pcsis_log_counters(state, true);
 498        }
 499unlock:
 500        mutex_unlock(&state->lock);
 501        if (!enable)
 502                pm_runtime_put(&state->pdev->dev);
 503
 504        return ret == 1 ? 0 : ret;
 505}
 506
 507static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
 508                                  struct v4l2_subdev_fh *fh,
 509                                  struct v4l2_subdev_mbus_code_enum *code)
 510{
 511        if (code->index >= ARRAY_SIZE(s5pcsis_formats))
 512                return -EINVAL;
 513
 514        code->code = s5pcsis_formats[code->index].code;
 515        return 0;
 516}
 517
 518static struct csis_pix_format const *s5pcsis_try_format(
 519        struct v4l2_mbus_framefmt *mf)
 520{
 521        struct csis_pix_format const *csis_fmt;
 522
 523        csis_fmt = find_csis_format(mf);
 524        if (csis_fmt == NULL)
 525                csis_fmt = &s5pcsis_formats[0];
 526
 527        mf->code = csis_fmt->code;
 528        v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
 529                              csis_fmt->pix_width_alignment,
 530                              &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
 531                              0);
 532        return csis_fmt;
 533}
 534
 535static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
 536                struct csis_state *state, struct v4l2_subdev_fh *fh,
 537                u32 pad, enum v4l2_subdev_format_whence which)
 538{
 539        if (which == V4L2_SUBDEV_FORMAT_TRY)
 540                return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
 541
 542        return &state->format;
 543}
 544
 545static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 546                           struct v4l2_subdev_format *fmt)
 547{
 548        struct csis_state *state = sd_to_csis_state(sd);
 549        struct csis_pix_format const *csis_fmt;
 550        struct v4l2_mbus_framefmt *mf;
 551
 552        if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
 553                return -EINVAL;
 554
 555        mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
 556
 557        if (fmt->pad == CSIS_PAD_SOURCE) {
 558                if (mf) {
 559                        mutex_lock(&state->lock);
 560                        fmt->format = *mf;
 561                        mutex_unlock(&state->lock);
 562                }
 563                return 0;
 564        }
 565        csis_fmt = s5pcsis_try_format(&fmt->format);
 566        if (mf) {
 567                mutex_lock(&state->lock);
 568                *mf = fmt->format;
 569                if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 570                        state->csis_fmt = csis_fmt;
 571                mutex_unlock(&state->lock);
 572        }
 573        return 0;
 574}
 575
 576static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 577                           struct v4l2_subdev_format *fmt)
 578{
 579        struct csis_state *state = sd_to_csis_state(sd);
 580        struct v4l2_mbus_framefmt *mf;
 581
 582        if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
 583                return -EINVAL;
 584
 585        mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
 586        if (!mf)
 587                return -EINVAL;
 588
 589        mutex_lock(&state->lock);
 590        fmt->format = *mf;
 591        mutex_unlock(&state->lock);
 592        return 0;
 593}
 594
 595static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf,
 596                               unsigned int *size)
 597{
 598        struct csis_state *state = sd_to_csis_state(sd);
 599        unsigned long flags;
 600
 601        *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE);
 602
 603        spin_lock_irqsave(&state->slock, flags);
 604        state->pkt_buf.data = buf;
 605        state->pkt_buf.len = *size;
 606        spin_unlock_irqrestore(&state->slock, flags);
 607
 608        return 0;
 609}
 610
 611static int s5pcsis_log_status(struct v4l2_subdev *sd)
 612{
 613        struct csis_state *state = sd_to_csis_state(sd);
 614
 615        mutex_lock(&state->lock);
 616        s5pcsis_log_counters(state, true);
 617        if (debug && (state->flags & ST_POWERED))
 618                dump_regs(state, __func__);
 619        mutex_unlock(&state->lock);
 620        return 0;
 621}
 622
 623static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 624{
 625        struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
 626
 627        format->colorspace = V4L2_COLORSPACE_JPEG;
 628        format->code = s5pcsis_formats[0].code;
 629        format->width = S5PCSIS_DEF_PIX_WIDTH;
 630        format->height = S5PCSIS_DEF_PIX_HEIGHT;
 631        format->field = V4L2_FIELD_NONE;
 632
 633        return 0;
 634}
 635
 636static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = {
 637        .open = s5pcsis_open,
 638};
 639
 640static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
 641        .s_power = s5pcsis_s_power,
 642        .log_status = s5pcsis_log_status,
 643};
 644
 645static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
 646        .enum_mbus_code = s5pcsis_enum_mbus_code,
 647        .get_fmt = s5pcsis_get_fmt,
 648        .set_fmt = s5pcsis_set_fmt,
 649};
 650
 651static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
 652        .s_rx_buffer = s5pcsis_s_rx_buffer,
 653        .s_stream = s5pcsis_s_stream,
 654};
 655
 656static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
 657        .core = &s5pcsis_core_ops,
 658        .pad = &s5pcsis_pad_ops,
 659        .video = &s5pcsis_video_ops,
 660};
 661
 662static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
 663{
 664        struct csis_state *state = dev_id;
 665        struct csis_pktbuf *pktbuf = &state->pkt_buf;
 666        unsigned long flags;
 667        u32 status;
 668
 669        status = s5pcsis_read(state, S5PCSIS_INTSRC);
 670        spin_lock_irqsave(&state->slock, flags);
 671
 672        if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) {
 673                u32 offset;
 674
 675                if (status & S5PCSIS_INTSRC_EVEN)
 676                        offset = S5PCSIS_PKTDATA_EVEN;
 677                else
 678                        offset = S5PCSIS_PKTDATA_ODD;
 679
 680                memcpy(pktbuf->data, state->regs + offset, pktbuf->len);
 681                pktbuf->data = NULL;
 682                rmb();
 683        }
 684
 685        /* Update the event/error counters */
 686        if ((status & S5PCSIS_INTSRC_ERRORS) || debug) {
 687                int i;
 688                for (i = 0; i < S5PCSIS_NUM_EVENTS; i++) {
 689                        if (!(status & state->events[i].mask))
 690                                continue;
 691                        state->events[i].counter++;
 692                        v4l2_dbg(2, debug, &state->sd, "%s: %d\n",
 693                                 state->events[i].name,
 694                                 state->events[i].counter);
 695                }
 696                v4l2_dbg(2, debug, &state->sd, "status: %08x\n", status);
 697        }
 698        spin_unlock_irqrestore(&state->slock, flags);
 699
 700        s5pcsis_write(state, S5PCSIS_INTSRC, status);
 701        return IRQ_HANDLED;
 702}
 703
 704static int s5pcsis_probe(struct platform_device *pdev)
 705{
 706        struct s5p_platform_mipi_csis *pdata;
 707        struct resource *mem_res;
 708        struct csis_state *state;
 709        int ret = -ENOMEM;
 710        int i;
 711
 712        state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
 713        if (!state)
 714                return -ENOMEM;
 715
 716        mutex_init(&state->lock);
 717        spin_lock_init(&state->slock);
 718
 719        state->pdev = pdev;
 720        state->index = max(0, pdev->id);
 721
 722        pdata = pdev->dev.platform_data;
 723        if (pdata == NULL) {
 724                dev_err(&pdev->dev, "Platform data not fully specified\n");
 725                return -EINVAL;
 726        }
 727
 728        if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
 729            pdata->lanes > CSIS0_MAX_LANES) {
 730                dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
 731                        pdata->lanes);
 732                return -EINVAL;
 733        }
 734
 735        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 736        state->regs = devm_ioremap_resource(&pdev->dev, mem_res);
 737        if (IS_ERR(state->regs))
 738                return PTR_ERR(state->regs);
 739
 740        state->irq = platform_get_irq(pdev, 0);
 741        if (state->irq < 0) {
 742                dev_err(&pdev->dev, "Failed to get irq\n");
 743                return state->irq;
 744        }
 745
 746        for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
 747                state->supplies[i].supply = csis_supply_name[i];
 748
 749        ret = devm_regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
 750                                 state->supplies);
 751        if (ret)
 752                return ret;
 753
 754        ret = s5pcsis_clk_get(state);
 755        if (ret < 0)
 756                return ret;
 757
 758        if (pdata->clk_rate)
 759                ret = clk_set_rate(state->clock[CSIS_CLK_MUX],
 760                                   pdata->clk_rate);
 761        else
 762                dev_WARN(&pdev->dev, "No clock frequency specified!\n");
 763        if (ret < 0)
 764                goto e_clkput;
 765
 766        ret = clk_enable(state->clock[CSIS_CLK_MUX]);
 767        if (ret < 0)
 768                goto e_clkput;
 769
 770        ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
 771                               0, dev_name(&pdev->dev), state);
 772        if (ret) {
 773                dev_err(&pdev->dev, "Interrupt request failed\n");
 774                goto e_clkdis;
 775        }
 776
 777        v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
 778        state->sd.owner = THIS_MODULE;
 779        strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
 780        state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 781        state->csis_fmt = &s5pcsis_formats[0];
 782
 783        state->format.code = s5pcsis_formats[0].code;
 784        state->format.width = S5PCSIS_DEF_PIX_WIDTH;
 785        state->format.height = S5PCSIS_DEF_PIX_HEIGHT;
 786
 787        state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
 788        state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
 789        ret = media_entity_init(&state->sd.entity,
 790                                CSIS_PADS_NUM, state->pads, 0);
 791        if (ret < 0)
 792                goto e_clkdis;
 793
 794        /* This allows to retrieve the platform device id by the host driver */
 795        v4l2_set_subdevdata(&state->sd, pdev);
 796
 797        /* .. and a pointer to the subdev. */
 798        platform_set_drvdata(pdev, &state->sd);
 799
 800        memcpy(state->events, s5pcsis_events, sizeof(state->events));
 801
 802        pm_runtime_enable(&pdev->dev);
 803        return 0;
 804
 805e_clkdis:
 806        clk_disable(state->clock[CSIS_CLK_MUX]);
 807e_clkput:
 808        s5pcsis_clk_put(state);
 809        return ret;
 810}
 811
 812static int s5pcsis_pm_suspend(struct device *dev, bool runtime)
 813{
 814        struct platform_device *pdev = to_platform_device(dev);
 815        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 816        struct csis_state *state = sd_to_csis_state(sd);
 817        int ret = 0;
 818
 819        v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
 820                 __func__, state->flags);
 821
 822        mutex_lock(&state->lock);
 823        if (state->flags & ST_POWERED) {
 824                s5pcsis_stop_stream(state);
 825                ret = s5p_csis_phy_enable(state->index, false);
 826                if (ret)
 827                        goto unlock;
 828                ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES,
 829                                             state->supplies);
 830                if (ret)
 831                        goto unlock;
 832                clk_disable(state->clock[CSIS_CLK_GATE]);
 833                state->flags &= ~ST_POWERED;
 834                if (!runtime)
 835                        state->flags |= ST_SUSPENDED;
 836        }
 837 unlock:
 838        mutex_unlock(&state->lock);
 839        return ret ? -EAGAIN : 0;
 840}
 841
 842static int s5pcsis_pm_resume(struct device *dev, bool runtime)
 843{
 844        struct platform_device *pdev = to_platform_device(dev);
 845        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 846        struct csis_state *state = sd_to_csis_state(sd);
 847        int ret = 0;
 848
 849        v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
 850                 __func__, state->flags);
 851
 852        mutex_lock(&state->lock);
 853        if (!runtime && !(state->flags & ST_SUSPENDED))
 854                goto unlock;
 855
 856        if (!(state->flags & ST_POWERED)) {
 857                ret = regulator_bulk_enable(CSIS_NUM_SUPPLIES,
 858                                            state->supplies);
 859                if (ret)
 860                        goto unlock;
 861                ret = s5p_csis_phy_enable(state->index, true);
 862                if (!ret) {
 863                        state->flags |= ST_POWERED;
 864                } else {
 865                        regulator_bulk_disable(CSIS_NUM_SUPPLIES,
 866                                               state->supplies);
 867                        goto unlock;
 868                }
 869                clk_enable(state->clock[CSIS_CLK_GATE]);
 870        }
 871        if (state->flags & ST_STREAMING)
 872                s5pcsis_start_stream(state);
 873
 874        state->flags &= ~ST_SUSPENDED;
 875 unlock:
 876        mutex_unlock(&state->lock);
 877        return ret ? -EAGAIN : 0;
 878}
 879
 880#ifdef CONFIG_PM_SLEEP
 881static int s5pcsis_suspend(struct device *dev)
 882{
 883        return s5pcsis_pm_suspend(dev, false);
 884}
 885
 886static int s5pcsis_resume(struct device *dev)
 887{
 888        return s5pcsis_pm_resume(dev, false);
 889}
 890#endif
 891
 892#ifdef CONFIG_PM_RUNTIME
 893static int s5pcsis_runtime_suspend(struct device *dev)
 894{
 895        return s5pcsis_pm_suspend(dev, true);
 896}
 897
 898static int s5pcsis_runtime_resume(struct device *dev)
 899{
 900        return s5pcsis_pm_resume(dev, true);
 901}
 902#endif
 903
 904static int s5pcsis_remove(struct platform_device *pdev)
 905{
 906        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 907        struct csis_state *state = sd_to_csis_state(sd);
 908
 909        pm_runtime_disable(&pdev->dev);
 910        s5pcsis_pm_suspend(&pdev->dev, false);
 911        clk_disable(state->clock[CSIS_CLK_MUX]);
 912        pm_runtime_set_suspended(&pdev->dev);
 913        s5pcsis_clk_put(state);
 914
 915        media_entity_cleanup(&state->sd.entity);
 916
 917        return 0;
 918}
 919
 920static const struct dev_pm_ops s5pcsis_pm_ops = {
 921        SET_RUNTIME_PM_OPS(s5pcsis_runtime_suspend, s5pcsis_runtime_resume,
 922                           NULL)
 923        SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume)
 924};
 925
 926static struct platform_driver s5pcsis_driver = {
 927        .probe          = s5pcsis_probe,
 928        .remove         = s5pcsis_remove,
 929        .driver         = {
 930                .name   = CSIS_DRIVER_NAME,
 931                .owner  = THIS_MODULE,
 932                .pm     = &s5pcsis_pm_ops,
 933        },
 934};
 935
 936module_platform_driver(s5pcsis_driver);
 937
 938MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
 939MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC MIPI-CSI2 receiver driver");
 940MODULE_LICENSE("GPL");
 941
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.