~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/media/video/s5p-fimc/mipi-csis.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
 
3
 *
 
4
 * Copyright (C) 2011 Samsung Electronics Co., Ltd.
 
5
 * Contact: 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 <plat/mipi_csis.h>
 
30
#include "mipi-csis.h"
 
31
 
 
32
static int debug;
 
33
module_param(debug, int, 0644);
 
34
MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
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           0xf000003f
 
66
#define S5PCSIS_INTSRC                  0x14
 
67
 
 
68
/* Pixel resolution */
 
69
#define S5PCSIS_RESOL                   0x2c
 
70
#define CSIS_MAX_PIX_WIDTH              0xffff
 
71
#define CSIS_MAX_PIX_HEIGHT             0xffff
 
72
 
 
73
enum {
 
74
        CSIS_CLK_MUX,
 
75
        CSIS_CLK_GATE,
 
76
};
 
77
 
 
78
static char *csi_clock_name[] = {
 
79
        [CSIS_CLK_MUX]  = "sclk_csis",
 
80
        [CSIS_CLK_GATE] = "csis",
 
81
};
 
82
#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name)
 
83
 
 
84
enum {
 
85
        ST_POWERED      = 1,
 
86
        ST_STREAMING    = 2,
 
87
        ST_SUSPENDED    = 4,
 
88
};
 
89
 
 
90
/**
 
91
 * struct csis_state - the driver's internal state data structure
 
92
 * @lock: mutex serializing the subdev and power management operations,
 
93
 *        protecting @format and @flags members
 
94
 * @pads: CSIS pads array
 
95
 * @sd: v4l2_subdev associated with CSIS device instance
 
96
 * @pdev: CSIS platform device
 
97
 * @regs_res: requested I/O register memory resource
 
98
 * @regs: mmaped I/O registers memory
 
99
 * @clock: CSIS clocks
 
100
 * @irq: requested s5p-mipi-csis irq number
 
101
 * @flags: the state variable for power and streaming control
 
102
 * @csis_fmt: current CSIS pixel format
 
103
 * @format: common media bus format for the source and sink pad
 
104
 */
 
105
struct csis_state {
 
106
        struct mutex lock;
 
107
        struct media_pad pads[CSIS_PADS_NUM];
 
108
        struct v4l2_subdev sd;
 
109
        struct platform_device *pdev;
 
110
        struct resource *regs_res;
 
111
        void __iomem *regs;
 
112
        struct clk *clock[NUM_CSIS_CLOCKS];
 
113
        int irq;
 
114
        struct regulator *supply;
 
115
        u32 flags;
 
116
        const struct csis_pix_format *csis_fmt;
 
117
        struct v4l2_mbus_framefmt format;
 
118
};
 
119
 
 
120
/**
 
121
 * struct csis_pix_format - CSIS pixel format description
 
122
 * @pix_width_alignment: horizontal pixel alignment, width will be
 
123
 *                       multiple of 2^pix_width_alignment
 
124
 * @code: corresponding media bus code
 
125
 * @fmt_reg: S5PCSIS_CONFIG register value
 
126
 */
 
127
struct csis_pix_format {
 
128
        unsigned int pix_width_alignment;
 
129
        enum v4l2_mbus_pixelcode code;
 
130
        u32 fmt_reg;
 
131
};
 
132
 
 
133
static const struct csis_pix_format s5pcsis_formats[] = {
 
134
        {
 
135
                .code = V4L2_MBUS_FMT_VYUY8_2X8,
 
136
                .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
 
137
        }, {
 
138
                .code = V4L2_MBUS_FMT_JPEG_1X8,
 
139
                .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
 
140
        },
 
141
};
 
142
 
 
143
#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
 
144
#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r)
 
145
 
 
146
static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev)
 
147
{
 
148
        return container_of(sdev, struct csis_state, sd);
 
149
}
 
150
 
 
151
static const struct csis_pix_format *find_csis_format(
 
152
        struct v4l2_mbus_framefmt *mf)
 
153
{
 
154
        int i;
 
155
 
 
156
        for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++)
 
157
                if (mf->code == s5pcsis_formats[i].code)
 
158
                        return &s5pcsis_formats[i];
 
159
        return NULL;
 
160
}
 
161
 
 
162
static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
 
163
{
 
164
        u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
 
165
 
 
166
        val = on ? val | S5PCSIS_INTMSK_EN_ALL :
 
167
                   val & ~S5PCSIS_INTMSK_EN_ALL;
 
168
        s5pcsis_write(state, S5PCSIS_INTMSK, val);
 
169
}
 
170
 
 
171
static void s5pcsis_reset(struct csis_state *state)
 
172
{
 
173
        u32 val = s5pcsis_read(state, S5PCSIS_CTRL);
 
174
 
 
175
        s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET);
 
176
        udelay(10);
 
177
}
 
178
 
 
179
static void s5pcsis_system_enable(struct csis_state *state, int on)
 
180
{
 
181
        u32 val;
 
182
 
 
183
        val = s5pcsis_read(state, S5PCSIS_CTRL);
 
184
        if (on)
 
185
                val |= S5PCSIS_CTRL_ENABLE;
 
186
        else
 
187
                val &= ~S5PCSIS_CTRL_ENABLE;
 
188
        s5pcsis_write(state, S5PCSIS_CTRL, val);
 
189
 
 
190
        val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
 
191
        if (on)
 
192
                val |= S5PCSIS_DPHYCTRL_ENABLE;
 
193
        else
 
194
                val &= ~S5PCSIS_DPHYCTRL_ENABLE;
 
195
        s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
 
196
}
 
197
 
 
198
/* Called with the state.lock mutex held */
 
199
static void __s5pcsis_set_format(struct csis_state *state)
 
200
{
 
201
        struct v4l2_mbus_framefmt *mf = &state->format;
 
202
        u32 val;
 
203
 
 
204
        v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n",
 
205
                 mf->code, mf->width, mf->height);
 
206
 
 
207
        /* Color format */
 
208
        val = s5pcsis_read(state, S5PCSIS_CONFIG);
 
209
        val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg;
 
210
        s5pcsis_write(state, S5PCSIS_CONFIG, val);
 
211
 
 
212
        /* Pixel resolution */
 
213
        val = (mf->width << 16) | mf->height;
 
214
        s5pcsis_write(state, S5PCSIS_RESOL, val);
 
215
}
 
216
 
 
217
static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
 
218
{
 
219
        u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
 
220
 
 
221
        val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27);
 
222
        s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
 
223
}
 
224
 
 
225
static void s5pcsis_set_params(struct csis_state *state)
 
226
{
 
227
        struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
 
228
        u32 val;
 
229
 
 
230
        val = s5pcsis_read(state, S5PCSIS_CONFIG);
 
231
        val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1);
 
232
        s5pcsis_write(state, S5PCSIS_CONFIG, val);
 
233
 
 
234
        __s5pcsis_set_format(state);
 
235
        s5pcsis_set_hsync_settle(state, pdata->hs_settle);
 
236
 
 
237
        val = s5pcsis_read(state, S5PCSIS_CTRL);
 
238
        if (pdata->alignment == 32)
 
239
                val |= S5PCSIS_CTRL_ALIGN_32BIT;
 
240
        else /* 24-bits */
 
241
                val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
 
242
        /* Not using external clock. */
 
243
        val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
 
244
        s5pcsis_write(state, S5PCSIS_CTRL, val);
 
245
 
 
246
        /* Update the shadow register. */
 
247
        val = s5pcsis_read(state, S5PCSIS_CTRL);
 
248
        s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW);
 
249
}
 
250
 
 
251
static void s5pcsis_clk_put(struct csis_state *state)
 
252
{
 
253
        int i;
 
254
 
 
255
        for (i = 0; i < NUM_CSIS_CLOCKS; i++)
 
256
                if (!IS_ERR_OR_NULL(state->clock[i]))
 
257
                        clk_put(state->clock[i]);
 
258
}
 
259
 
 
260
static int s5pcsis_clk_get(struct csis_state *state)
 
261
{
 
262
        struct device *dev = &state->pdev->dev;
 
263
        int i;
 
264
 
 
265
        for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
 
266
                state->clock[i] = clk_get(dev, csi_clock_name[i]);
 
267
                if (IS_ERR(state->clock[i])) {
 
268
                        s5pcsis_clk_put(state);
 
269
                        dev_err(dev, "failed to get clock: %s\n",
 
270
                                csi_clock_name[i]);
 
271
                        return -ENXIO;
 
272
                }
 
273
        }
 
274
        return 0;
 
275
}
 
276
 
 
277
static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
 
278
{
 
279
        struct csis_state *state = sd_to_csis_state(sd);
 
280
        struct device *dev = &state->pdev->dev;
 
281
 
 
282
        if (on)
 
283
                return pm_runtime_get_sync(dev);
 
284
 
 
285
        return pm_runtime_put_sync(dev);
 
286
}
 
287
 
 
288
static void s5pcsis_start_stream(struct csis_state *state)
 
289
{
 
290
        s5pcsis_reset(state);
 
291
        s5pcsis_set_params(state);
 
292
        s5pcsis_system_enable(state, true);
 
293
        s5pcsis_enable_interrupts(state, true);
 
294
}
 
295
 
 
296
static void s5pcsis_stop_stream(struct csis_state *state)
 
297
{
 
298
        s5pcsis_enable_interrupts(state, false);
 
299
        s5pcsis_system_enable(state, false);
 
300
}
 
301
 
 
302
/* v4l2_subdev operations */
 
303
static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
 
304
{
 
305
        struct csis_state *state = sd_to_csis_state(sd);
 
306
        int ret = 0;
 
307
 
 
308
        v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n",
 
309
                 __func__, enable, state->flags);
 
310
 
 
311
        if (enable) {
 
312
                ret = pm_runtime_get_sync(&state->pdev->dev);
 
313
                if (ret && ret != 1)
 
314
                        return ret;
 
315
        }
 
316
        mutex_lock(&state->lock);
 
317
        if (enable) {
 
318
                if (state->flags & ST_SUSPENDED) {
 
319
                        ret = -EBUSY;
 
320
                        goto unlock;
 
321
                }
 
322
                s5pcsis_start_stream(state);
 
323
                state->flags |= ST_STREAMING;
 
324
        } else {
 
325
                s5pcsis_stop_stream(state);
 
326
                state->flags &= ~ST_STREAMING;
 
327
        }
 
328
unlock:
 
329
        mutex_unlock(&state->lock);
 
330
        if (!enable)
 
331
                pm_runtime_put(&state->pdev->dev);
 
332
 
 
333
        return ret == 1 ? 0 : ret;
 
334
}
 
335
 
 
336
static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
 
337
                                  struct v4l2_subdev_fh *fh,
 
338
                                  struct v4l2_subdev_mbus_code_enum *code)
 
339
{
 
340
        if (code->index >= ARRAY_SIZE(s5pcsis_formats))
 
341
                return -EINVAL;
 
342
 
 
343
        code->code = s5pcsis_formats[code->index].code;
 
344
        return 0;
 
345
}
 
346
 
 
347
static struct csis_pix_format const *s5pcsis_try_format(
 
348
        struct v4l2_mbus_framefmt *mf)
 
349
{
 
350
        struct csis_pix_format const *csis_fmt;
 
351
 
 
352
        csis_fmt = find_csis_format(mf);
 
353
        if (csis_fmt == NULL)
 
354
                csis_fmt = &s5pcsis_formats[0];
 
355
 
 
356
        mf->code = csis_fmt->code;
 
357
        v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
 
358
                              csis_fmt->pix_width_alignment,
 
359
                              &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
 
360
                              0);
 
361
        return csis_fmt;
 
362
}
 
363
 
 
364
static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
 
365
                struct csis_state *state, struct v4l2_subdev_fh *fh,
 
366
                u32 pad, enum v4l2_subdev_format_whence which)
 
367
{
 
368
        if (which == V4L2_SUBDEV_FORMAT_TRY)
 
369
                return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
 
370
 
 
371
        return &state->format;
 
372
}
 
373
 
 
374
static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 
375
                           struct v4l2_subdev_format *fmt)
 
376
{
 
377
        struct csis_state *state = sd_to_csis_state(sd);
 
378
        struct csis_pix_format const *csis_fmt;
 
379
        struct v4l2_mbus_framefmt *mf;
 
380
 
 
381
        if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
 
382
                return -EINVAL;
 
383
 
 
384
        mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
 
385
 
 
386
        if (fmt->pad == CSIS_PAD_SOURCE) {
 
387
                if (mf) {
 
388
                        mutex_lock(&state->lock);
 
389
                        fmt->format = *mf;
 
390
                        mutex_unlock(&state->lock);
 
391
                }
 
392
                return 0;
 
393
        }
 
394
        csis_fmt = s5pcsis_try_format(&fmt->format);
 
395
        if (mf) {
 
396
                mutex_lock(&state->lock);
 
397
                *mf = fmt->format;
 
398
                if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 
399
                        state->csis_fmt = csis_fmt;
 
400
                mutex_unlock(&state->lock);
 
401
        }
 
402
        return 0;
 
403
}
 
404
 
 
405
static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 
406
                           struct v4l2_subdev_format *fmt)
 
407
{
 
408
        struct csis_state *state = sd_to_csis_state(sd);
 
409
        struct v4l2_mbus_framefmt *mf;
 
410
 
 
411
        if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
 
412
                return -EINVAL;
 
413
 
 
414
        mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
 
415
        if (!mf)
 
416
                return -EINVAL;
 
417
 
 
418
        mutex_lock(&state->lock);
 
419
        fmt->format = *mf;
 
420
        mutex_unlock(&state->lock);
 
421
        return 0;
 
422
}
 
423
 
 
424
static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
 
425
        .s_power = s5pcsis_s_power,
 
426
};
 
427
 
 
428
static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
 
429
        .enum_mbus_code = s5pcsis_enum_mbus_code,
 
430
        .get_fmt = s5pcsis_get_fmt,
 
431
        .set_fmt = s5pcsis_set_fmt,
 
432
};
 
433
 
 
434
static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
 
435
        .s_stream = s5pcsis_s_stream,
 
436
};
 
437
 
 
438
static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
 
439
        .core = &s5pcsis_core_ops,
 
440
        .pad = &s5pcsis_pad_ops,
 
441
        .video = &s5pcsis_video_ops,
 
442
};
 
443
 
 
444
static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
 
445
{
 
446
        struct csis_state *state = dev_id;
 
447
        u32 val;
 
448
 
 
449
        /* Just clear the interrupt pending bits. */
 
450
        val = s5pcsis_read(state, S5PCSIS_INTSRC);
 
451
        s5pcsis_write(state, S5PCSIS_INTSRC, val);
 
452
 
 
453
        return IRQ_HANDLED;
 
454
}
 
455
 
 
456
static int __devinit s5pcsis_probe(struct platform_device *pdev)
 
457
{
 
458
        struct s5p_platform_mipi_csis *pdata;
 
459
        struct resource *mem_res;
 
460
        struct resource *regs_res;
 
461
        struct csis_state *state;
 
462
        int ret = -ENOMEM;
 
463
 
 
464
        state = kzalloc(sizeof(*state), GFP_KERNEL);
 
465
        if (!state)
 
466
                return -ENOMEM;
 
467
 
 
468
        mutex_init(&state->lock);
 
469
        state->pdev = pdev;
 
470
 
 
471
        pdata = pdev->dev.platform_data;
 
472
        if (pdata == NULL || pdata->phy_enable == NULL) {
 
473
                dev_err(&pdev->dev, "Platform data not fully specified\n");
 
474
                goto e_free;
 
475
        }
 
476
 
 
477
        if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
 
478
            pdata->lanes > CSIS0_MAX_LANES) {
 
479
                ret = -EINVAL;
 
480
                dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
 
481
                        pdata->lanes);
 
482
                goto e_free;
 
483
        }
 
484
 
 
485
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
486
        if (!mem_res) {
 
487
                dev_err(&pdev->dev, "Failed to get IO memory region\n");
 
488
                goto e_free;
 
489
        }
 
490
 
 
491
        regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
 
492
                                      pdev->name);
 
493
        if (!regs_res) {
 
494
                dev_err(&pdev->dev, "Failed to request IO memory region\n");
 
495
                goto e_free;
 
496
        }
 
497
        state->regs_res = regs_res;
 
498
 
 
499
        state->regs = ioremap(mem_res->start, resource_size(mem_res));
 
500
        if (!state->regs) {
 
501
                dev_err(&pdev->dev, "Failed to remap IO region\n");
 
502
                goto e_reqmem;
 
503
        }
 
504
 
 
505
        ret = s5pcsis_clk_get(state);
 
506
        if (ret)
 
507
                goto e_unmap;
 
508
 
 
509
        clk_enable(state->clock[CSIS_CLK_MUX]);
 
510
        if (pdata->clk_rate)
 
511
                clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
 
512
        else
 
513
                dev_WARN(&pdev->dev, "No clock frequency specified!\n");
 
514
 
 
515
        state->irq = platform_get_irq(pdev, 0);
 
516
        if (state->irq < 0) {
 
517
                ret = state->irq;
 
518
                dev_err(&pdev->dev, "Failed to get irq\n");
 
519
                goto e_clkput;
 
520
        }
 
521
 
 
522
        if (!pdata->fixed_phy_vdd) {
 
523
                state->supply = regulator_get(&pdev->dev, "vdd");
 
524
                if (IS_ERR(state->supply)) {
 
525
                        ret = PTR_ERR(state->supply);
 
526
                        state->supply = NULL;
 
527
                        goto e_clkput;
 
528
                }
 
529
        }
 
530
 
 
531
        ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
 
532
                          dev_name(&pdev->dev), state);
 
533
        if (ret) {
 
534
                dev_err(&pdev->dev, "request_irq failed\n");
 
535
                goto e_regput;
 
536
        }
 
537
 
 
538
        v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
 
539
        state->sd.owner = THIS_MODULE;
 
540
        strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
 
541
        state->csis_fmt = &s5pcsis_formats[0];
 
542
 
 
543
        state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
 
544
        state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
 
545
        ret = media_entity_init(&state->sd.entity,
 
546
                                CSIS_PADS_NUM, state->pads, 0);
 
547
        if (ret < 0)
 
548
                goto e_irqfree;
 
549
 
 
550
        /* This allows to retrieve the platform device id by the host driver */
 
551
        v4l2_set_subdevdata(&state->sd, pdev);
 
552
 
 
553
        /* .. and a pointer to the subdev. */
 
554
        platform_set_drvdata(pdev, &state->sd);
 
555
 
 
556
        state->flags = ST_SUSPENDED;
 
557
        pm_runtime_enable(&pdev->dev);
 
558
 
 
559
        return 0;
 
560
 
 
561
e_irqfree:
 
562
        free_irq(state->irq, state);
 
563
e_regput:
 
564
        if (state->supply)
 
565
                regulator_put(state->supply);
 
566
e_clkput:
 
567
        clk_disable(state->clock[CSIS_CLK_MUX]);
 
568
        s5pcsis_clk_put(state);
 
569
e_unmap:
 
570
        iounmap(state->regs);
 
571
e_reqmem:
 
572
        release_mem_region(regs_res->start, resource_size(regs_res));
 
573
e_free:
 
574
        kfree(state);
 
575
        return ret;
 
576
}
 
577
 
 
578
static int s5pcsis_suspend(struct device *dev)
 
579
{
 
580
        struct s5p_platform_mipi_csis *pdata = dev->platform_data;
 
581
        struct platform_device *pdev = to_platform_device(dev);
 
582
        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 
583
        struct csis_state *state = sd_to_csis_state(sd);
 
584
        int ret = 0;
 
585
 
 
586
        v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
 
587
                 __func__, state->flags);
 
588
 
 
589
        mutex_lock(&state->lock);
 
590
        if (state->flags & ST_POWERED) {
 
591
                s5pcsis_stop_stream(state);
 
592
                ret = pdata->phy_enable(state->pdev, false);
 
593
                if (ret)
 
594
                        goto unlock;
 
595
                if (state->supply) {
 
596
                        ret = regulator_disable(state->supply);
 
597
                        if (ret)
 
598
                                goto unlock;
 
599
                }
 
600
                clk_disable(state->clock[CSIS_CLK_GATE]);
 
601
                state->flags &= ~ST_POWERED;
 
602
        }
 
603
        state->flags |= ST_SUSPENDED;
 
604
 unlock:
 
605
        mutex_unlock(&state->lock);
 
606
        return ret ? -EAGAIN : 0;
 
607
}
 
608
 
 
609
static int s5pcsis_resume(struct device *dev)
 
610
{
 
611
        struct s5p_platform_mipi_csis *pdata = dev->platform_data;
 
612
        struct platform_device *pdev = to_platform_device(dev);
 
613
        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 
614
        struct csis_state *state = sd_to_csis_state(sd);
 
615
        int ret = 0;
 
616
 
 
617
        v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
 
618
                 __func__, state->flags);
 
619
 
 
620
        mutex_lock(&state->lock);
 
621
        if (!(state->flags & ST_SUSPENDED))
 
622
                goto unlock;
 
623
 
 
624
        if (!(state->flags & ST_POWERED)) {
 
625
                if (state->supply)
 
626
                        ret = regulator_enable(state->supply);
 
627
                if (ret)
 
628
                        goto unlock;
 
629
 
 
630
                ret = pdata->phy_enable(state->pdev, true);
 
631
                if (!ret) {
 
632
                        state->flags |= ST_POWERED;
 
633
                } else if (state->supply) {
 
634
                        regulator_disable(state->supply);
 
635
                        goto unlock;
 
636
                }
 
637
                clk_enable(state->clock[CSIS_CLK_GATE]);
 
638
        }
 
639
        if (state->flags & ST_STREAMING)
 
640
                s5pcsis_start_stream(state);
 
641
 
 
642
        state->flags &= ~ST_SUSPENDED;
 
643
 unlock:
 
644
        mutex_unlock(&state->lock);
 
645
        return ret ? -EAGAIN : 0;
 
646
}
 
647
 
 
648
#ifdef CONFIG_PM_SLEEP
 
649
static int s5pcsis_pm_suspend(struct device *dev)
 
650
{
 
651
        return s5pcsis_suspend(dev);
 
652
}
 
653
 
 
654
static int s5pcsis_pm_resume(struct device *dev)
 
655
{
 
656
        int ret;
 
657
 
 
658
        ret = s5pcsis_resume(dev);
 
659
 
 
660
        if (!ret) {
 
661
                pm_runtime_disable(dev);
 
662
                ret = pm_runtime_set_active(dev);
 
663
                pm_runtime_enable(dev);
 
664
        }
 
665
 
 
666
        return ret;
 
667
}
 
668
#endif
 
669
 
 
670
static int __devexit s5pcsis_remove(struct platform_device *pdev)
 
671
{
 
672
        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 
673
        struct csis_state *state = sd_to_csis_state(sd);
 
674
        struct resource *res = state->regs_res;
 
675
 
 
676
        pm_runtime_disable(&pdev->dev);
 
677
        s5pcsis_suspend(&pdev->dev);
 
678
        clk_disable(state->clock[CSIS_CLK_MUX]);
 
679
        pm_runtime_set_suspended(&pdev->dev);
 
680
 
 
681
        s5pcsis_clk_put(state);
 
682
        if (state->supply)
 
683
                regulator_put(state->supply);
 
684
 
 
685
        media_entity_cleanup(&state->sd.entity);
 
686
        free_irq(state->irq, state);
 
687
        iounmap(state->regs);
 
688
        release_mem_region(res->start, resource_size(res));
 
689
        kfree(state);
 
690
 
 
691
        return 0;
 
692
}
 
693
 
 
694
static const struct dev_pm_ops s5pcsis_pm_ops = {
 
695
        SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL)
 
696
        SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume)
 
697
};
 
698
 
 
699
static struct platform_driver s5pcsis_driver = {
 
700
        .probe          = s5pcsis_probe,
 
701
        .remove         = __devexit_p(s5pcsis_remove),
 
702
        .driver         = {
 
703
                .name   = CSIS_DRIVER_NAME,
 
704
                .owner  = THIS_MODULE,
 
705
                .pm     = &s5pcsis_pm_ops,
 
706
        },
 
707
};
 
708
 
 
709
static int __init s5pcsis_init(void)
 
710
{
 
711
        return platform_driver_probe(&s5pcsis_driver, s5pcsis_probe);
 
712
}
 
713
 
 
714
static void __exit s5pcsis_exit(void)
 
715
{
 
716
        platform_driver_unregister(&s5pcsis_driver);
 
717
}
 
718
 
 
719
module_init(s5pcsis_init);
 
720
module_exit(s5pcsis_exit);
 
721
 
 
722
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
 
723
MODULE_DESCRIPTION("S5P/EXYNOS4 MIPI CSI receiver driver");
 
724
MODULE_LICENSE("GPL");